diff --git a/Authorization/Authorization.xcodeproj/project.pbxproj b/Authorization/Authorization.xcodeproj/project.pbxproj index 8473bbbf8..267bc049c 100644 --- a/Authorization/Authorization.xcodeproj/project.pbxproj +++ b/Authorization/Authorization.xcodeproj/project.pbxproj @@ -26,6 +26,8 @@ 0770DE6B28D0C035006D8A5D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0770DE6D28D0C035006D8A5D /* Localizable.strings */; }; 0770DE7128D0C0E7006D8A5D /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0770DE7028D0C0E7006D8A5D /* Strings.swift */; }; 5FB79D2802949372CDAF08D6 /* Pods_App_Authorization_AuthorizationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FAE9B7FD61FF88C9C4FE1E8 /* Pods_App_Authorization_AuthorizationTests.framework */; }; + 9972D16F2E5F14440020CFBD /* TenantSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D16E2E5F14440020CFBD /* TenantSelectionView.swift */; }; + 9972D1702E5F14440020CFBD /* TenantViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D16D2E5F14440020CFBD /* TenantViewModel.swift */; }; 99C1654B2C0C4F0600DC384D /* ContainerWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C1654A2C0C4F0600DC384D /* ContainerWebView.swift */; }; 99C1654D2C0C4F2F00DC384D /* SSOHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C1654C2C0C4F2F00DC384D /* SSOHelper.swift */; }; 99C1654F2C0C4F5900DC384D /* SSOWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C1654E2C0C4F5900DC384D /* SSOWebView.swift */; }; @@ -90,19 +92,25 @@ 0770DE6728D0BF03006D8A5D /* swiftgen.yml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.yaml; path = swiftgen.yml; sourceTree = ""; }; 0770DE6C28D0C035006D8A5D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 0770DE7028D0C0E7006D8A5D /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; + 077FC5D16B28128BCA22472B /* Pods-App-Authorization-AuthorizationTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.debugprodtenants.xcconfig"; sourceTree = ""; }; 0E586C84FB9FFDD8AAE29BB3 /* Pods-App-Authorization-AuthorizationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.debug.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.debug.xcconfig"; sourceTree = ""; }; 1CB6628EDEAAC2431CD50D9A /* Pods-App-Authorization-AuthorizationTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.debugprod.xcconfig"; sourceTree = ""; }; 1CD50AA5CB635FD7200C4DF9 /* Pods-App-Authorization.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.debugstage.xcconfig"; sourceTree = ""; }; + 21A5CC93A250984DA0696C99 /* Pods-App-Authorization.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.openedxmultitenants.xcconfig"; sourceTree = ""; }; 2F1206D6806C156203F01524 /* Pods-App-Authorization-AuthorizationTests.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.debugstage.xcconfig"; sourceTree = ""; }; 37CBD3ECE7D9B20E0BC61344 /* Pods-App-Authorization-AuthorizationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.release.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.release.xcconfig"; sourceTree = ""; }; 3E0D103D8210828583660AF6 /* Pods-App-Authorization.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.debug.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.debug.xcconfig"; sourceTree = ""; }; 47BCFB7C19382EECF15131B6 /* Pods_App_Authorization.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Authorization.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 49A74E7AC5109DFA06BDAF3A /* Pods-App-Authorization-AuthorizationTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.releasedev.xcconfig"; sourceTree = ""; }; 4FAE9B7FD61FF88C9C4FE1E8 /* Pods_App_Authorization_AuthorizationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Authorization_AuthorizationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5DEB4953C577B41EA3C5C9E7 /* Pods-App-Authorization.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.debugprodtenants.xcconfig"; sourceTree = ""; }; + 630A70CE476FE591CCBC6244 /* Pods-App-Authorization-AuthorizationTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; 68795EBDC3000C1B12F9432C /* Pods-App-Authorization.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.debugprod.xcconfig"; sourceTree = ""; }; 7A84BB166492D4E46FBCF01C /* Pods-App-Authorization-AuthorizationTests.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization-AuthorizationTests.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Authorization-AuthorizationTests/Pods-App-Authorization-AuthorizationTests.debugdev.xcconfig"; sourceTree = ""; }; 90DFBB75EF40580E180D71C8 /* Pods-App-Authorization.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.debugdev.xcconfig"; sourceTree = ""; }; 96C85172770225EB81A6D2DA /* Pods-App-Authorization.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Authorization.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Authorization/Pods-App-Authorization.releasedev.xcconfig"; sourceTree = ""; }; + 9972D16D2E5F14440020CFBD /* TenantViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TenantViewModel.swift; sourceTree = ""; }; + 9972D16E2E5F14440020CFBD /* TenantSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TenantSelectionView.swift; sourceTree = ""; }; 99C1654A2C0C4F0600DC384D /* ContainerWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerWebView.swift; sourceTree = ""; }; 99C1654C2C0C4F2F00DC384D /* SSOHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSOHelper.swift; sourceTree = ""; }; 99C1654E2C0C4F5900DC384D /* SSOWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSOWebView.swift; sourceTree = ""; }; @@ -187,6 +195,7 @@ 071009CC28D1E24000344290 /* Presentation */ = { isa = PBXGroup; children = ( + 9972D16C2E5F14340020CFBD /* MultiTenant */, 99C165492C0C4EF000DC384D /* SSO */, BA8B3A302AD5485100D25EF5 /* SocialAuth */, E03261622AE6464A002CA7EB /* Startup */, @@ -305,11 +314,24 @@ F52826C68AEA1CF4769389EA /* Pods-App-Authorization.releasestage.xcconfig */, 2F1206D6806C156203F01524 /* Pods-App-Authorization-AuthorizationTests.debugstage.xcconfig */, A99D45203C981893C104053A /* Pods-App-Authorization-AuthorizationTests.releasestage.xcconfig */, + 21A5CC93A250984DA0696C99 /* Pods-App-Authorization.openedxmultitenants.xcconfig */, + 630A70CE476FE591CCBC6244 /* Pods-App-Authorization-AuthorizationTests.openedxmultitenants.xcconfig */, + 5DEB4953C577B41EA3C5C9E7 /* Pods-App-Authorization.debugprodtenants.xcconfig */, + 077FC5D16B28128BCA22472B /* Pods-App-Authorization-AuthorizationTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; sourceTree = ""; }; + 9972D16C2E5F14340020CFBD /* MultiTenant */ = { + isa = PBXGroup; + children = ( + 9972D16D2E5F14440020CFBD /* TenantViewModel.swift */, + 9972D16E2E5F14440020CFBD /* TenantSelectionView.swift */, + ); + path = MultiTenant; + sourceTree = ""; + }; 99C165492C0C4EF000DC384D /* SSO */ = { isa = PBXGroup; children = ( @@ -584,6 +606,8 @@ 0770DE7128D0C0E7006D8A5D /* Strings.swift in Sources */, 025F40E229D360E20064C183 /* ResetPasswordViewModel.swift in Sources */, 02066B462906D72F00F4307E /* SignUpViewModel.swift in Sources */, + 9972D16F2E5F14440020CFBD /* TenantSelectionView.swift in Sources */, + 9972D1702E5F14440020CFBD /* TenantViewModel.swift in Sources */, E03261642AE64676002CA7EB /* StartupViewModel.swift in Sources */, 02A2ACDB2A4B016100FBBBBB /* AuthorizationAnalytics.swift in Sources */, 99C165512C0C4F7B00DC384D /* SSOWebViewModel.swift in Sources */, @@ -705,6 +729,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -816,6 +841,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1040,6 +1066,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1133,6 +1160,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1231,6 +1259,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1324,6 +1353,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1480,6 +1510,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1515,6 +1546,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1537,6 +1569,237 @@ }; name = Release; }; + 995886A32E64473B0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886A42E64473B0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5DEB4953C577B41EA3C5C9E7 /* Pods-App-Authorization.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Authorization; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = TENANTS; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886A52E64473B0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 077FC5D16B28128BCA22472B /* Pods-App-Authorization-AuthorizationTests.debugprodtenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.AuthorizationTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1DA2E6037560020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1DB2E6037560020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 21A5CC93A250984DA0696C99 /* Pods-App-Authorization.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Authorization; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = TENANTS; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1DC2E6037560020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 630A70CE476FE591CCBC6244 /* Pods-App-Authorization-AuthorizationTests.openedxmultitenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.AuthorizationTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1544,11 +1807,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0716945B296D913400E3DED6 /* Debug */, + 9972D1DC2E6037560020CFBD /* OpenEdXMultiTenants */, 0716945C296D913400E3DED6 /* DebugProd */, 02DD1CA129E80CF900F35DCE /* DebugStage */, 0716945D296D913400E3DED6 /* DebugDev */, 0716945E296D913400E3DED6 /* Release */, 0716945F296D913400E3DED6 /* ReleaseProd */, + 995886A52E64473B0065D132 /* DebugProdTenants */, 02DD1CA429E80D0200F35DCE /* ReleaseStage */, 07169460296D913400E3DED6 /* ReleaseDev */, ); @@ -1559,11 +1824,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0770DE4028D0A319006D8A5D /* Debug */, + 9972D1DA2E6037560020CFBD /* OpenEdXMultiTenants */, 0727876828D232A9002E9142 /* DebugProd */, 02DD1C9F29E80CF900F35DCE /* DebugStage */, 0727876428D2329C002E9142 /* DebugDev */, 0770DE4128D0A319006D8A5D /* Release */, 0727876A28D232B0002E9142 /* ReleaseProd */, + 995886A32E64473B0065D132 /* DebugProdTenants */, 02DD1CA229E80D0200F35DCE /* ReleaseStage */, 0727876628D232A4002E9142 /* ReleaseDev */, ); @@ -1574,11 +1841,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0770DE4328D0A319006D8A5D /* Debug */, + 9972D1DB2E6037560020CFBD /* OpenEdXMultiTenants */, 0727876928D232A9002E9142 /* DebugProd */, 02DD1CA029E80CF900F35DCE /* DebugStage */, 0727876528D2329C002E9142 /* DebugDev */, 0770DE4428D0A319006D8A5D /* Release */, 0727876B28D232B0002E9142 /* ReleaseProd */, + 995886A42E64473B0065D132 /* DebugProdTenants */, 02DD1CA329E80D0200F35DCE /* ReleaseStage */, 0727876728D232A4002E9142 /* ReleaseDev */, ); diff --git a/Authorization/Authorization/Presentation/Login/SignInView.swift b/Authorization/Authorization/Presentation/Login/SignInView.swift index f92309117..138fe8033 100644 --- a/Authorization/Authorization/Presentation/Login/SignInView.swift +++ b/Authorization/Authorization/Presentation/Login/SignInView.swift @@ -12,7 +12,6 @@ import Theme import Swinject public struct SignInView: View { - @State private var email: String = "" @State private var password: String = "" @@ -21,284 +20,356 @@ public struct SignInView: View { @ObservedObject private var viewModel: SignInViewModel - public init(viewModel: SignInViewModel) { + @ObservedObject var tenantViewModel: TenantViewModel + @State var isSuperUser: Bool = false + + func showSuperUserLoginView() { + isSuperUser.toggle() + } + + public init(viewModel: SignInViewModel, tenantViewModel: TenantViewModel) { self.viewModel = viewModel + self.tenantViewModel = tenantViewModel } public var body: some View { - ZStack(alignment: .top) { - VStack { - ThemeAssets.headerBackground.swiftUIImage - .resizable() - .edgesIgnoringSafeArea(.top) - .accessibilityIdentifier("auth_bg_image") - }.frame(maxWidth: .infinity, maxHeight: 200) - if viewModel.config.features.startupScreenEnabled { + if tenantViewModel.selectedTenant != nil { + ZStack(alignment: .top) { VStack { - BackNavigationButton( - color: Theme.Colors.loginNavigationText, - action: { - viewModel.router.back() - } - ) - .backViewStyle() - .padding(.leading, isHorizontal ? 48 : 0) - .padding(.top, 11) - - }.frame(maxWidth: .infinity, alignment: .topLeading) - .padding(.top, isHorizontal ? 20 : 0) - } - - VStack(alignment: .center) { - ThemeAssets.appLogo.swiftUIImage - .resizable() - .aspectRatio(contentMode: .fit) - .frame(maxWidth: 189, maxHeight: 89) - .padding(.top, isHorizontal ? 20 : 40) - .padding(.bottom, isHorizontal ? 10 : 40) - .accessibilityIdentifier("logo_image") + #if TENANTS + ThemeAssets.headerBackground.swiftUIImage + .resizable() + .edgesIgnoringSafeArea(.top) + .accessibilityIdentifier("auth_bg_image") + + #else + ThemeAssets.headerBackground.swiftUIImage + .resizable() + .edgesIgnoringSafeArea(.top) + .accessibilityIdentifier("auth_bg_image") + #endif + }.frame(maxWidth: .infinity, maxHeight: 200) + if viewModel.config.features.startupScreenEnabled || + tenantViewModel.config.tenantsConfig.tenants.count > 1 { + VStack { + BackNavigationButton( + color: Theme.Colors.loginNavigationText, + action: { + tenantViewModel.config.tenantsConfig.tenants.count > 1 ? + tenantViewModel.resetSelectedTenant() : + viewModel.router.back(animated: true) + } + ) + + .backViewStyle() + .padding(.leading, isHorizontal ? 48 : 0) + .padding(.top, 11) + + }.frame(maxWidth: .infinity, alignment: .topLeading) + .padding(.top, isHorizontal ? 20 : 0) + } - GeometryReader { proxy in - ScrollView { - VStack { - VStack(alignment: .leading) { - if viewModel.config.uiComponents.loginRegistrationEnabled { - Text(AuthLocalization.SignIn.logInTitle) - .font(Theme.Fonts.displaySmall) - .foregroundColor(Theme.Colors.textPrimary) - .padding(.bottom, 4) - .accessibilityIdentifier("signin_text") - Text(AuthLocalization.SignIn.welcomeBack) - .font(Theme.Fonts.titleSmall) - .foregroundColor(Theme.Colors.textPrimary) - .padding(.bottom, 20) - .accessibilityIdentifier("welcome_back_text") - if viewModel.socialAuthEnabled { - SocialAuthView( - viewModel: .init( - config: viewModel.config, - lastUsedOption: viewModel.storage.lastUsedSocialAuth - ) { result in - Task { await viewModel.login(with: result) } - } - ) - .padding(.top, 22) - .padding(.bottom, 16) - } - Text(AuthLocalization.SignIn.emailOrUsername) - .font(Theme.Fonts.labelLarge) - .foregroundColor(Theme.Colors.textPrimary) - .accessibilityIdentifier("username_text") - TextField("", text: $email) - .font(Theme.Fonts.bodyLarge) - .foregroundColor(Theme.Colors.textInputTextColor) - .keyboardType(.emailAddress) - .textContentType(.emailAddress) - .autocapitalization(.none) - .autocorrectionDisabled() - .padding(.all, 14) - .background( - Theme.InputFieldBackground( - placeHolder: AuthLocalization.SignIn.emailOrUsername, - text: email, - padding: 15 - ) - ) - .overlay( - Theme.Shapes.textInputShape - .stroke(lineWidth: 1) - .fill(Theme.Colors.textInputStroke) - ) - .accessibilityIdentifier("username_textfield") - - Text(AuthLocalization.SignIn.password) - .font(Theme.Fonts.labelLarge) - .foregroundColor(Theme.Colors.textPrimary) - .padding(.top, 18) - .accessibilityIdentifier("password_text") - SecureInputView($password) - .font(Theme.Fonts.bodyLarge) - .padding(.all, 14) - .background( - Theme.InputFieldBackground( - placeHolder: AuthLocalization.SignIn.password, - text: password, - padding: 15 - ) - ) - .overlay( - Theme.Shapes.textInputShape - .stroke(lineWidth: 1) - .fill(Theme.Colors.textInputStroke) - ) - .accessibilityIdentifier("password_textfield") - HStack { - if !viewModel.config.features.startupScreenEnabled { - Button(CoreLocalization.SignIn.registerBtn) { - viewModel.router.showRegisterScreen( - sourceScreen: viewModel.sourceScreen + VStack(alignment: .center) { + +#if TENANTS + ThemeAssets.appLogo.swiftUIImage + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxWidth: 189, maxHeight: 89) + .padding(.top, isHorizontal ? 20 : 40) + .padding(.bottom, isHorizontal ? 10 : 40) + .accessibilityIdentifier("logo_image") + .onTapGesture(count: 10, perform: { + showSuperUserLoginView() + }) +#else + ThemeAssets.appLogo.swiftUIImage + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxWidth: 189, maxHeight: 89) + .padding(.top, isHorizontal ? 20 : 40) + .padding(.bottom, isHorizontal ? 10 : 40) + .accessibilityIdentifier("logo_image") + .onTapGesture(count: 10, perform: { + showSuperUserLoginView() + }) +#endif + + GeometryReader { _ in + ScrollView { + VStack { + VStack(alignment: .center) { + if self.tenantViewModel.selectedTenant? + .uiComponents?.loginRegistrationEnabled ?? false + || isSuperUser { + VStack(alignment: .leading) { + Text(AuthLocalization.SignIn.logInTitle) + .font(Theme.Fonts.displaySmall) + .foregroundColor(Theme.Colors.accentColor) + .padding(.bottom, 4) + .accessibilityIdentifier("signin_text") + Text(AuthLocalization.SignIn.welcomeBack) + .font(Theme.Fonts.titleSmall) + .foregroundColor(Theme.Colors.textPrimary) + .padding(.bottom, 20) + .accessibilityIdentifier("welcome_back_text") + + Text(AuthLocalization.SignIn.emailOrUsername) + .font(Theme.Fonts.labelLarge) + .foregroundColor(Theme.Colors.textPrimary) + .accessibilityIdentifier("username_text") + TextField(AuthLocalization.SignIn.emailOrUsername, text: $email) + .font(Theme.Fonts.bodyLarge) + .foregroundColor(Theme.Colors.textPrimary) + .keyboardType(.emailAddress) + .textContentType(.emailAddress) + .autocapitalization(.none) + .autocorrectionDisabled() + .padding(.all, 14) + .background( + Theme.Shapes.textInputShape + .fill(Theme.Colors.textInputBackground) + ) + .overlay( + Theme.Shapes.textInputShape + .stroke(lineWidth: 1) + .fill(Theme.Colors.textInputStroke) ) + .accessibilityIdentifier("username_textfield") + + Text(AuthLocalization.SignIn.password) + .font(Theme.Fonts.labelLarge) + .foregroundColor(Theme.Colors.textPrimary) + .padding(.top, 18) + .accessibilityIdentifier("password_text") + SecureField(AuthLocalization.SignIn.password, text: $password) + .font(Theme.Fonts.bodyLarge) + .foregroundColor(Theme.Colors.textPrimary) + .padding(.all, 14) + .background( + Theme.Shapes.textInputShape + .fill(Theme.Colors.textInputBackground) + ) + .overlay( + Theme.Shapes.textInputShape + .stroke(lineWidth: 1) + .fill(Theme.Colors.textInputStroke) + ) + .accessibilityIdentifier("password_textfield") + if !isSuperUser { + HStack { + if !viewModel.config.features.startupScreenEnabled { + Button(CoreLocalization.SignIn.registerBtn) { + viewModel.router.showRegisterScreen( + sourceScreen: viewModel.sourceScreen) + } + .foregroundColor(Theme.Colors.accentColor) + .accessibilityIdentifier("register_button") + + Spacer() + } + + Button(AuthLocalization.SignIn.forgotPassBtn) { + viewModel.trackForgotPasswordClicked() + viewModel.router.showForgotPasswordScreen() + } + .font(Theme.Fonts.bodyLarge) + .foregroundColor(Theme.Colors.accentXColor) + .padding(.top, 0) + .accessibilityIdentifier("forgot_password_button") + } } - .foregroundColor(Theme.Colors.accentColor) - .accessibilityIdentifier("register_button") - Spacer() - } - - Button(AuthLocalization.SignIn.forgotPassBtn) { - viewModel.trackForgotPasswordClicked() - viewModel.router.showForgotPasswordScreen() + if viewModel.isShowProgress { + HStack(alignment: .center) { + ProgressBar(size: 40, lineWidth: 8) + .padding(20) + .accessibilityIdentifier("progressbar") + }.frame(maxWidth: .infinity) + } else { + StyledButton(CoreLocalization.SignIn.logInBtn, action: { + Task { + await viewModel.login(username: email, password: password) + } + }, color: Theme.Colors.accentColor) + .frame(maxWidth: .infinity) + .padding(.top, 40) + .accessibilityIdentifier("signin_button") + + } } - .font(Theme.Fonts.bodyLarge) - .foregroundColor(Theme.Colors.infoColor) - .padding(.top, 0) - .accessibilityIdentifier("forgot_password_button") } - if viewModel.isShowProgress { - HStack(alignment: .center) { - ProgressBar(size: 40, lineWidth: 8) - .padding(20) - .accessibilityIdentifier("progress_bar") - }.frame(maxWidth: .infinity) - } else { - StyledButton(CoreLocalization.SignIn.logInBtn) { - Task { - await viewModel.login(username: email, password: password) + if self.tenantViewModel.selectedTenant?.uiComponents?.samlSSOLoginEnabled ?? false { + if self.tenantViewModel.selectedTenant? + .uiComponents?.loginRegistrationEnabled + ?? false { + VStack(alignment: .center) { + Text(AuthLocalization.SignIn.ssoHeading) + .font(Theme.Fonts.headlineSmall) + .multilineTextAlignment(.center) + .foregroundColor(Theme.Colors.textPrimary) + .padding(.bottom, 4) + .padding(.horizontal, 20) + .accessibilityIdentifier("signin_sso_heading") + } + + Divider() + + VStack(alignment: .center) { + ThemeAssets.headerBackground.swiftUIImage + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxWidth: 88, maxHeight: 38) + .padding(.top, isHorizontal ? 20 : 20) + .padding(.bottom, isHorizontal ? 10 : 20) + .accessibilityIdentifier("sso_header") + + Text(AuthLocalization.SignIn.ssoLogInTitle) + .font(Theme.Fonts.headlineSmall) + .multilineTextAlignment(.center) + .foregroundColor(Theme.Colors.textPrimary) + .padding(.bottom, 10) + .padding(.horizontal, 20) + .accessibilityIdentifier("signin_sso_login_title") + + Text(AuthLocalization.SignIn.ssoLogInSubtitle) + .font(Theme.Fonts.titleMedium) + .multilineTextAlignment(.center) + .foregroundColor(Theme.Colors.textSecondaryLight) + .padding(.bottom, 10) + .padding(.horizontal, 20) + .accessibilityIdentifier("signin_sso_login_subtitle") } } - .frame(maxWidth: .infinity) - .padding(.top, 40) - .accessibilityIdentifier("signin_button") - } - } - if viewModel.config.uiComponents.samlSSOLoginEnabled { - if !viewModel.config.uiComponents.loginRegistrationEnabled { - VStack(alignment: .center) { - Text(AuthLocalization.SignIn.ssoHeading) - .font(Theme.Fonts.headlineSmall) - .multilineTextAlignment(.center) - .foregroundColor(Theme.Colors.textPrimary) - .padding(.bottom, 4) - .padding(.horizontal, 20) - .accessibilityIdentifier("signin_sso_heading") - } - - Divider() VStack(alignment: .center) { - Text(AuthLocalization.SignIn.ssoLogInTitle) - .font(Theme.Fonts.headlineSmall) - .multilineTextAlignment(.center) - .foregroundColor(Theme.Colors.textPrimary) - .padding(.bottom, 10) - .padding(.horizontal, 20) - .accessibilityIdentifier("signin_sso_login_title") - Text(AuthLocalization.SignIn.ssoLogInSubtitle) - .font(Theme.Fonts.titleMedium) - .multilineTextAlignment(.center) - .foregroundColor(Theme.Colors.textSecondaryLight) - .padding(.bottom, 10) - .padding(.horizontal, 20) - .accessibilityIdentifier("signin_sso_login_subtitle") - } - } - - VStack(alignment: .center) { - if viewModel.isShowProgress { - HStack(alignment: .center) { - ProgressBar(size: 40, lineWidth: 8) - .padding(20) - .accessibilityIdentifier("progressbar") - }.frame(maxWidth: .infinity) - } else { - let languageCode = Locale.current.language.languageCode?.identifier ?? "en" - if viewModel.config.uiComponents.samlSSODefaultLoginButton { - StyledButton( - viewModel.config.ssoButtonTitle[languageCode] as! String, - action: { - viewModel.router - .showSSOWebBrowser(title: CoreLocalization.SignIn.logInBtn) - } - ) - .frame(maxWidth: .infinity) - .padding(.top, 20) - .accessibilityIdentifier("signin_SSO_button") + if viewModel.isShowProgress && !isSuperUser { + HStack(alignment: .center) { + ProgressBar(size: 40, lineWidth: 8) + .padding(20) + .accessibilityIdentifier("progressbar") + }.frame(maxWidth: .infinity) } else { - StyledButton( - viewModel.config.ssoButtonTitle[languageCode] as! String, - action: { + let languageCode = + Locale.current.language.languageCode?.identifier + ?? "en" + if self.tenantViewModel.selectedTenant? + .uiComponents?.samlSSODefaultLoginButton + ?? false { + Text(AuthLocalization.SignIn.logInTitle) + .font(Theme.Fonts.displaySmall) + .foregroundColor(Theme.Colors.accentColor) + .padding(.bottom, 4) + .accessibilityIdentifier("signin_text") + + Divider() + + StyledButton(viewModel.tenantProvider() + .ssoButtonTitle, + action: { viewModel.router - .showSSOWebBrowser(title: CoreLocalization.SignIn.logInBtn) + .showSSOWebBrowser( + title: CoreLocalization.SignIn.logInBtn) }, - color: .white, - textColor: Theme.Colors.accentColor, - borderColor: Theme.Colors.accentColor) - .frame(maxWidth: .infinity) - .padding(.top, 20) - .accessibilityIdentifier("signin_SSO_button") + color: Theme.Colors.accentColor) + .frame(maxWidth: .infinity) + .padding(.top, 20) + .accessibilityIdentifier("signin_SSO_button") + } else { + StyledButton(viewModel.tenantProvider() + .ssoButtonTitle, + action: { + viewModel.router + .showSSOWebBrowser( + title: CoreLocalization.SignIn.logInBtn) + }, + color: .white, + textColor: Theme.Colors.accentColor, + borderColor: Theme.Colors.accentColor) + .frame(maxWidth: .infinity) + .padding(.top, 20) + .accessibilityIdentifier("signin_SSO_button") + } + } } } } + if viewModel.socialAuthEnabled { + SocialAuthView( + viewModel: .init( + config: viewModel.config, lastUsedOption: "" + ) { result in + Task { await viewModel.login(with: result) } + } + ) + } + agreements + Spacer() } - agreements - Spacer() - } - .padding(.horizontal, 24) - .padding(.top, 50) - .frameLimit(width: proxy.size.width) + .padding(.horizontal, 24) + .padding(.top, 25) + }.roundedBackground(Theme.Colors.loginBackground) + .scrollAvoidKeyboard(dismissKeyboardByTap: true) } - .roundedBackground(Theme.Colors.loginBackground) - .scrollAvoidKeyboard(dismissKeyboardByTap: true) } - } - - // MARK: - Alert - if viewModel.showAlert { - VStack { - Text(viewModel.alertMessage ?? "") - .shadowCardStyle(bgColor: Theme.Colors.accentColor, - textColor: Theme.Colors.white) - .padding(.top, 80) - Spacer() - - } - .transition(.move(edge: .top)) - .onAppear { - doAfter(Theme.Timeout.snackbarMessageLongTimeout) { - viewModel.alertMessage = nil + + // MARK: - Alert + if viewModel.showAlert { + VStack { + Text(viewModel.alertMessage ?? "") + .shadowCardStyle(bgColor: Theme.Colors.accentColor, + textColor: Theme.Colors.white) + .padding(.top, 80) + Spacer() + } - } - } - - // MARK: - Show error - if viewModel.showError { - VStack { - Spacer() - SnackBarView(message: viewModel.errorMessage) - }.transition(.move(edge: .bottom)) + .transition(.move(edge: .top)) .onAppear { doAfter(Theme.Timeout.snackbarMessageLongTimeout) { - viewModel.errorMessage = nil + viewModel.alertMessage = nil } } + } + + // MARK: - Show error + if viewModel.showError { + VStack { + Spacer() + SnackBarView(message: viewModel.errorMessage) + }.transition(.move(edge: .bottom)) + .onAppear { + doAfter(Theme.Timeout.snackbarMessageLongTimeout) { + viewModel.errorMessage = nil + } + } + } } - } - .navigationBarHidden(true) - .ignoresSafeArea(.all, edges: .horizontal) - .background(Theme.Colors.background.ignoresSafeArea(.all)) - .onFirstAppear { - viewModel.trackScreenEvent() + .navigationBarHidden(true) + .ignoresSafeArea(.all, edges: .horizontal) + .background(Theme.Colors.background.ignoresSafeArea(.all)) + .onFirstAppear { + viewModel.trackScreenEvent() + } + .onAppear { + tenantViewModel.loadFromUserDefaults() + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: Color.red.uiColor() + ) + } + } else { +// ProgressView("Loading tenant...") } } - + @ViewBuilder private var agreements: some View { if let eulaURL = viewModel.config.agreement.eulaURL, - let tosURL = viewModel.config.agreement.tosURL, - let policy = viewModel.config.agreement.privacyPolicyURL { + let tosURL = viewModel.config.agreement.tosURL, + let policy = viewModel.config.agreement.privacyPolicyURL { let text = AuthLocalization.SignIn.agreement( "\(viewModel.config.platformName)", eulaURL, @@ -316,9 +387,9 @@ public struct SignInView: View { .environment(\.openURL, OpenURLAction(handler: handleURL)) } } - + private func handleURL(_ url: URL) -> OpenURLAction.Result { - viewModel.router.showWebBrowser(title: "", url: url) + viewModel.router.showWebBrowser(title: url.host ?? "", url: url) return .handled } } @@ -333,15 +404,21 @@ struct SignInView_Previews: PreviewProvider { analytics: AuthorizationAnalyticsMock(), validator: Validator(), storage: CoreStorageMock(), - sourceScreen: .default + sourceScreen: .default, + tenantProvider: { TenantProviderMock()} ) - - SignInView(viewModel: vm) + let tenantVM = TenantViewModel( + router: AuthorizationRouterMock(), + config: ConfigMock(), + analytics: AuthorizationAnalyticsMock(), + storage: CoreStorageMock(), + ) + SignInView(viewModel: vm, tenantViewModel: tenantVM) .preferredColorScheme(.light) .previewDisplayName("SignInView Light") .loadFonts() - SignInView(viewModel: vm) + SignInView(viewModel: vm, tenantViewModel: tenantVM) .preferredColorScheme(.dark) .previewDisplayName("SignInView Dark") .loadFonts() diff --git a/Authorization/Authorization/Presentation/Login/SignInViewModel.swift b/Authorization/Authorization/Presentation/Login/SignInViewModel.swift index 14bd27a92..db5210f6f 100644 --- a/Authorization/Authorization/Presentation/Login/SignInViewModel.swift +++ b/Authorization/Authorization/Presentation/Login/SignInViewModel.swift @@ -44,7 +44,8 @@ public class SignInViewModel: ObservableObject { private let analytics: AuthorizationAnalytics private let validator: Validator let storage: CoreStorage - + let tenantProvider: @Sendable () -> any TenantProvider + public init( interactor: AuthInteractorProtocol, router: AuthorizationRouter, @@ -52,7 +53,8 @@ public class SignInViewModel: ObservableObject { analytics: AuthorizationAnalytics, validator: Validator, storage: CoreStorage, - sourceScreen: LogistrationSourceScreen + sourceScreen: LogistrationSourceScreen, + tenantProvider: @escaping @Sendable () -> any TenantProvider ) { self.interactor = interactor self.router = router @@ -61,6 +63,7 @@ public class SignInViewModel: ObservableObject { self.validator = validator self.storage = storage self.sourceScreen = sourceScreen + self.tenantProvider = tenantProvider } var socialAuthEnabled: Bool { diff --git a/Authorization/Authorization/Presentation/MultiTenant/TenantSelectionView.swift b/Authorization/Authorization/Presentation/MultiTenant/TenantSelectionView.swift new file mode 100644 index 000000000..3ade6138c --- /dev/null +++ b/Authorization/Authorization/Presentation/MultiTenant/TenantSelectionView.swift @@ -0,0 +1,183 @@ +// +// TenantSelectionView.swift +// Authorization +// +// Created by Rawan Matar on 02/03/2025. +// + +import SwiftUI +import Core +import Theme +import Swinject + +// Define a struct for tenant theme +public struct TenantTheme { + let name: String + let color: Color + let baseURL: String? + let baseURLHiddenLogin: String? + let baseSSOURL: String? + let successfulSSOLoginURL: String? + let environmentDisplayName: String? +} + +public struct TenantContentView: View { + @ObservedObject var viewModel: TenantViewModel +// var tenants: [Tenant] = [] + @Environment(\.isHorizontal) private var isHorizontal + var isSwitchTenant: Bool + public init(viewModel: TenantViewModel, isSwitchTenant: Bool = false) { + self.viewModel = viewModel + self.isSwitchTenant = isSwitchTenant +// tenants = self.viewModel.config.tenantsConfig.tenants + } + + public var body: some View { + ZStack(alignment: .top) { + VStack(alignment: .center) { + if viewModel.storage.accessToken != nil, isSwitchTenant { + if viewModel.isSwitchedTenant { + ProgressView() + .onAppear { + viewModel.isSwitchedTenant = false + if viewModel.selectedTenant?.isSwitchTenantLoginEnabled ?? false { + viewModel.router.showLoginScreen(sourceScreen: .startup) + } else { + viewModel.router.showMainOrWhatsNewScreen( + sourceScreen: .discovery, + postLoginData: nil) + } + + } + } else { + BackNavigationButton( + color: Theme.Colors.accentColor, + action: { + viewModel.router.back(animated: true) + } + ) + + .backViewStyle() + .padding(.leading, isHorizontal ? 48 : 0) + .padding(.top, 11) + TenantSelectionView(viewModel: viewModel) + + } + } else { + if viewModel.selectedTenant != nil { + ProgressView() + .onAppear { + viewModel.router.showLoginScreen(sourceScreen: .startup) + } + } else { + TenantSelectionView(viewModel: viewModel) + + } + } + } + } + .navigationBarHidden(true) + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } + .onReceive(viewModel.$shouldNavigateBack.removeDuplicates()) { shouldNavigate in + if shouldNavigate { + DispatchQueue.main.async { + viewModel.router.back() + viewModel.shouldNavigateBack = false + } + } + } + } +} + +public struct TenantSelectionView: View { + @ObservedObject var viewModel: TenantViewModel + @State private var searchText: String = "" + @Environment(\.isHorizontal) private var isHorizontal + + public init(viewModel: TenantViewModel) { + self.viewModel = viewModel + } + var tenants: [Tenant] { + if searchText.isEmpty { + return viewModel.config.tenantsConfig.tenants + } else { + return viewModel.config.tenantsConfig.tenants.filter { + $0.name.lowercased().contains(searchText.lowercased()) || + $0.tenantName.lowercased().contains(searchText.lowercased()) + } + } + } + + public var body: some View { + VStack { + Text(AuthLocalization.TenantSelection.title) + .font(.title) + .padding() + + TextField(AuthLocalization.TenantSelection.searchTitle, text: $searchText) + .padding(8) + .background(Color(.systemGray6)) + .cornerRadius(10) + .padding([.horizontal, .top]) + + List(tenants) { tenant in + Button(action: { + viewModel.selectedTenant = viewModel.config.tenantsConfig.tenants.first( + where: { + return $0.name == tenant.name + }) + viewModel.isSwitchedTenant = true + }) { + HStack { + getLogo(name: tenant.name) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxWidth: 40, maxHeight: 40) + .accessibilityIdentifier("logo_image") + + Spacer(minLength: 5) + + Text(tenant.tenantName) + .foregroundColor(ThemeManager.shared.theme.colors.textPrimary) + .frame(maxWidth: .infinity, alignment: .leading) + } + .padding() + } + } + .searchable(text: $searchText) + } + .navigationBarHidden(true) + } + + func getLogo(name: String) -> Image { + switch name.lowercased() { + case "tenanta": + return ThemeAssets.appLogo.swiftUIImage + case "tenantb": + return ThemeAssets.appLogo.swiftUIImage + default: + return ThemeAssets.appLogo.swiftUIImage + } + } +} + +extension Color { + init(_ colorString: String) { + switch colorString.lowercased() { + case "green": + self = .green + case "blue": + self = .blue + case "red": + self = .red + // Add more mappings if needed + default: + self = .gray + } + } +} diff --git a/Authorization/Authorization/Presentation/MultiTenant/TenantViewModel.swift b/Authorization/Authorization/Presentation/MultiTenant/TenantViewModel.swift new file mode 100644 index 000000000..58e7a8185 --- /dev/null +++ b/Authorization/Authorization/Presentation/MultiTenant/TenantViewModel.swift @@ -0,0 +1,135 @@ +// +// TenantViewModel.swift +// Authorization +// +// Created by Rawan Matar on 02/03/2025. +// + +import Foundation +import SwiftUI +import Core +import Alamofire +import AuthenticationServices +import FacebookLogin +import GoogleSignIn +import MSAL +import Theme + +public class TenantViewModel: TenantProvider, ObservableObject { + public var ssoButtonTitle: String { + selectedTenant?.ssoButtonTitle ?? "SSO Sign in" + } + + public var feedbackEmail: String { + selectedTenant?.feedbackEmail ?? "support@example.com" + } + + public var oAuthClientId: String { + selectedTenant?.oAuthClientId ?? "" + } + + public var name: String { + selectedTenant?.name ?? "Unknown" + } + + public var tenantName: String { + selectedTenant?.tenantName ?? "Unknown" + } + + public var color: String { + selectedTenant?.color ?? "#007aff" + } + + public var baseURL: URL { + selectedTenant?.baseURL ?? URL(string: "http://localhost:8000")! + } + + public var baseURLHiddenLogin: URL { + selectedTenant?.baseURLHiddenLogin ?? URL(string: "http://localhost:8000")! + } + + public var baseSSOURL: URL { + selectedTenant?.baseSSOURL ?? URL(string: "test.com")! + } + + public var successfulSSOLoginURL: URL { + selectedTenant?.successfulSSOLoginURL ?? URL(string: "test.com")! + } + + public var environmentDisplayName: String { + selectedTenant?.environmentDisplayName ?? "Unknown" + } + + public var uiComponents: Core.UIComponentsConfig { + selectedTenant?.uiComponents ?? config.uiComponents + } + + @Published public var selectedTenant: Tenant? { + didSet { + saveToUserDefaults() + let name = selectedTenant?.name ?? "" + let localized = selectedTenant?.tenantName ?? "-" + //switch local DB + NotificationCenter.default.post( + name: .tenantDidChange, + object: nil, + userInfo: ["tenant": selectedTenant as Any] + ) + //switch theme + Task { + @MainActor in + ThemeManager.shared.applyTheme( + for: name, + localizedName: localized + ) + } + } + } + @Published public var isSwitchedTenant: Bool = false + @Published var shouldNavigateBack = false + + private func saveToUserDefaults() { + UserDefaults.standard.removeObject(forKey: "selectedTenant") + print("saveToUserDefaults") + if let tenant = selectedTenant { + print("tenant: \(tenant)") + do { + let data = try JSONEncoder().encode(tenant) + UserDefaults.standard.set(data, forKey: "selectedTenant") + } catch { + print("ERROR ENCOIDNG TENTANT") + } + } + } + + public func loadFromUserDefaults() { + guard let data = UserDefaults.standard.data(forKey: "selectedTenant"), + let tenant = try? JSONDecoder().decode(Tenant.self, from: data) else { return } + self.selectedTenant = tenant + } + + public func resetSelectedTenant() { + UserDefaults.standard.removeObject(forKey: "selectedTenant") + self.selectedTenant = nil + self.shouldNavigateBack = true + } + + let sourceScreen: LogistrationSourceScreen = .default + let router: AuthorizationRouter + public let config: ConfigProtocol + private let analytics: AuthorizationAnalytics + let storage: CoreStorage + + public init( + router: AuthorizationRouter, + config: ConfigProtocol, + analytics: AuthorizationAnalytics, + storage: CoreStorage + ) { + self.router = router + self.config = config + self.analytics = analytics + self.storage = storage + self.loadFromUserDefaults() + } +} diff --git a/Authorization/Authorization/Presentation/Registration/SignUpView.swift b/Authorization/Authorization/Presentation/Registration/SignUpView.swift index 4bf20dda2..d04511a1f 100644 --- a/Authorization/Authorization/Presentation/Registration/SignUpView.swift +++ b/Authorization/Authorization/Presentation/Registration/SignUpView.swift @@ -16,6 +16,7 @@ public struct SignUpView: View { private var disclosureGroupOpen: Bool = false @Environment(\.isHorizontal) private var isHorizontal + @Environment(\.layoutDirection) var layoutDirection @ObservedObject private var viewModel: SignUpViewModel @@ -30,9 +31,15 @@ public struct SignUpView: View { public var body: some View { ZStack(alignment: .top) { VStack { + #if TENANTS + ThemeAssets.headerBackground.swiftUIImage + .resizable() + .edgesIgnoringSafeArea(.top) + #else ThemeAssets.headerBackground.swiftUIImage - .resizable() - .edgesIgnoringSafeArea(.top) + .resizable() + .edgesIgnoringSafeArea(.top) + #endif } .frame(maxWidth: .infinity, maxHeight: 200) .accessibilityIdentifier("auth_bg_image") @@ -75,7 +82,7 @@ public struct SignUpView: View { .foregroundColor(Theme.Colors.textPrimary) .padding(.bottom, 20) .accessibilityIdentifier("signup_subtitle_text") - + if viewModel.thirdPartyAuthSuccess { Text(AuthLocalization.SignUp.successSigninLabel) .font(Theme.Fonts.titleMedium) @@ -90,21 +97,6 @@ public struct SignUpView: View { let requiredFields = viewModel.requiredFields let optionalFields = viewModel.optionalFields - - if viewModel.socialAuthEnabled, - !requiredFields.isEmpty { - SocialAuthView( - authType: .register, - viewModel: .init( - config: viewModel.config, - lastUsedOption: viewModel.storage.lastUsedSocialAuth - ) { result in - Task { await viewModel.register(with: result) } - } - ) - .padding(.top, 22) - .padding(.bottom, -2) - } FieldsView( fields: requiredFields, @@ -171,9 +163,18 @@ public struct SignUpView: View { .frameLimit(width: proxy.size.width) } .roundedBackground(Theme.Colors.background) - .onRightSwipeGesture { - viewModel.router.back() - } + .onSwipeGesture( + onLeftSwipe: { + if layoutDirection == .rightToLeft { + viewModel.router.back() + } + }, + onRightSwipe: { + if layoutDirection == .leftToRight { + viewModel.router.back() + } + } + ) .scrollAvoidKeyboard(dismissKeyboardByTap: true) .onChange(of: viewModel.scrollTo, perform: { index in withAnimation { diff --git a/Authorization/Authorization/Presentation/Registration/SignUpViewModel.swift b/Authorization/Authorization/Presentation/Registration/SignUpViewModel.swift index 88af34779..9a33057e9 100644 --- a/Authorization/Authorization/Presentation/Registration/SignUpViewModel.swift +++ b/Authorization/Authorization/Presentation/Registration/SignUpViewModel.swift @@ -58,7 +58,8 @@ public final class SignUpViewModel: ObservableObject { private let validator: Validator var authMethod: AuthMethod = .password let storage: CoreStorage - + public var selectedTenant: Tenant? + public init( interactor: AuthInteractorProtocol, router: AuthorizationRouter, @@ -166,7 +167,7 @@ public final class SignUpViewModel: ObservableObject { if let externalToken = externalToken, let backend = backend { validateFields["access_token"] = externalToken validateFields["provider"] = backend - validateFields["client_id"] = config.oAuthClientId + validateFields["client_id"] = selectedTenant?.oAuthClientId ?? "" if validateFields.contains(where: {$0.key == "password"}) { validateFields.removeValue(forKey: "password") } diff --git a/Authorization/Authorization/Presentation/Reset Password/ResetPasswordView.swift b/Authorization/Authorization/Presentation/Reset Password/ResetPasswordView.swift index e069b75e1..901f6edad 100644 --- a/Authorization/Authorization/Presentation/Reset Password/ResetPasswordView.swift +++ b/Authorization/Authorization/Presentation/Reset Password/ResetPasswordView.swift @@ -29,13 +29,19 @@ public struct ResetPasswordView: View { GeometryReader { proxy in ZStack(alignment: .top) { VStack { + #if TENANTS ThemeAssets.headerBackground.swiftUIImage .resizable() .edgesIgnoringSafeArea(.top) + #else + ThemeAssets.headerBackground.swiftUIImage + .resizable() + .edgesIgnoringSafeArea(.top) + #endif } .frame(maxWidth: .infinity, maxHeight: 200) .accessibilityIdentifier("auth_bg_image") - + VStack(alignment: .center) { NavigationBar(title: AuthLocalization.Forgot.title, titleColor: Theme.Colors.loginNavigationText, @@ -43,7 +49,7 @@ public struct ResetPasswordView: View { leftButtonAction: { viewModel.router.back() }).padding(.leading, isHorizontal ? 48 : 0) - + ScrollView { VStack { if isRecovered { @@ -55,7 +61,7 @@ public struct ResetPasswordView: View { .padding(.bottom, 40) .padding(.top, 100) .accessibilityIdentifier("check_email_image") - + Text(AuthLocalization.Forgot.checkTitle) .font(Theme.Fonts.titleLarge) .multilineTextAlignment(.center) @@ -76,7 +82,7 @@ public struct ResetPasswordView: View { .accessibilityIdentifier("signin_button") } } - + } else { VStack(alignment: .leading) { Text(AuthLocalization.Forgot.title) @@ -138,9 +144,9 @@ public struct ResetPasswordView: View { .frameLimit(width: proxy.size.width) }.roundedBackground(Theme.Colors.background) .scrollAvoidKeyboard(dismissKeyboardByTap: true) - + } - + // MARK: - Alert if viewModel.showAlert { VStack { @@ -150,7 +156,7 @@ public struct ResetPasswordView: View { .padding(.top, 80) .accessibilityIdentifier("show_alert_text") Spacer() - + } .transition(.move(edge: .top)) .onAppear { @@ -159,7 +165,7 @@ public struct ResetPasswordView: View { } } } - + // MARK: - Show error if viewModel.showError { VStack { @@ -174,7 +180,9 @@ public struct ResetPasswordView: View { } } .ignoresSafeArea(.all, edges: .horizontal) + .background(Theme.Colors.background.ignoresSafeArea(.all)) + .navigationBarHidden(true) } } diff --git a/Authorization/Authorization/Presentation/SSO/SSOWebView.swift b/Authorization/Authorization/Presentation/SSO/SSOWebView.swift index b525f91df..fd5d731d6 100644 --- a/Authorization/Authorization/Presentation/SSO/SSOWebView.swift +++ b/Authorization/Authorization/Presentation/SSO/SSOWebView.swift @@ -84,7 +84,7 @@ public struct SSOWebView: UIViewRepresentable { return } - if url.contains(viewModel.config.ssoFinishedURL.absoluteString) { + if url.contains(viewModel.tenantProvider().successfulSSOLoginURL.absoluteString) { webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in Task { await self.viewModel.SSOLogin(cookies: cookies) diff --git a/Authorization/Authorization/Presentation/SSO/SSOWebViewModel.swift b/Authorization/Authorization/Presentation/SSO/SSOWebViewModel.swift index a1bd57936..3bdf26d66 100644 --- a/Authorization/Authorization/Presentation/SSO/SSOWebViewModel.swift +++ b/Authorization/Authorization/Presentation/SSO/SSOWebViewModel.swift @@ -43,19 +43,22 @@ public class SSOWebViewModel: ObservableObject { private let interactor: AuthInteractorProtocol private let analytics: AuthorizationAnalytics let ssoHelper: SSOHelper + let tenantProvider: @Sendable () -> any TenantProvider public init( interactor: AuthInteractorProtocol, router: AuthorizationRouter, config: ConfigProtocol, analytics: AuthorizationAnalytics, - ssoHelper: SSOHelper + ssoHelper: SSOHelper, + tenantProvider: @escaping @Sendable () -> any TenantProvider ) { self.interactor = interactor self.router = router self.config = config self.analytics = analytics self.ssoHelper = ssoHelper + self.tenantProvider = tenantProvider } @MainActor diff --git a/Authorization/Authorization/Presentation/Startup/StartupView.swift b/Authorization/Authorization/Presentation/Startup/StartupView.swift index 32c73b673..1f580e461 100644 --- a/Authorization/Authorization/Presentation/Startup/StartupView.swift +++ b/Authorization/Authorization/Presentation/Startup/StartupView.swift @@ -26,6 +26,7 @@ public struct StartupView: View { public var body: some View { ZStack(alignment: .top) { VStack(alignment: .leading) { + #if TENANTS ThemeAssets.appLogo.swiftUIImage .resizable() .aspectRatio(contentMode: .fit) @@ -35,6 +36,17 @@ public struct StartupView: View { .padding(.horizontal, isHorizontal ? 10 : 24) .colorMultiply(Theme.Colors.accentColor) .accessibilityIdentifier("logo_image") + #else + ThemeAssets.appLogo.swiftUIImage + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxWidth: 189, maxHeight: 89) + .padding(.top, isHorizontal ? 20 : 40) + .padding(.bottom, isHorizontal ? 0 : 20) + .padding(.horizontal, isHorizontal ? 10 : 24) + .colorMultiply(Theme.Colors.accentColor) + .accessibilityIdentifier("logo_image") + #endif VStack { VStack(alignment: .leading) { @@ -62,7 +74,6 @@ public struct StartupView: View { searchQuery: searchQuery, sourceScreen: .startup ) - viewModel.logAnalytics(searchQuery: searchQuery) }) .autocapitalization(.none) .autocorrectionDisabled() @@ -90,7 +101,6 @@ public struct StartupView: View { searchQuery: searchQuery, sourceScreen: .startup ) - viewModel.logAnalytics() } label: { Text(AuthLocalization.Startup.exploreAllCourses) .underline() diff --git a/Authorization/Authorization/SwiftGen/Strings.swift b/Authorization/Authorization/SwiftGen/Strings.swift index c72255aa0..f1908eb82 100644 --- a/Authorization/Authorization/SwiftGen/Strings.swift +++ b/Authorization/Authorization/SwiftGen/Strings.swift @@ -66,10 +66,7 @@ public enum AuthLocalization { public static let emailOrUsername = AuthLocalization.tr("Localizable", "SIGN_IN.EMAIL_OR_USERNAME", fallback: "Email or username") /// Forgot password? public static let forgotPassBtn = AuthLocalization.tr("Localizable", "SIGN_IN.FORGOT_PASS_BTN", fallback: "Forgot password?") - /// Localizable.strings - /// Authorization - /// - /// Created by Vladimir Chekyrta on 13.09.2022. + /// Sign in public static let logInTitle = AuthLocalization.tr("Localizable", "SIGN_IN.LOG_IN_TITLE", fallback: "Sign in") /// Password public static let password = AuthLocalization.tr("Localizable", "SIGN_IN.PASSWORD", fallback: "Password") @@ -118,6 +115,15 @@ public enum AuthLocalization { /// Start public static let title = AuthLocalization.tr("Localizable", "STARTUP.TITLE", fallback: "Start") } + public enum TenantSelection { + /// Search for a Platform + public static let searchTitle = AuthLocalization.tr("Localizable", "TENANT_SELECTION.SEARCH_TITLE", fallback: "Search for a Platform") + /// Localizable.strings + /// Authorization + /// + /// Created by Vladimir Chekyrta on 13.09.2022. + public static let title = AuthLocalization.tr("Localizable", "TENANT_SELECTION.TITLE", fallback: "Select a Platform") + } } // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces diff --git a/Authorization/Authorization/en.lproj/Localizable.strings b/Authorization/Authorization/en.lproj/Localizable.strings index de9e0dd5f..12740e333 100644 --- a/Authorization/Authorization/en.lproj/Localizable.strings +++ b/Authorization/Authorization/en.lproj/Localizable.strings @@ -5,6 +5,8 @@ Created by Vladimir Chekyrta on 13.09.2022. */ +"TENANT_SELECTION.TITLE" = "Select a Platform"; +"TENANT_SELECTION.SEARCH_TITLE" = "Search for a Platform"; "SIGN_IN.LOG_IN_TITLE" = "Sign in"; "SIGN_IN.WELCOME_BACK" = "Welcome back! Sign in to access your courses."; diff --git a/Core/Core.xcodeproj/project.pbxproj b/Core/Core.xcodeproj/project.pbxproj index bf9943aa9..74fce986a 100644 --- a/Core/Core.xcodeproj/project.pbxproj +++ b/Core/Core.xcodeproj/project.pbxproj @@ -132,6 +132,8 @@ 14769D3C2B9822EE00AB36D4 /* CoreAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14769D3B2B9822EE00AB36D4 /* CoreAnalytics.swift */; }; 5E58740A2AA9DF20F4644191 /* Pods_App_Core_CoreTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33FA09A20AAE2B2A0BA89190 /* Pods_App_Core_CoreTests.framework */; }; 9784D47E2BF7762800AFEFFF /* FullScreenErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9784D47D2BF7762800AFEFFF /* FullScreenErrorView.swift */; }; + 9972D17A2E5F1CF60020CFBD /* TenantsConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D1792E5F1CF60020CFBD /* TenantsConfig.swift */; }; + 9972D17C2E5F1F1F0020CFBD /* NavigationAppearanceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D17B2E5F1F1F0020CFBD /* NavigationAppearanceManager.swift */; }; A53A32352B233DEC005FE38A /* ThemeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A32342B233DEC005FE38A /* ThemeConfig.swift */; }; A595689B2B6173DF00ED4F90 /* BranchConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A595689A2B6173DF00ED4F90 /* BranchConfig.swift */; }; A5D4B3DE2CDD0A9700688951 /* SecureInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D4B3DD2CDD0A9700688951 /* SecureInputView.swift */; }; @@ -337,6 +339,7 @@ 141F1D2F2B7328D4009E81EB /* WebviewCookiesUpdateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebviewCookiesUpdateProtocol.swift; sourceTree = ""; }; 14769D3B2B9822EE00AB36D4 /* CoreAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreAnalytics.swift; sourceTree = ""; }; 1A154A95AF4EE85A4A1C083B /* Pods-App-Core.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.releasedev.xcconfig"; sourceTree = ""; }; + 1FA6477F0518ACE12DE7CE63 /* Pods-App-Core-CoreTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; 2B7E6FE7843FC4CF2BFA712D /* Pods-App-Core.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.debug.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.debug.xcconfig"; sourceTree = ""; }; 33FA09A20AAE2B2A0BA89190 /* Pods_App_Core_CoreTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Core_CoreTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 349B90CD6579F7B8D257E515 /* Pods_App_Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -344,16 +347,20 @@ 3C63D5D2247C793C259341B8 /* Pods-App-Core-CoreTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.releasedev.xcconfig"; sourceTree = ""; }; 5CEFA8766C44C519B86C681D /* Pods-App-Core-CoreTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.debug.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.debug.xcconfig"; sourceTree = ""; }; 60153262DBC2F9E660D7E11B /* Pods-App-Core.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.release.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.release.xcconfig"; sourceTree = ""; }; + 8D1CA66790F551B9084DB467 /* Pods-App-Core.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.debugprodtenants.xcconfig"; sourceTree = ""; }; 8F3B171E9FA5E6F40B4890A8 /* Pods-App-Core-CoreTests.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.debugstage.xcconfig"; sourceTree = ""; }; 90D63D7E70B8F5027A211EA3 /* Pods-CoreTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreTests.debugprod.xcconfig"; path = "Target Support Files/Pods-CoreTests/Pods-CoreTests.debugprod.xcconfig"; sourceTree = ""; }; 951751177FD4703992DC1491 /* Pods-CoreTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreTests.releasestage.xcconfig"; path = "Target Support Files/Pods-CoreTests/Pods-CoreTests.releasestage.xcconfig"; sourceTree = ""; }; 9784D47D2BF7762800AFEFFF /* FullScreenErrorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullScreenErrorView.swift; sourceTree = ""; }; + 9972D1792E5F1CF60020CFBD /* TenantsConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TenantsConfig.swift; sourceTree = ""; }; + 9972D17B2E5F1F1F0020CFBD /* NavigationAppearanceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationAppearanceManager.swift; sourceTree = ""; }; 9D5B06CAA99EA5CD49CBE2BB /* Pods-App-Core.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.debugdev.xcconfig"; sourceTree = ""; }; 9E0B33614CBD791307FFDEAE /* Pods-App-Core-CoreTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.release.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.release.xcconfig"; sourceTree = ""; }; A53A32342B233DEC005FE38A /* ThemeConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeConfig.swift; sourceTree = ""; }; A595689A2B6173DF00ED4F90 /* BranchConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BranchConfig.swift; sourceTree = ""; }; A5D4B3DD2CDD0A9700688951 /* SecureInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInputView.swift; sourceTree = ""; }; A5F4E7B42B61544A00ACD166 /* BrazeConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeConfig.swift; sourceTree = ""; }; + A834B3AC9D8E33F6B0F77BFB /* Pods-App-Core.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.openedxmultitenants.xcconfig"; sourceTree = ""; }; B2556B4A2D4F84F402A7A7D9 /* Pods-CoreTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-CoreTests/Pods-CoreTests.releaseprod.xcconfig"; sourceTree = ""; }; BA4AFB412B5A7A0900A21367 /* VideoDownloadQualityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDownloadQualityView.swift; sourceTree = ""; }; BA4AFB432B6A5AF100A21367 /* CheckBoxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxView.swift; sourceTree = ""; }; @@ -393,6 +400,7 @@ E0D586192B2FF74C009B4BA7 /* DiscoveryConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryConfig.swift; sourceTree = ""; }; E0D586352B314CD3009B4BA7 /* LogistrationBottomView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogistrationBottomView.swift; sourceTree = ""; }; E8D9725130C85DA55AD474A4 /* Pods-CoreTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreTests.debug.xcconfig"; path = "Target Support Files/Pods-CoreTests/Pods-CoreTests.debug.xcconfig"; sourceTree = ""; }; + ECFED61297F87F0F1E4CB043 /* Pods-App-Core-CoreTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.debugprodtenants.xcconfig"; sourceTree = ""; }; F4E50CE1DB6AA77E9B5D09EF /* Pods-App-Core-CoreTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.debugprod.xcconfig"; sourceTree = ""; }; F7ED6F0C276DBD2F1BA38987 /* Pods-CoreTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreTests.release.xcconfig"; path = "Target Support Files/Pods-CoreTests/Pods-CoreTests.release.xcconfig"; sourceTree = ""; }; FB6C49AC95A27A1222AD0F06 /* Pods-App-Core-CoreTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core-CoreTests.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Core-CoreTests/Pods-App-Core-CoreTests.releasestage.xcconfig"; sourceTree = ""; }; @@ -674,6 +682,7 @@ 0770DE0A28D07831006D8A5D /* Core */ = { isa = PBXGroup; children = ( + 9972D17B2E5F1F1F0020CFBD /* NavigationAppearanceManager.swift */, 14769D3A2B9822D900AB36D4 /* Analytics */, BA8FA65F2AD5973500EA029A /* Providers */, 027BD3A12909470F00392132 /* AvoidingHelpers */, @@ -841,6 +850,10 @@ B2556B4A2D4F84F402A7A7D9 /* Pods-CoreTests.releaseprod.xcconfig */, 951751177FD4703992DC1491 /* Pods-CoreTests.releasestage.xcconfig */, FD97820E148E423964AC0CAB /* Pods-CoreTests.releasedev.xcconfig */, + A834B3AC9D8E33F6B0F77BFB /* Pods-App-Core.openedxmultitenants.xcconfig */, + 1FA6477F0518ACE12DE7CE63 /* Pods-App-Core-CoreTests.openedxmultitenants.xcconfig */, + 8D1CA66790F551B9084DB467 /* Pods-App-Core.debugprodtenants.xcconfig */, + ECFED61297F87F0F1E4CB043 /* Pods-App-Core-CoreTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -898,6 +911,7 @@ A53A32342B233DEC005FE38A /* ThemeConfig.swift */, E0D586192B2FF74C009B4BA7 /* DiscoveryConfig.swift */, CE38BBD62D9D8294002CD276 /* ExperimentalFeaturesConfig.swift */, + 9972D1792E5F1CF60020CFBD /* TenantsConfig.swift */, ); path = Config; sourceTree = ""; @@ -1167,6 +1181,7 @@ 027F1BF72C071C820001A24C /* NavigationTitle.swift in Sources */, CE1D5B7D2CE65D360019CA34 /* Protected.swift in Sources */, 06619EAA2B8F2936001FAADE /* ReadabilityModifier.swift in Sources */, + 9972D17A2E5F1CF60020CFBD /* TenantsConfig.swift in Sources */, BAFB99902B14B377007D09F9 /* GoogleConfig.swift in Sources */, 029A132C2C2471F8005FB830 /* OfflineSyncEndpoint.swift in Sources */, A5D4B3DE2CDD0A9700688951 /* SecureInputView.swift in Sources */, @@ -1238,6 +1253,7 @@ 029A13282C246AE6005FB830 /* OfflineSyncManager.swift in Sources */, 02E93F852AEBAEBC006C4750 /* AppReviewViewModel.swift in Sources */, A595689B2B6173DF00ED4F90 /* BranchConfig.swift in Sources */, + 9972D17C2E5F1F1F0020CFBD /* NavigationAppearanceManager.swift in Sources */, 0770DE2528D08FBA006D8A5D /* CoreStorage.swift in Sources */, 020306CC2932C0C4000949EA /* PickerView.swift in Sources */, 027BD3C52909707700392132 /* Shake.swift in Sources */, @@ -2311,6 +2327,252 @@ }; name = Release; }; + 9958869D2E64470D0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 9958869E2E64470D0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8D1CA66790F551B9084DB467 /* Pods-App-Core.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Core; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = TENANTS; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9958869F2E64470D0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ECFED61297F87F0F1E4CB043 /* Pods-App-Core-CoreTests.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.CoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1D72E6037390020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1D82E6037390020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A834B3AC9D8E33F6B0F77BFB /* Pods-App-Core.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Core; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = TENANTS; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1D92E6037390020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1FA6477F0518ACE12DE7CE63 /* Pods-App-Core-CoreTests.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.CoreTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2318,11 +2580,13 @@ isa = XCConfigurationList; buildConfigurations = ( 07169470296D996900E3DED6 /* Debug */, + 9972D1D92E6037390020CFBD /* OpenEdXMultiTenants */, 07169471296D996900E3DED6 /* DebugProd */, 02DD1C9B29E80CE400F35DCE /* DebugStage */, 07169472296D996900E3DED6 /* DebugDev */, 07169473296D996900E3DED6 /* Release */, 07169474296D996900E3DED6 /* ReleaseProd */, + 9958869F2E64470D0065D132 /* DebugProdTenants */, 02DD1C9E29E80CED00F35DCE /* ReleaseStage */, 07169475296D996900E3DED6 /* ReleaseDev */, ); @@ -2333,11 +2597,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0770DE0D28D07831006D8A5D /* Debug */, + 9972D1D72E6037390020CFBD /* OpenEdXMultiTenants */, 0727876028D23277002E9142 /* DebugProd */, 02DD1C9929E80CE400F35DCE /* DebugStage */, 0727875C28D2326B002E9142 /* DebugDev */, 0770DE0E28D07831006D8A5D /* Release */, 0727876228D2327C002E9142 /* ReleaseProd */, + 9958869D2E64470D0065D132 /* DebugProdTenants */, 02DD1C9C29E80CED00F35DCE /* ReleaseStage */, 0727875E28D23272002E9142 /* ReleaseDev */, ); @@ -2348,11 +2614,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0770DE1028D07831006D8A5D /* Debug */, + 9972D1D82E6037390020CFBD /* OpenEdXMultiTenants */, 0727876128D23277002E9142 /* DebugProd */, 02DD1C9A29E80CE400F35DCE /* DebugStage */, 0727875D28D2326B002E9142 /* DebugDev */, 0770DE1128D07831006D8A5D /* Release */, 0727876328D2327C002E9142 /* ReleaseProd */, + 9958869E2E64470D0065D132 /* DebugProdTenants */, 02DD1C9D29E80CED00F35DCE /* ReleaseStage */, 0727875F28D23272002E9142 /* ReleaseDev */, ); diff --git a/Core/Core/Configuration/BaseRouter.swift b/Core/Core/Configuration/BaseRouter.swift index c18d01c80..ddb2e0c80 100644 --- a/Core/Core/Configuration/BaseRouter.swift +++ b/Core/Core/Configuration/BaseRouter.swift @@ -26,6 +26,8 @@ public protocol BaseRouter: Sendable { func showStartupScreen() + func showTenantScreen(sourceScreen: LogistrationSourceScreen) + func showLoginScreen(sourceScreen: LogistrationSourceScreen) func showRegisterScreen(sourceScreen: LogistrationSourceScreen) @@ -84,6 +86,8 @@ open class BaseRouterMock: BaseRouter { public func showMainOrWhatsNewScreen(sourceScreen: LogistrationSourceScreen, postLoginData: PostLoginData?) {} + public func showTenantScreen(sourceScreen: LogistrationSourceScreen) {} + public func showStartupScreen() {} public func showLoginScreen(sourceScreen: LogistrationSourceScreen) {} diff --git a/Core/Core/Configuration/CSSInjector.swift b/Core/Core/Configuration/CSSInjector.swift index 8e4625c59..395526d52 100644 --- a/Core/Core/Configuration/CSSInjector.swift +++ b/Core/Core/Configuration/CSSInjector.swift @@ -10,11 +10,12 @@ import SwiftUI import Theme public class CSSInjector { - + private let tenantProvider: TenantProvider public let baseURL: URL - public init(config: ConfigProtocol) { - self.baseURL = config.baseURL + public init(config: ConfigProtocol, tenantProvider: TenantProvider) { + self.tenantProvider = tenantProvider + self.baseURL = tenantProvider.baseURL } public enum CssType { @@ -157,7 +158,8 @@ public class CSSInjector { #if DEBUG public class CSSInjectorMock: CSSInjector { public convenience init() { - self.init(config: ConfigMock()) + let mockTenantProvider = TenantProviderMock( uiComponents: UIComponentsConfig(dictionary: [:])) + self.init(config: ConfigMock(), tenantProvider: mockTenantProvider) } } #endif diff --git a/Core/Core/Configuration/Config/Config.swift b/Core/Core/Configuration/Config/Config.swift index 6364069df..da2c03a26 100644 --- a/Core/Core/Configuration/Config/Config.swift +++ b/Core/Core/Configuration/Config/Config.swift @@ -9,13 +9,13 @@ import Foundation //sourcery: AutoMockable public protocol ConfigProtocol: Sendable { - var baseURL: URL { get } - var baseSSOURL: URL { get } - var ssoFinishedURL: URL { get } - var ssoButtonTitle: [String: Any] { get } - var oAuthClientId: String { get } +// var baseURL: URL { get } +// var baseSSOURL: URL { get } +// var ssoFinishedURL: URL { get } +// var ssoButtonTitle: [String: Any] { get } +// var oAuthClientId: String { get } var tokenType: TokenType { get } - var feedbackEmail: String { get } +// var feedbackEmail: String { get } var appStoreLink: String { get } var faq: URL? { get } var platformName: String { get } @@ -30,6 +30,7 @@ public protocol ConfigProtocol: Sendable { var uiComponents: UIComponentsConfig { get } var discovery: DiscoveryConfig { get } var dashboard: DashboardConfig { get } + var tenantsConfig: TenantsConfig { get } var braze: BrazeConfig { get } var branch: BranchConfig { get } var program: DiscoveryConfig { get } @@ -56,6 +57,7 @@ private enum ConfigKeys: String, Sendable { case appstoreID = "APP_STORE_ID" case faq = "FAQ_URL" case URIScheme = "URI_SCHEME" + case tenantsKey = "TENANTS" } public class Config: @unchecked Sendable { @@ -118,44 +120,44 @@ public class Config: @unchecked Sendable { } extension Config: ConfigProtocol { - public var baseURL: URL { - guard let urlString = string(for: ConfigKeys.baseURL.rawValue), - let url = URL(string: urlString) else { - fatalError("Unable to find base url in config.") - } - return url - } - - public var baseSSOURL: URL { - guard let urlString = string(for: ConfigKeys.ssoBaseURL.rawValue), - let url = URL(string: urlString) else { - fatalError("Unable to find SSO base url in config.") - } - return url - } - - public var ssoFinishedURL: URL { - guard let urlString = string(for: ConfigKeys.ssoFinishedURL.rawValue), - let url = URL(string: urlString) else { - fatalError("Unable to find SSO successful login url in config.") - } - return url - } - - public var ssoButtonTitle: [String: Any] { - guard let ssoButtonTitle = dict(for: ConfigKeys.ssoButtonTitle.rawValue) else { - return ["en": CoreLocalization.SignIn.logInWithSsoBtn] - } - return ssoButtonTitle - } - - public var oAuthClientId: String { - guard let clientID = string(for: ConfigKeys.oAuthClientID.rawValue) else { - fatalError("Unable to find OAuth ClientID in config.") - } - return clientID - } - +// public var baseURL: URL { +// guard let urlString = string(for: ConfigKeys.baseURL.rawValue), +// let url = URL(string: urlString) else { +// fatalError("Unable to find base url in config.") +// } +// return url +// } +// +// public var baseSSOURL: URL { +// guard let urlString = string(for: ConfigKeys.ssoBaseURL.rawValue), +// let url = URL(string: urlString) else { +// fatalError("Unable to find SSO base url in config.") +// } +// return url +// } +// +// public var ssoFinishedURL: URL { +// guard let urlString = string(for: ConfigKeys.ssoFinishedURL.rawValue), +// let url = URL(string: urlString) else { +// fatalError("Unable to find SSO successful login url in config.") +// } +// return url +// } +// +// public var ssoButtonTitle: [String: Any] { +// guard let ssoButtonTitle = dict(for: ConfigKeys.ssoButtonTitle.rawValue) else { +// return ["en": CoreLocalization.SignIn.logInWithSsoBtn] +// } +// return ssoButtonTitle +// } +// +// public var oAuthClientId: String { +// guard let clientID = string(for: ConfigKeys.oAuthClientID.rawValue) else { +// fatalError("Unable to find OAuth ClientID in config.") +// } +// return clientID +// } +// public var tokenType: TokenType { guard let tokenTypeValue = string(for: ConfigKeys.tokenType.rawValue), let tokenType = TokenType(rawValue: tokenTypeValue) @@ -163,10 +165,10 @@ extension Config: ConfigProtocol { return tokenType } - public var feedbackEmail: String { - return string(for: ConfigKeys.feedbackEmailAddress.rawValue) ?? "" - } - +// public var feedbackEmail: String { +// return string(for: ConfigKeys.feedbackEmailAddress.rawValue) ?? "" +// } +// public var platformName: String { return string(for: ConfigKeys.platformName.rawValue) ?? "" } @@ -190,6 +192,17 @@ extension Config: ConfigProtocol { public var URIScheme: String { return string(for: ConfigKeys.URIScheme.rawValue) ?? "" } + + public var tenantsConfig: TenantsConfig { + let array = properties[ConfigKeys.tenantsKey.rawValue] as? [[String: Any]] ?? [] + print("tenant config: \(array)") + return TenantsConfig(array: array) + } + + public var selectedTenantKey: String { + UserDefaults.standard.string(forKey: "selectedTenant") + ?? "" + } } // Mark - For testing and SwiftUI preview diff --git a/Core/Core/Configuration/Config/TenantsConfig.swift b/Core/Core/Configuration/Config/TenantsConfig.swift new file mode 100644 index 000000000..189c1d883 --- /dev/null +++ b/Core/Core/Configuration/Config/TenantsConfig.swift @@ -0,0 +1,171 @@ +// +// TenantConfig.swift +// Core +// +// Created by Rawan Matar on 15/04/2025. +// + +import Foundation +import OEXFoundation + +public protocol TenantProvider { + var name: String { get } + var tenantName: String { get } + var color: String { get } + var oAuthClientId: String { get } + var baseURL: URL { get } + var baseURLHiddenLogin: URL { get } + var baseSSOURL: URL { get } + var ssoButtonTitle: String { get } + var successfulSSOLoginURL: URL { get } + var environmentDisplayName: String { get } + var feedbackEmail: String { get } + var uiComponents: UIComponentsConfig { get } +} + +private enum TenantKeys: String, RawStringExtractable { + case name + case tenantName = "TENANT_NAME" + case color + case oAuthClientId = "OAUTH_CLIENT_ID" + case baseURL = "API_HOST_URL" + case baseURLHiddenLogin = "API_HOST_URL_HIDDEN_LOGIN" + case baseSSOURL = "SSO_URL" + case SuccessfulSSOLoginURL = "SSO_URL_SUCCESSFUL_LOGIN" + case ssoButtonTitle = "SSO_BUTTON_TITLE" + case feedbackEmailAddress = "FEEDBACK_EMAIL_ADDRESS" + case environmentDisplayName = "ENVIRONMENT_DISPLAY_NAME" + case isSwitchTenantLoginEnabled = "IS_SWITCH_TENANT_LOGIN_ENABLED" + case uiComponents = "UI_COMPONENTS" +} + +public class Tenant: Codable, Identifiable { + public var id = UUID() + public let name: String + public var tenantName: String + public let color: String + public var oAuthClientId: String + public var feedbackEmail: String? + public var baseURL: URL? + public var baseURLHiddenLogin: URL? + public var baseSSOURL: URL? + public var ssoButtonTitle: String + public var successfulSSOLoginURL: URL? + public var environmentDisplayName: String? + public var isSwitchTenantLoginEnabled: Bool + public var uiComponents: UIComponentsConfig? + + init(dictionary: [String: Any]) { + self.name = dictionary[TenantKeys.name] as? String ?? "" + var languageCode: String = "en" + if let langCode = Locale.preferredLanguages.first?.prefix(2) { + languageCode = String(langCode) + } + if let tenantNameDict = dictionary[TenantKeys.tenantName] as? [String: Any] { + self.tenantName = tenantNameDict[languageCode] as? String ?? "" + } else { + self.tenantName = "unknown" + } + self.isSwitchTenantLoginEnabled = dictionary[TenantKeys.isSwitchTenantLoginEnabled] as? Bool ?? false + self.color = dictionary[TenantKeys.color] as? String ?? "" + self.oAuthClientId = dictionary[TenantKeys.oAuthClientId] as? String ?? "" + + if let urlString = dictionary[TenantKeys.baseURL] as? String + , let url = URL(string: urlString) { + self.baseURL = url + } + + if let urlString = dictionary[TenantKeys.baseURLHiddenLogin] as? String + , let url = URL(string: urlString) { + self.baseURLHiddenLogin = url + } + if let urlString = dictionary[TenantKeys.baseSSOURL] as? String + , let url = URL(string: urlString) { + self.baseSSOURL = url + } + if let urlString = dictionary[TenantKeys.SuccessfulSSOLoginURL] as? String + , let url = URL(string: urlString) { + self.successfulSSOLoginURL = url + } + + if let tenantSSOButtonNameDict = dictionary[TenantKeys.ssoButtonTitle] as? [String: Any] { + self.ssoButtonTitle = tenantSSOButtonNameDict[languageCode] as? String ?? "" + } else { + self.ssoButtonTitle = "unknown" + } + + self.feedbackEmail = dictionary[TenantKeys.feedbackEmailAddress] as? String ?? "" + + self.environmentDisplayName = dictionary[TenantKeys.environmentDisplayName] as? String + if let uiDict = dictionary[TenantKeys.uiComponents] as? [String: Any] { + self.uiComponents = UIComponentsConfig(dictionary: uiDict) + } else { + self.uiComponents = nil + } + } +} + +public class TenantsConfig { + public let tenants: [Tenant] + + public convenience init() { + self.init(array: [[:]]) + } + + init(array: [[String: Any]]) { + self.tenants = array.map { Tenant(dictionary: $0) } + } +} +#if DEBUG +public class TenantProviderMock: TenantProvider { + public var ssoButtonTitle: String + + public var name: String + + public var tenantName: String + + public var color: String + + public var feedbackEmail: String + + public var oAuthClientId: String + + public var baseURL: URL + + public var baseURLHiddenLogin: URL + + public var baseSSOURL: URL + + public var successfulSSOLoginURL: URL + + public var environmentDisplayName: String + + public var uiComponents: UIComponentsConfig + + public init( + oAuthClientId: String = "mockClientId", + baseURL: URL = URL(string: "https://mock.base.url")!, + name: String = "Test", + tenantName: String = "Test", + color: String = "#fff", + feedbackEmail: String = "support@example.com", + baseSSOURL: URL = URL(string: "https://mock.base.url")!, + successfulSSOLoginURL: URL = URL(string: "https://mock.base.url")!, + environmentDisplayName: String = "Test", + uiComponents: UIComponentsConfig? = nil, + ssoButtonTitle: String = "") { + self.oAuthClientId = oAuthClientId + self.baseURL = baseURL + self.name = name + self.tenantName = tenantName + self.color = color + self.baseSSOURL = baseSSOURL + self.successfulSSOLoginURL = successfulSSOLoginURL + self.environmentDisplayName = environmentDisplayName + self.uiComponents = UIComponentsConfig(dictionary: [:]) + self.baseURLHiddenLogin = baseURL + self.feedbackEmail = feedbackEmail + self.ssoButtonTitle = ssoButtonTitle + } +} +#endif diff --git a/Core/Core/Configuration/Config/UIComponentsConfig.swift b/Core/Core/Configuration/Config/UIComponentsConfig.swift index c62b20774..aee2467f0 100644 --- a/Core/Core/Configuration/Config/UIComponentsConfig.swift +++ b/Core/Core/Configuration/Config/UIComponentsConfig.swift @@ -16,7 +16,7 @@ private enum Keys: String, RawStringExtractable { case samlSSODefaultLoginButton = "SAML_SSO_DEFAULT_LOGIN_BUTTON" } -public class UIComponentsConfig: NSObject { +public class UIComponentsConfig: NSObject, Codable, Identifiable { public var courseDropDownNavigationEnabled: Bool public var courseUnitProgressEnabled: Bool public var loginRegistrationEnabled: Bool diff --git a/Core/Core/Data/Repository/AuthRepository.swift b/Core/Core/Data/Repository/AuthRepository.swift index 18671e890..530541db4 100644 --- a/Core/Core/Data/Repository/AuthRepository.swift +++ b/Core/Core/Data/Repository/AuthRepository.swift @@ -24,11 +24,17 @@ public actor AuthRepository: AuthRepositoryProtocol { private let api: API private var appStorage: CoreStorage private let config: ConfigProtocol + private let tenantProvider: () -> TenantProvider - public init(api: API, appStorage: CoreStorage, config: ConfigProtocol) { + public init( + api: API, + appStorage: CoreStorage, + config: ConfigProtocol, + tenantProvider: @escaping () -> TenantProvider) { self.api = api self.appStorage = appStorage self.config = config + self.tenantProvider = tenantProvider } public func login(username: String, password: String) async throws -> User { @@ -36,7 +42,7 @@ public actor AuthRepository: AuthRepositoryProtocol { let endPoint = AuthEndpoint.getAccessToken( username: username, password: password, - clientId: config.oAuthClientId, + clientId: tenantProvider().oAuthClientId, tokenType: config.tokenType.rawValue ) let authResponse = try await api.requestData(endPoint).mapResponse(DataLayer.AuthResponse.self) @@ -61,7 +67,7 @@ public actor AuthRepository: AuthRepositoryProtocol { let endPoint = AuthEndpoint.exchangeAccessToken( externalToken: externalToken, backend: backend, - clientId: config.oAuthClientId, + clientId: tenantProvider().oAuthClientId, tokenType: config.tokenType.rawValue ) let authResponse = try await api.requestData(endPoint).mapResponse(DataLayer.AuthResponse.self) diff --git a/Core/Core/Extensions/Notification.swift b/Core/Core/Extensions/Notification.swift index 5e8dc6416..915b2585b 100644 --- a/Core/Core/Extensions/Notification.swift +++ b/Core/Core/Extensions/Notification.swift @@ -23,6 +23,7 @@ public extension Notification.Name { static let showDownloadFailed = Notification.Name("showDownloadFailed") static let tryDownloadAgain = Notification.Name("tryDownloadAgain") static let refreshEnrollments = Notification.Name("refreshEnrollments") + static let tenantDidChange = Notification.Name("tenantDidChange") static let onVideoProgressUpdated = Notification.Name("onVideoProgressUpdated") static let onAssignmentProgressUpdated = Notification.Name("onAssignmentProgressUpdated") } diff --git a/Core/Core/Extensions/ViewExtension.swift b/Core/Core/Extensions/ViewExtension.swift index 92766f5e6..482cc2ba5 100644 --- a/Core/Core/Extensions/ViewExtension.swift +++ b/Core/Core/Extensions/ViewExtension.swift @@ -55,8 +55,8 @@ public extension View { func shadowCardStyle( top: CGFloat? = 0, bottom: CGFloat? = 0, - bgColor: Color = Theme.Colors.cardViewBackground, - textColor: Color = Theme.Colors.textPrimary + bgColor: Color, + textColor: Color ) -> some View { return self .padding(.all, 16) @@ -79,7 +79,7 @@ public extension View { func titleSettings( top: CGFloat? = 10, bottom: CGFloat? = 20, - color: Color = Theme.Colors.textPrimary + color: Color ) -> some View { return self .lineLimit(1) @@ -130,6 +130,22 @@ public extension View { } } } + + func onSwipeGesture(onLeftSwipe: @escaping () -> Void, onRightSwipe: @escaping () -> Void) -> some View { + self.gesture( + DragGesture(minimumDistance: 20, coordinateSpace: .local) + .onEnded { value in + // Check for right swipe + if value.translation.width > 50 && abs(value.translation.height) < 50 { + onRightSwipe() + } + // Check for left swipe + else if value.translation.width < -50 && abs(value.translation.height) < 50 { + onLeftSwipe() + } + } + ) + } } public extension View { diff --git a/Core/Core/NavigationAppearanceManager.swift b/Core/Core/NavigationAppearanceManager.swift new file mode 100644 index 000000000..1fd6afb71 --- /dev/null +++ b/Core/Core/NavigationAppearanceManager.swift @@ -0,0 +1,32 @@ +// +// NavigationAppearanceManager.swift +// OpenEdX +// +// Created by Rawan Matar on 28/05/2025. +// + +import UIKit + +public class NavigationAppearanceManager { + @MainActor public static let shared = NavigationAppearanceManager() + + private init() {} + + public var navigationController: UINavigationController? + + @MainActor public func updateAppearance(backgroundColor: UIColor, titleColor: UIColor = .white) { + guard let nav = navigationController else { + return + } + let appearance = UINavigationBarAppearance() + appearance.configureWithOpaqueBackground() + appearance.backgroundColor = backgroundColor + appearance.titleTextAttributes = [.foregroundColor: titleColor] + appearance.largeTitleTextAttributes = [.foregroundColor: titleColor] + + nav.navigationBar.standardAppearance = appearance + nav.navigationBar.scrollEdgeAppearance = appearance + nav.navigationBar.tintColor = titleColor + + } +} diff --git a/Core/Core/Network/OfflineSyncManager.swift b/Core/Core/Network/OfflineSyncManager.swift index bb4d995f5..0c869cb64 100644 --- a/Core/Core/Network/OfflineSyncManager.swift +++ b/Core/Core/Network/OfflineSyncManager.swift @@ -23,14 +23,17 @@ public class OfflineSyncManager: OfflineSyncManagerProtocol { let interactor: OfflineSyncInteractorProtocol let connectivity: ConnectivityProtocol private var cancellables = Set() + private let tenantProvider: @Sendable () -> TenantProvider public init( persistence: CorePersistenceProtocol, interactor: OfflineSyncInteractorProtocol, - connectivity: ConnectivityProtocol + connectivity: ConnectivityProtocol, + tenantProvider: @escaping @Sendable () -> TenantProvider ) { self.persistence = persistence self.interactor = interactor + self.tenantProvider = tenantProvider self.connectivity = connectivity self.connectivity.internetReachableSubject.sink(receiveValue: { state in @@ -77,7 +80,7 @@ public class OfflineSyncManager: OfflineSyncManagerProtocol { await persistence.deleteProgress(for: progress.blockID) } if let config = Container.shared.resolve(ConfigProtocol.self), let cookies { - HTTPCookieStorage.shared.setCookies(cookies, for: config.baseURL, mainDocumentURL: nil) + HTTPCookieStorage.shared.setCookies(cookies, for: tenantProvider().baseURL, mainDocumentURL: nil) } } catch { debugLog("Error submitting offline progress: \(error.localizedDescription)") diff --git a/Core/Core/Network/RequestInterceptor.swift b/Core/Core/Network/RequestInterceptor.swift index d6bb9b8cd..e0fb0d1c4 100644 --- a/Core/Core/Network/RequestInterceptor.swift +++ b/Core/Core/Network/RequestInterceptor.swift @@ -17,10 +17,14 @@ final public class RequestInterceptor: Alamofire.RequestInterceptor { private let config: ConfigProtocol private let storage: CoreStorage + private let tenantProvider: @Sendable () -> TenantProvider - public init(config: ConfigProtocol, storage: CoreStorage) { + public init(config: ConfigProtocol, + storage: CoreStorage, + tenantProvider: @escaping @Sendable () -> TenantProvider) { self.config = config self.storage = storage + self.tenantProvider = tenantProvider } private let lock = NSLock() @@ -119,11 +123,11 @@ final public class RequestInterceptor: Alamofire.RequestInterceptor { mutableState.isRefreshing = true - let url = config.baseURL.appendingPathComponent("/oauth2/access_token") + let url = tenantProvider().baseURL.appendingPathComponent("/oauth2/access_token") let parameters: [String: Encodable & Sendable] = [ "grant_type": AuthConstants.GrantTypeRefreshToken, - "client_id": config.oAuthClientId, + "client_id": tenantProvider().oAuthClientId, "refresh_token": refreshToken, "token_type": config.tokenType.rawValue, "asymmetric_jwt": true diff --git a/Core/Core/View/Base/AlertView.swift b/Core/Core/View/Base/AlertView.swift index a2d3ecb1d..2955cf5c6 100644 --- a/Core/Core/View/Base/AlertView.swift +++ b/Core/Core/View/Base/AlertView.swift @@ -52,7 +52,6 @@ public struct AlertView: View { private let type: AlertViewType @Environment(\.isHorizontal) private var isHorizontal - public init( alertTitle: String, alertMessage: String, @@ -236,12 +235,13 @@ public struct AlertView: View { if nextSectionName != nil { UnitButtonView(type: .nextSection, action: { nextSectionTapped() }) .frame(maxWidth: 215) + } UnitButtonView(type: .custom(action), bgColor: .clear, action: { firstButtonTapped() }) .frame(maxWidth: 215) - + if let nextSectionName { Group { Text(CoreLocalization.Courseware.nextSectionDescriptionFirst) + @@ -281,12 +281,13 @@ public struct AlertView: View { if nextSectionName != nil { UnitButtonView(type: .nextSection, action: { nextSectionTapped() }) .frame(maxWidth: 215) + } UnitButtonView(type: .custom(action), bgColor: Theme.Colors.secondaryButtonBGColor, action: { firstButtonTapped() }) .frame(maxWidth: 215) - + if let nextSectionName { Group { Text(CoreLocalization.Courseware.nextSectionDescriptionFirst) + diff --git a/Core/Core/View/Base/AppReview/AppReviewView.swift b/Core/Core/View/Base/AppReview/AppReviewView.swift index efe5df5bd..611574642 100644 --- a/Core/Core/View/Base/AppReview/AppReviewView.swift +++ b/Core/Core/View/Base/AppReview/AppReviewView.swift @@ -161,7 +161,7 @@ struct AppReviewView_Previews: PreviewProvider { viewModel: AppReviewViewModel( config: ConfigMock(), storage: CoreStorageMock(), - analytics: CoreAnalyticsMock() + analytics: CoreAnalyticsMock(), tenantProvider: { TenantProviderMock() } ) ) } diff --git a/Core/Core/View/Base/AppReview/AppReviewViewModel.swift b/Core/Core/View/Base/AppReview/AppReviewViewModel.swift index 4b9f66c64..560086924 100644 --- a/Core/Core/View/Base/AppReview/AppReviewViewModel.swift +++ b/Core/Core/View/Base/AppReview/AppReviewViewModel.swift @@ -53,11 +53,18 @@ public class AppReviewViewModel: ObservableObject { private let config: ConfigProtocol var storage: CoreStorage private let analytics: CoreAnalytics + private let tenantProvider: () -> TenantProvider - public init(config: ConfigProtocol, storage: CoreStorage, analytics: CoreAnalytics) { + public init( + config: ConfigProtocol, + storage: CoreStorage, + analytics: CoreAnalytics, + tenantProvider: @escaping () -> TenantProvider + ) { self.config = config self.storage = storage self.analytics = analytics + self.tenantProvider = tenantProvider } public func shouldShowRatingView() -> Bool { @@ -121,7 +128,7 @@ public class AppReviewViewModel: ObservableObject { let feedbackDetails = "\n\n OS version: \(osVersion)\nApp version: \(appVersion)\nDevice model: \(deviceModel)" let mailUrl = with.composeURL( - to: config.feedbackEmail, + to: tenantProvider().feedbackEmail, subject: "Feedback", body: feedback + feedbackDetails, cc: nil, diff --git a/Core/Core/View/Base/AppReview/Elements/AppReviewButton.swift b/Core/Core/View/Base/AppReview/Elements/AppReviewButton.swift index 78486c676..0ff6c2d43 100644 --- a/Core/Core/View/Base/AppReview/Elements/AppReviewButton.swift +++ b/Core/Core/View/Base/AppReview/Elements/AppReviewButton.swift @@ -34,7 +34,9 @@ struct AppReviewButton: View { : CoreLocalization.Review.Button.rateUs ) ) - .foregroundColor(isActive ? Theme.Colors.primaryButtonTextColor : Color.black.opacity(0.6)) + .foregroundColor(isActive ? + Theme.Colors.primaryButtonTextColor + : Color.black.opacity(0.6)) .font(Theme.Fonts.labelLarge) .padding(3) diff --git a/Core/Core/View/Base/CheckBoxView.swift b/Core/Core/View/Base/CheckBoxView.swift index 267d21463..1545b37c7 100644 --- a/Core/Core/View/Base/CheckBoxView.swift +++ b/Core/Core/View/Base/CheckBoxView.swift @@ -14,7 +14,7 @@ public struct CheckBoxView: View { private var text: String private var font: Font private let color: Color - + public init( checked: Binding, text: String, diff --git a/Core/Core/View/Base/DownloadView.swift b/Core/Core/View/Base/DownloadView.swift index f0580f468..bc51d61e9 100644 --- a/Core/Core/View/Base/DownloadView.swift +++ b/Core/Core/View/Base/DownloadView.swift @@ -31,6 +31,7 @@ public struct DownloadAvailableView: View { } public struct DownloadProgressView: View { + public init () { } diff --git a/Core/Core/View/Base/FullScreenErrorView/FullScreenErrorView.swift b/Core/Core/View/Base/FullScreenErrorView/FullScreenErrorView.swift index 4e17c0626..910dcb2de 100644 --- a/Core/Core/View/Base/FullScreenErrorView/FullScreenErrorView.swift +++ b/Core/Core/View/Base/FullScreenErrorView/FullScreenErrorView.swift @@ -16,7 +16,6 @@ public struct FullScreenErrorView: View { case generic case noContent(_ message: String, image: SwiftUI.Image) } - private let errorType: ErrorType private var action: () -> Void = {} @@ -91,6 +90,7 @@ public struct FullScreenErrorView: View { self.action() } ) + } Spacer() } diff --git a/Core/Core/View/Base/FullScreenProgressView.swift b/Core/Core/View/Base/FullScreenProgressView.swift index 8a49dc0f6..377cb0eef 100644 --- a/Core/Core/View/Base/FullScreenProgressView.swift +++ b/Core/Core/View/Base/FullScreenProgressView.swift @@ -11,7 +11,7 @@ import Theme public struct FullScreenProgressView: View { @Environment(\.dismiss) private var dismiss - + public init() {} public var body: some View { diff --git a/Core/Core/View/Base/OfflineSnackBarView.swift b/Core/Core/View/Base/OfflineSnackBarView.swift index c26a577ee..791ad19af 100644 --- a/Core/Core/View/Base/OfflineSnackBarView.swift +++ b/Core/Core/View/Base/OfflineSnackBarView.swift @@ -80,5 +80,6 @@ public struct OfflineSnackBarView: View { struct OfflineSnackBarView_Previews: PreviewProvider { static var previews: some View { OfflineSnackBarView(connectivity: Connectivity(), reloadAction: {}) + .environmentObject(ThemeManager.shared) } } diff --git a/Core/Core/View/Base/ProgressBar.swift b/Core/Core/View/Base/ProgressBar.swift index b3be390e7..585382f81 100644 --- a/Core/Core/View/Base/ProgressBar.swift +++ b/Core/Core/View/Base/ProgressBar.swift @@ -21,14 +21,18 @@ public struct ProgressBar: View { .repeatForever(autoreverses: false) } - private let gradient = AngularGradient( - gradient: Gradient(colors: [ - Theme.Colors.accentColor.opacity(0.7), - Theme.Colors.accentColor.opacity(0.35), - Theme.Colors.accentColor.opacity(0.01)]), - center: .center, - startAngle: .degrees(270), - endAngle: .degrees(0)) + private var gradient: AngularGradient { + AngularGradient( + gradient: Gradient(colors: [ + Theme.Colors.accentColor.opacity(0.7), + Theme.Colors.accentColor.opacity(0.35), + Theme.Colors.accentColor.opacity(0.01) + ]), + center: .center, + startAngle: .degrees(270), + endAngle: .degrees(0) + ) + } public init(size: CGFloat = 50, lineWidth: CGFloat = 10) { self.size = size diff --git a/Core/Core/View/Base/UnitButtonView.swift b/Core/Core/View/Base/UnitButtonView.swift index b89106145..b64a5f5fb 100644 --- a/Core/Core/View/Base/UnitButtonView.swift +++ b/Core/Core/View/Base/UnitButtonView.swift @@ -139,9 +139,12 @@ public struct UnitButtonView: View { case .reload, .custom: VStack(alignment: .center) { Text(type.stringValue()) - .foregroundColor(bgColor == nil ? .white : Theme.Colors.secondaryButtonTextColor) + .foregroundColor(bgColor == nil + ? .white + : Theme.Colors.secondaryButtonTextColor) .font(Theme.Fonts.labelLarge) - }.padding(.horizontal, 16) + } + .padding(.horizontal, 16) case .continueLesson, .nextSection: HStack { Text(type.stringValue()) diff --git a/Core/Core/View/Base/VideoDownloadQualityView.swift b/Core/Core/View/Base/VideoDownloadQualityView.swift index 2fd29240a..a41bd630a 100644 --- a/Core/Core/View/Base/VideoDownloadQualityView.swift +++ b/Core/Core/View/Base/VideoDownloadQualityView.swift @@ -36,7 +36,7 @@ public struct VideoDownloadQualityView: View { private var router: BaseRouter private var isModal: Bool @Environment(\.isHorizontal) private var isHorizontal - + public init( downloadQuality: DownloadQuality, didSelect: ((DownloadQuality) -> Void)?, @@ -151,7 +151,7 @@ public struct SettingsCell: View { private var title: String private var description: String? - + public init(title: String, description: String?) { self.title = title self.description = description diff --git a/Core/Core/View/Base/WebBrowser.swift b/Core/Core/View/Base/WebBrowser.swift index cd61dcdb6..96ffbe6c0 100644 --- a/Core/Core/View/Base/WebBrowser.swift +++ b/Core/Core/View/Base/WebBrowser.swift @@ -13,7 +13,7 @@ public struct WebBrowser: View { @State private var isLoading: Bool = true @Environment(\.presentationMode) var presentationMode - + private var url: String private var pageTitle: String private var showProgress: Bool @@ -73,6 +73,7 @@ public struct WebBrowser: View { connectivity: connectivity ) .accessibilityIdentifier("web_browser") + } .padding(.top, proxy.safeAreaInsets.top) .padding(.bottom, proxy.safeAreaInsets.bottom) diff --git a/Core/Core/View/Base/WebUnitView.swift b/Core/Core/View/Base/WebUnitView.swift index bb143560f..da974dc7d 100644 --- a/Core/Core/View/Base/WebUnitView.swift +++ b/Core/Core/View/Base/WebUnitView.swift @@ -81,7 +81,7 @@ public struct WebUnitView: View { WebView( viewModel: .init( url: url, - baseURL: viewModel.config.baseURL.absoluteString, + baseURL: viewModel.baseURLString, openFile: { file in self.fileUrl = file }, @@ -104,6 +104,7 @@ public struct WebUnitView: View { width: reader.size.width, height: reader.size.height ) + } } .scrollDisabled(true) diff --git a/Core/Core/View/Base/WebUnitViewModel.swift b/Core/Core/View/Base/WebUnitViewModel.swift index 693a2e4b6..da2ba76e4 100644 --- a/Core/Core/View/Base/WebUnitViewModel.swift +++ b/Core/Core/View/Base/WebUnitViewModel.swift @@ -13,6 +13,7 @@ public final class WebUnitViewModel: ObservableObject, WebviewCookiesUpdateProto public let authInteractor: AuthInteractorProtocol let config: ConfigProtocol let syncManager: OfflineSyncManagerProtocol + private let tenantProvider: () -> TenantProvider @Published public var updatingCookies: Bool = false @Published public var cookiesReady: Bool = false @@ -30,10 +31,17 @@ public final class WebUnitViewModel: ObservableObject, WebviewCookiesUpdateProto public init( authInteractor: AuthInteractorProtocol, config: ConfigProtocol, - syncManager: OfflineSyncManagerProtocol + syncManager: OfflineSyncManagerProtocol, + tenantProvider: @escaping () -> TenantProvider ) { self.authInteractor = authInteractor self.config = config self.syncManager = syncManager + self.tenantProvider = tenantProvider + } + + /// Expose current tenant baseURL + public var baseURLString: String { + tenantProvider().baseURL.absoluteString } } diff --git a/Course/Course.xcodeproj/project.pbxproj b/Course/Course.xcodeproj/project.pbxproj index 932017dc8..ee9e17144 100644 --- a/Course/Course.xcodeproj/project.pbxproj +++ b/Course/Course.xcodeproj/project.pbxproj @@ -241,6 +241,7 @@ 0766DFCD299AB26D00EBEF6A /* EncodedVideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncodedVideoPlayer.swift; sourceTree = ""; }; 0766DFCF299AB29000EBEF6A /* PlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerViewController.swift; sourceTree = ""; }; 07DE59852BECB868001CBFBC /* CourseAnalytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseAnalytics.swift; sourceTree = ""; }; + 28A8CBB5DC32735E777E6CDF /* Pods-App-Course-CourseTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course-CourseTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; 2A444220A08C5035164B071F /* Pods-App-Course-CourseTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course-CourseTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests.releasedev.xcconfig"; sourceTree = ""; }; 3A55620C6018088BFF77F9AE /* Pods-App-CourseDetails.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-CourseDetails.debug.xcconfig"; path = "Target Support Files/Pods-App-CourseDetails/Pods-App-CourseDetails.debug.xcconfig"; sourceTree = ""; }; 3D506212980347A9D5A70E20 /* Pods-App-Course.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Course/Pods-App-Course.debugstage.xcconfig"; sourceTree = ""; }; @@ -250,6 +251,7 @@ 50E59D2B81E12610964282C5 /* Pods_App_Course_CourseTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Course_CourseTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51A3A7BA0FC6386531BE678A /* Pods-App-CourseDetails.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-CourseDetails.debugdev.xcconfig"; path = "Target Support Files/Pods-App-CourseDetails/Pods-App-CourseDetails.debugdev.xcconfig"; sourceTree = ""; }; 600A464AEDA7BEFEC1A7FE99 /* Pods-App-Course-CourseTests.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course-CourseTests.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests.debugdev.xcconfig"; sourceTree = ""; }; + 60D9657A1C5D9AC2B4BC5921 /* Pods-App-Course.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Course/Pods-App-Course.openedxmultitenants.xcconfig"; sourceTree = ""; }; 69A261790A0B4C724CCFA4F2 /* Pods-App-CourseDetails.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-CourseDetails.release.xcconfig"; path = "Target Support Files/Pods-App-CourseDetails/Pods-App-CourseDetails.release.xcconfig"; sourceTree = ""; }; 831B08139890634968EDD44D /* Pods-App-Course-CourseTests.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course-CourseTests.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests.debugstage.xcconfig"; sourceTree = ""; }; 975F475D2B6151FD00E5B031 /* CourseDatesMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDatesMock.swift; sourceTree = ""; }; @@ -262,6 +264,7 @@ A47C63D9EB0D866F303D4588 /* Pods-App-Course.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Course/Pods-App-Course.releasestage.xcconfig"; sourceTree = ""; }; ADC2A1B8183A674705F5F7E2 /* Pods-App-Course.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course.debug.xcconfig"; path = "Target Support Files/Pods-App-Course/Pods-App-Course.debug.xcconfig"; sourceTree = ""; }; B196A14555D0E006995A5683 /* Pods-App-CourseDetails.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-CourseDetails.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-CourseDetails/Pods-App-CourseDetails.releaseprod.xcconfig"; sourceTree = ""; }; + B7101E605174B3087BC5CF5A /* Pods-App-Course.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Course/Pods-App-Course.debugprodtenants.xcconfig"; sourceTree = ""; }; BA58CF5C2B3D804D005B102E /* CourseStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseStorage.swift; sourceTree = ""; }; BA58CF602B471041005B102E /* VideoDownloadQualityBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDownloadQualityBarView.swift; sourceTree = ""; }; BA58CF632B471363005B102E /* VideoDownloadQualityContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDownloadQualityContainerView.swift; sourceTree = ""; }; @@ -310,6 +313,7 @@ DB7D6EAB2ADFCAC40036BB13 /* CourseDatesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseDatesView.swift; sourceTree = ""; }; DB7D6EAD2ADFCB4A0036BB13 /* CourseDatesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDatesViewModel.swift; sourceTree = ""; }; DBE05972CB5115D4535C6B8A /* Pods-App-Course-CourseTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course-CourseTests.debug.xcconfig"; path = "Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests.debug.xcconfig"; sourceTree = ""; }; + E23510D911DE262795902A07 /* Pods-App-Course-CourseTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course-CourseTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests.debugprodtenants.xcconfig"; sourceTree = ""; }; E5E795BD160CDA7D9C120DE6 /* Pods_App_Course.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Course.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E6BDAE887ED8A46860B3F6D3 /* Pods-App-Course-CourseTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course-CourseTests.release.xcconfig"; path = "Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests.release.xcconfig"; sourceTree = ""; }; E954A304FDC0409BEC34C125 /* Pods-App-Course.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Course.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Course/Pods-App-Course.debugprod.xcconfig"; sourceTree = ""; }; @@ -824,6 +828,10 @@ A47C63D9EB0D866F303D4588 /* Pods-App-Course.releasestage.xcconfig */, 831B08139890634968EDD44D /* Pods-App-Course-CourseTests.debugstage.xcconfig */, EBB67646EDD08315BA7B3DC5 /* Pods-App-Course-CourseTests.releasestage.xcconfig */, + 60D9657A1C5D9AC2B4BC5921 /* Pods-App-Course.openedxmultitenants.xcconfig */, + 28A8CBB5DC32735E777E6CDF /* Pods-App-Course-CourseTests.openedxmultitenants.xcconfig */, + B7101E605174B3087BC5CF5A /* Pods-App-Course.debugprodtenants.xcconfig */, + E23510D911DE262795902A07 /* Pods-App-Course-CourseTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -984,14 +992,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App-Course-CourseTests/Pods-App-Course-CourseTests-resources.sh\"\n"; @@ -2182,6 +2186,249 @@ }; name = ReleaseStage; }; + 995886BE2E6448D90065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886BF2E6448D90065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B7101E605174B3087BC5CF5A /* Pods-App-Course.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.CourseDetails; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886C02E6448D90065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E23510D911DE262795902A07 /* Pods-App-Course-CourseTests.debugprodtenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.CourseTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1EC2E60377F0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1ED2E60377F0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 60D9657A1C5D9AC2B4BC5921 /* Pods-App-Course.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.CourseDetails; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1EE2E60377F0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 28A8CBB5DC32735E777E6CDF /* Pods-App-Course-CourseTests.openedxmultitenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.CourseTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2189,11 +2436,13 @@ isa = XCConfigurationList; buildConfigurations = ( 023812EB297AC8EB0087098F /* Debug */, + 9972D1EE2E60377F0020CFBD /* OpenEdXMultiTenants */, 023812EC297AC8EB0087098F /* DebugProd */, 02DD1CB929E80D4200F35DCE /* DebugStage */, 023812ED297AC8EB0087098F /* DebugDev */, 023812EE297AC8EB0087098F /* Release */, 023812EF297AC8EB0087098F /* ReleaseProd */, + 995886C02E6448D90065D132 /* DebugProdTenants */, 02DD1CBC29E80D4700F35DCE /* ReleaseStage */, 023812F0297AC8EB0087098F /* ReleaseDev */, ); @@ -2204,11 +2453,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0289F8F328E1C3510064F8F3 /* Debug */, + 9972D1EC2E60377F0020CFBD /* OpenEdXMultiTenants */, 0289F8FA28E1C37B0064F8F3 /* DebugProd */, 02DD1CB729E80D4200F35DCE /* DebugStage */, 0289F8F828E1C3750064F8F3 /* DebugDev */, 0289F8F428E1C3510064F8F3 /* Release */, 0289F8FE28E1C3880064F8F3 /* ReleaseProd */, + 995886BE2E6448D90065D132 /* DebugProdTenants */, 02DD1CBA29E80D4700F35DCE /* ReleaseStage */, 0289F8FC28E1C3830064F8F3 /* ReleaseDev */, ); @@ -2219,11 +2470,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0289F8F628E1C3510064F8F3 /* Debug */, + 9972D1ED2E60377F0020CFBD /* OpenEdXMultiTenants */, 0289F8FB28E1C37B0064F8F3 /* DebugProd */, 02DD1CB829E80D4200F35DCE /* DebugStage */, 0289F8F928E1C3750064F8F3 /* DebugDev */, 0289F8F728E1C3510064F8F3 /* Release */, 0289F8FF28E1C3880064F8F3 /* ReleaseProd */, + 995886BF2E6448D90065D132 /* DebugProdTenants */, 02DD1CBB29E80D4700F35DCE /* ReleaseStage */, 0289F8FD28E1C3830064F8F3 /* ReleaseDev */, ); diff --git a/Course/Course/Data/CourseRepository.swift b/Course/Course/Data/CourseRepository.swift index 4e0432e2b..5c5e814e5 100644 --- a/Course/Course/Data/CourseRepository.swift +++ b/Course/Course/Data/CourseRepository.swift @@ -33,17 +33,20 @@ public actor CourseRepository: CourseRepositoryProtocol { private let coreStorage: CoreStorage private let config: ConfigProtocol private let persistence: CoursePersistenceProtocol + private let tenantProvider: @Sendable () -> any TenantProvider public init( api: API, coreStorage: CoreStorage, config: ConfigProtocol, - persistence: CoursePersistenceProtocol + persistence: CoursePersistenceProtocol, + tenantProvider: @escaping @Sendable () -> any TenantProvider ) { self.api = api self.coreStorage = coreStorage self.config = config self.persistence = persistence + self.tenantProvider = tenantProvider } public func getCourseBlocks(courseID: String) async throws -> CourseStructure { @@ -230,7 +233,7 @@ public actor CourseRepository: CourseRepositoryProtocol { let block = blocks.first(where: {$0.id == id })! let subtitles = block.userViewData?.transcripts?.map { let url = $0.value - .replacingOccurrences(of: config.baseURL.absoluteString, with: "") + .replacingOccurrences(of: tenantProvider().baseURL.absoluteString, with: "") .replacingOccurrences(of: "?lang=\($0.key)", with: "") return SubtitleUrl(language: $0.key, url: url) } @@ -241,7 +244,8 @@ public actor CourseRepository: CourseRepositoryProtocol { let fileUrl = offlineData.fileUrl, let lastModified = offlineData.lastModified, let fileSize = offlineData.fileSize { - let fullUrl = fileUrl.starts(with: "http") ? fileUrl : config.baseURL.absoluteString + fileUrl + let fullUrl = fileUrl.starts(with: "http") ? fileUrl + : tenantProvider().baseURL.absoluteString + fileUrl offlineDownload = OfflineDownload( fileUrl: fullUrl, lastModified: lastModified, diff --git a/Course/Course/Presentation/Container/CourseContainerView.swift b/Course/Course/Presentation/Container/CourseContainerView.swift index 73ea05091..f85fd0d1a 100644 --- a/Course/Course/Presentation/Container/CourseContainerView.swift +++ b/Course/Course/Presentation/Container/CourseContainerView.swift @@ -242,6 +242,7 @@ public struct CourseContainerView: View { } .tag(tab) .accentColor(Theme.Colors.accentColor) + case .dates: CourseDatesView( courseID: courseID, @@ -256,6 +257,7 @@ public struct CourseContainerView: View { } .tag(tab) .accentColor(Theme.Colors.accentColor) + case .offline: OfflineView( courseID: courseID, @@ -270,6 +272,7 @@ public struct CourseContainerView: View { } .tag(tab) .accentColor(Theme.Colors.accentColor) + case .discussion: DiscussionTopicsView( courseID: courseID, @@ -286,6 +289,7 @@ public struct CourseContainerView: View { } .tag(tab) .accentColor(Theme.Colors.accentColor) + case .handounds: HandoutsView( courseID: courseID, @@ -300,6 +304,7 @@ public struct CourseContainerView: View { } .tag(tab) .accentColor(Theme.Colors.accentColor) + } } } @@ -392,7 +397,10 @@ public struct CourseContainerView: View { enrollmentEnd: nil, lastVisitedBlockID: nil, coreAnalytics: CoreAnalyticsMock(), - courseHelper: CourseDownloadHelper(courseStructure: nil, manager: DownloadManagerMock()) + courseHelper: CourseDownloadHelper( + courseStructure: nil, + manager: DownloadManagerMock()), + tenantProvider: { TenantProviderMock() } ), courseDatesViewModel: CourseDatesViewModel( interactor: CourseInteractor.mock, diff --git a/Course/Course/Presentation/Container/CourseContainerViewModel.swift b/Course/Course/Presentation/Container/CourseContainerViewModel.swift index 092079627..1160831a6 100644 --- a/Course/Course/Presentation/Container/CourseContainerViewModel.swift +++ b/Course/Course/Presentation/Container/CourseContainerViewModel.swift @@ -106,6 +106,7 @@ public final class CourseContainerViewModel: BaseCourseViewModel { let router: CourseRouter let config: ConfigProtocol let connectivity: ConnectivityProtocol + let tenantProvider: @Sendable () -> any TenantProvider let isActive: Bool? let courseStart: Date? @@ -143,7 +144,8 @@ public final class CourseContainerViewModel: BaseCourseViewModel { lastVisitedBlockID: String?, coreAnalytics: CoreAnalytics, selection: CourseTab = CourseTab.course, - courseHelper: CourseDownloadHelperProtocol + courseHelper: CourseDownloadHelperProtocol, + tenantProvider: @escaping @Sendable () -> any TenantProvider ) { self.interactor = interactor self.authInteractor = authInteractor @@ -164,6 +166,7 @@ public final class CourseContainerViewModel: BaseCourseViewModel { self.selection = selection.rawValue self.courseHelper = courseHelper self.courseHelper.videoQuality = storage.userSettings?.downloadQuality ?? .auto + self.tenantProvider = tenantProvider super.init(manager: manager) addObservers() } diff --git a/Course/Course/Presentation/Dates/CourseDatesView.swift b/Course/Course/Presentation/Dates/CourseDatesView.swift index 192b7c2a9..f31a1bc06 100644 --- a/Course/Course/Presentation/Dates/CourseDatesView.swift +++ b/Course/Course/Presentation/Dates/CourseDatesView.swift @@ -55,6 +55,7 @@ public struct CourseDatesView: View { courseID: courseID ) .padding(.top, 10) + } else { GeometryReader { proxy in VStack { @@ -146,6 +147,7 @@ public struct CourseDatesView: View { ) { viewModel.resetEventState() } + } } } diff --git a/Course/Course/Presentation/Dates/DatesStatusInfoView.swift b/Course/Course/Presentation/Dates/DatesStatusInfoView.swift index b193dae22..efc94ca9f 100644 --- a/Course/Course/Presentation/Dates/DatesStatusInfoView.swift +++ b/Course/Course/Presentation/Dates/DatesStatusInfoView.swift @@ -23,7 +23,7 @@ struct DatesStatusInfoView: View { var screen: DatesStatusInfoScreen @State private var isLoading = false - + var body: some View { VStack(alignment: .leading, spacing: 8) { let header = datesBannerInfo.status?.header ?? "" @@ -73,6 +73,7 @@ struct DatesStatusInfoView: View { } .padding([.leading, .trailing], 16) .disabled(isLoading) + } Spacer() } diff --git a/Course/Course/Presentation/Handouts/HandoutsUpdatesDetailView.swift b/Course/Course/Presentation/Handouts/HandoutsUpdatesDetailView.swift index c4c5923c7..af8ab6769 100644 --- a/Course/Course/Presentation/Handouts/HandoutsUpdatesDetailView.swift +++ b/Course/Course/Presentation/Handouts/HandoutsUpdatesDetailView.swift @@ -112,6 +112,12 @@ public struct HandoutsUpdatesDetailView: View { guard UIApplication.shared.applicationState == .active else { return } updateColorScheme() } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } } private var webViewHtml: some View { diff --git a/Course/Course/Presentation/Handouts/HandoutsView.swift b/Course/Course/Presentation/Handouts/HandoutsView.swift index d04be11af..eb0bf7b21 100644 --- a/Course/Course/Presentation/Handouts/HandoutsView.swift +++ b/Course/Course/Presentation/Handouts/HandoutsView.swift @@ -66,6 +66,7 @@ struct HandoutsView: View { courseID: courseID ) }) + Divider() .frame(height: 1) .overlay(Theme.Colors.cardViewStroke) @@ -84,6 +85,7 @@ struct HandoutsView: View { courseID: courseID ) }) + }.padding(.horizontal, 32) Spacer(minLength: 84) } @@ -100,6 +102,7 @@ struct HandoutsView: View { } } ) + .environmentObject(ThemeManager.shared) } .onFirstAppear { diff --git a/Course/Course/Presentation/Offline/OfflineView.swift b/Course/Course/Presentation/Offline/OfflineView.swift index 9b5cee5ed..1716e8a6d 100644 --- a/Course/Course/Presentation/Offline/OfflineView.swift +++ b/Course/Course/Presentation/Offline/OfflineView.swift @@ -259,7 +259,10 @@ struct OfflineView: View { enrollmentEnd: nil, lastVisitedBlockID: nil, coreAnalytics: CoreAnalyticsMock(), - courseHelper: CourseDownloadHelper(courseStructure: nil, manager: DownloadManagerMock()) + courseHelper: CourseDownloadHelper( + courseStructure: nil, + manager: DownloadManagerMock()), + tenantProvider: { TenantProviderMock() } ) OfflineView( diff --git a/Course/Course/Presentation/Offline/Subviews/LargestDownloadsView.swift b/Course/Course/Presentation/Offline/Subviews/LargestDownloadsView.swift index 7aa0930d7..4b8de3746 100644 --- a/Course/Course/Presentation/Offline/Subviews/LargestDownloadsView.swift +++ b/Course/Course/Presentation/Offline/Subviews/LargestDownloadsView.swift @@ -103,7 +103,10 @@ struct LargestDownloadsView_Previews: PreviewProvider { enrollmentEnd: nil, lastVisitedBlockID: nil, coreAnalytics: CoreAnalyticsMock(), - courseHelper: CourseDownloadHelper(courseStructure: nil, manager: DownloadManagerMock()) + courseHelper: CourseDownloadHelper( + courseStructure: nil, + manager: DownloadManagerMock()), + tenantProvider: { TenantProviderMock() } ) LargestDownloadsView(viewModel: vm) diff --git a/Course/Course/Presentation/Outline/ContinueWithView.swift b/Course/Course/Presentation/Outline/ContinueWithView.swift index 09b5319ef..3d1e07d2b 100644 --- a/Course/Course/Presentation/Outline/ContinueWithView.swift +++ b/Course/Course/Presentation/Outline/ContinueWithView.swift @@ -20,7 +20,7 @@ struct ContinueWithView: View { private let data: ContinueWith private let action: () -> Void private let courseContinueUnit: CourseVertical - + init(data: ContinueWith, courseContinueUnit: CourseVertical, action: @escaping () -> Void) { self.data = data self.action = action @@ -36,14 +36,14 @@ struct ContinueWithView: View { .foregroundColor(.white) .multilineTextAlignment(.leading) .lineLimit(2) - + Spacer() - + HStack(spacing: 8) { Text(CoreLocalization.Courseware.continue) .font(Theme.Fonts.labelLarge) .foregroundColor(.white) - + CoreAssets.arrowLeft.swiftUIImage .renderingMode(.template) .foregroundColor(.white) @@ -93,10 +93,10 @@ struct ContinueWithView: View { encodedVideo: nil, multiDevice: false, offlineDownload: nil - + ) ] - + ContinueWithView( data: ContinueWith( chapterIndex: 0, diff --git a/Course/Course/Presentation/Outline/CourseOutlineView.swift b/Course/Course/Presentation/Outline/CourseOutlineView.swift index 2c2c8565e..ca752a035 100644 --- a/Course/Course/Presentation/Outline/CourseOutlineView.swift +++ b/Course/Course/Presentation/Outline/CourseOutlineView.swift @@ -165,6 +165,7 @@ public struct CourseOutlineView: View { } } ) + .environmentObject(ThemeManager.shared) // MARK: - Error Alert if viewModel.showError { @@ -309,7 +310,7 @@ public struct CourseOutlineView: View { // MARK: - Course Banner if let banner = viewModel.courseStructure?.media.image.raw .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) { - KFImage(URL(string: viewModel.config.baseURL.absoluteString + banner)) + KFImage(URL(string: viewModel.tenantProvider().baseURL.absoluteString + banner)) .onFailureImage(CoreAssets.noCourseImage.image) .resizable() .aspectRatio(contentMode: .fill) @@ -344,7 +345,10 @@ struct CourseOutlineView_Previews: PreviewProvider { enrollmentEnd: nil, lastVisitedBlockID: nil, coreAnalytics: CoreAnalyticsMock(), - courseHelper: CourseDownloadHelper(courseStructure: nil, manager: DownloadManagerMock()) + courseHelper: CourseDownloadHelper(courseStructure: nil, manager: DownloadManagerMock()), + tenantProvider: { + TenantProviderMock() + } ) Task { await withTaskGroup(of: Void.self) { group in diff --git a/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift b/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift index de23e0277..4624bef46 100644 --- a/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift +++ b/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift @@ -190,7 +190,8 @@ struct CourseVerticalView_Previews: PreviewProvider { title: "Course title", courseName: "CourseName", courseID: "1", - viewModel: viewModel + viewModel: viewModel, + themeManager: ThemeManager.shared ) .preferredColorScheme(.light) .previewDisplayName("CourseVerticalView Light") @@ -199,7 +200,8 @@ struct CourseVerticalView_Previews: PreviewProvider { title: "Course title", courseName: "CourseName", courseID: "1", - viewModel: viewModel + viewModel: viewModel, + themeManager: ThemeManager.shared ) .preferredColorScheme(.dark) .previewDisplayName("CourseVerticalView Dark") diff --git a/Course/Course/Presentation/Subviews/CourseHeaderView.swift b/Course/Course/Presentation/Subviews/CourseHeaderView.swift index 3f604e7df..d16bfa18b 100644 --- a/Course/Course/Presentation/Subviews/CourseHeaderView.swift +++ b/Course/Course/Presentation/Subviews/CourseHeaderView.swift @@ -166,7 +166,7 @@ struct CourseHeaderView: View { if path.contains("http://") || path.contains("https://") { return URL(string: path) } - return URL(string: viewModel.config.baseURL.absoluteString + path) + return URL(string: viewModel.tenantProvider().baseURL.absoluteString + path) } private func courseMenuBar(containerWidth: CGFloat) -> some View { diff --git a/Course/Course/Presentation/Subviews/DatesSuccessView/DatesSuccessView.swift b/Course/Course/Presentation/Subviews/DatesSuccessView/DatesSuccessView.swift index 3adfe607c..fdd2f8121 100644 --- a/Course/Course/Presentation/Subviews/DatesSuccessView/DatesSuccessView.swift +++ b/Course/Course/Presentation/Subviews/DatesSuccessView/DatesSuccessView.swift @@ -23,7 +23,6 @@ public struct DatesSuccessView: View { var courseContainerViewModel: CourseContainerViewModel? var action: () -> Void = {} var dismissAction: () -> Void = {} - @State private var dismiss: Bool = false init ( diff --git a/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityBarView.swift b/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityBarView.swift index 8617dcb58..934e9c570 100644 --- a/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityBarView.swift +++ b/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityBarView.swift @@ -14,7 +14,7 @@ struct VideoDownloadQualityBarView: View { private var downloadQuality: DownloadQuality private var onTap: (() -> Void)? - + init(downloadQuality: DownloadQuality, onTap: (() -> Void)? = nil) { self.downloadQuality = downloadQuality self.onTap = onTap diff --git a/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityContainerView.swift b/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityContainerView.swift index 79007c35e..55633c457 100644 --- a/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityContainerView.swift +++ b/Course/Course/Presentation/Subviews/VideoDownloadQualityBarView/VideoDownloadQualityContainerView.swift @@ -12,7 +12,7 @@ import Theme struct VideoDownloadQualityContainerView: View { @Environment(\.dismiss) private var dismiss - + private var downloadQuality: DownloadQuality private var didSelect: ((DownloadQuality) -> Void)? private let analytics: CoreAnalytics diff --git a/Course/Course/Presentation/Unit/CourseNavigationView.swift b/Course/Course/Presentation/Unit/CourseNavigationView.swift index 4257f18e9..8c733edc2 100644 --- a/Course/Course/Presentation/Unit/CourseNavigationView.swift +++ b/Course/Course/Presentation/Unit/CourseNavigationView.swift @@ -8,6 +8,7 @@ import SwiftUI import Core import Combine +import Theme struct CourseNavigationView: View { @@ -55,6 +56,7 @@ struct CourseNavigationView: View { viewModel.select(move: .next) } ) + } private var nextButton: some View { @@ -66,6 +68,7 @@ struct CourseNavigationView: View { viewModel.select(move: .next) } ) + } private var prevButton: some View { @@ -77,6 +80,7 @@ struct CourseNavigationView: View { viewModel.select(move: .previous) } ) + } private var lastButton: some View { @@ -142,6 +146,7 @@ struct CourseNavigationView: View { ) } ) + } } diff --git a/Course/Course/Presentation/Unit/CourseUnitView.swift b/Course/Course/Presentation/Unit/CourseUnitView.swift index b635922e5..721ba9c69 100644 --- a/Course/Course/Presentation/Unit/CourseUnitView.swift +++ b/Course/Course/Presentation/Unit/CourseUnitView.swift @@ -139,6 +139,12 @@ public struct CourseUnitView: View { showDiscussion = viewModel.selectedLesson().type == .discussion } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .navigationBarHidden(true) .navigationBarBackButtonHidden(true) .navigationTitle("") @@ -217,6 +223,7 @@ public struct CourseUnitView: View { index: index, reader: reader ) + // MARK: Encoded Video case let .video(encodedUrl, blockID): videoView( @@ -237,6 +244,7 @@ public struct CourseUnitView: View { index: index, reader: reader ) + // MARK: Unknown case .unknown(let url): unknownView( @@ -563,6 +571,7 @@ public struct CourseUnitView: View { viewModel: viewModel, playerStateSubject: playerStateSubject ) + if isHorizontal { Spacer() } diff --git a/Course/Course/Presentation/Unit/Subviews/LessonLineProgressView.swift b/Course/Course/Presentation/Unit/Subviews/LessonLineProgressView.swift index 8233051d0..dbb767d2d 100644 --- a/Course/Course/Presentation/Unit/Subviews/LessonLineProgressView.swift +++ b/Course/Course/Presentation/Unit/Subviews/LessonLineProgressView.swift @@ -12,7 +12,7 @@ struct LessonLineProgressView: View { @ObservedObject var viewModel: CourseUnitViewModel @Environment(\.isHorizontal) private var isHorizontal - + init(viewModel: CourseUnitViewModel) { self.viewModel = viewModel } diff --git a/Course/Course/Presentation/Unit/Subviews/YouTubeView.swift b/Course/Course/Presentation/Unit/Subviews/YouTubeView.swift index 3be341524..66e837312 100644 --- a/Course/Course/Presentation/Unit/Subviews/YouTubeView.swift +++ b/Course/Course/Presentation/Unit/Subviews/YouTubeView.swift @@ -20,7 +20,7 @@ struct YouTubeView: View { let playerStateSubject: CurrentValueSubject let languages: [SubtitleUrl] let isOnScreen: Bool - + var body: some View { let vm = Container.shared.resolve( YouTubeVideoPlayerViewModel.self, diff --git a/Dashboard/Dashboard.xcodeproj/project.pbxproj b/Dashboard/Dashboard.xcodeproj/project.pbxproj index dc5f31b57..dd53aa54a 100644 --- a/Dashboard/Dashboard.xcodeproj/project.pbxproj +++ b/Dashboard/Dashboard.xcodeproj/project.pbxproj @@ -88,14 +88,18 @@ 2AC36B6C48F0512E8ECEC9BC /* Pods-App-Dashboard-DashboardTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard-DashboardTests.debug.xcconfig"; path = "Target Support Files/Pods-App-Dashboard-DashboardTests/Pods-App-Dashboard-DashboardTests.debug.xcconfig"; sourceTree = ""; }; 3E3C0ABBCE5A2853AD231815 /* Pods-App-Dashboard.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.debugstage.xcconfig"; sourceTree = ""; }; 4BC4CB3BD3F2BC4E453AC9B8 /* Pods-App-Dashboard.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.debugprod.xcconfig"; sourceTree = ""; }; + 58318522C8BCB420C91906FF /* Pods-App-Dashboard.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.openedxmultitenants.xcconfig"; sourceTree = ""; }; + 62182E1F063E9CE38CA426DD /* Pods-App-Dashboard.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.debugprodtenants.xcconfig"; sourceTree = ""; }; 65CD5AB152F3DEC88D48AE2D /* Pods-App-Dashboard.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.debugdev.xcconfig"; sourceTree = ""; }; 6BA3D1943CAB859ECDC95C76 /* Pods-App-Dashboard.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.releasedev.xcconfig"; sourceTree = ""; }; 89D6F05AC9854DBBAB091D9C /* Pods-App-Dashboard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.release.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.release.xcconfig"; sourceTree = ""; }; + 97B43AAB00F57C5433DE9D3A /* Pods-App-Dashboard-DashboardTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard-DashboardTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Dashboard-DashboardTests/Pods-App-Dashboard-DashboardTests.debugprodtenants.xcconfig"; sourceTree = ""; }; 97E7DF0A2B7A3EAF00A2A09B /* CourseEnrollmentsMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseEnrollmentsMock.swift; sourceTree = ""; }; BBABB135366FFB1DAEFA0D16 /* Pods-App-Dashboard-DashboardTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard-DashboardTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Dashboard-DashboardTests/Pods-App-Dashboard-DashboardTests.debugprod.xcconfig"; sourceTree = ""; }; CCF4C665AD91B6B96F6A11DF /* Pods-App-Dashboard-DashboardTests.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard-DashboardTests.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Dashboard-DashboardTests/Pods-App-Dashboard-DashboardTests.debugdev.xcconfig"; sourceTree = ""; }; CE1735052CD2552A00F9606A /* PrimaryCourseDashboardViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryCourseDashboardViewModelTests.swift; sourceTree = ""; }; CE1735092CD26CB500F9606A /* AllCoursesViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllCoursesViewModelTests.swift; sourceTree = ""; }; + D1621B3181F9FA360501CBE3 /* Pods-App-Dashboard-DashboardTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard-DashboardTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Dashboard-DashboardTests/Pods-App-Dashboard-DashboardTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; DE6CF4F983BBF52606807F9A /* Pods-App-Dashboard-DashboardTests.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard-DashboardTests.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Dashboard-DashboardTests/Pods-App-Dashboard-DashboardTests.debugstage.xcconfig"; sourceTree = ""; }; E36D702D7E3F9A8B3303AD0A /* Pods-App-Dashboard-DashboardTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard-DashboardTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Dashboard-DashboardTests/Pods-App-Dashboard-DashboardTests.releasedev.xcconfig"; sourceTree = ""; }; E5B672C28C8F9279BB4E5C9B /* Pods-App-Dashboard.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Dashboard.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Dashboard/Pods-App-Dashboard.releasestage.xcconfig"; sourceTree = ""; }; @@ -279,6 +283,10 @@ E5B672C28C8F9279BB4E5C9B /* Pods-App-Dashboard.releasestage.xcconfig */, DE6CF4F983BBF52606807F9A /* Pods-App-Dashboard-DashboardTests.debugstage.xcconfig */, ECE21225FE448F905E93214B /* Pods-App-Dashboard-DashboardTests.releasestage.xcconfig */, + 58318522C8BCB420C91906FF /* Pods-App-Dashboard.openedxmultitenants.xcconfig */, + D1621B3181F9FA360501CBE3 /* Pods-App-Dashboard-DashboardTests.openedxmultitenants.xcconfig */, + 62182E1F063E9CE38CA426DD /* Pods-App-Dashboard.debugprodtenants.xcconfig */, + 97B43AAB00F57C5433DE9D3A /* Pods-App-Dashboard-DashboardTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -1487,6 +1495,239 @@ }; name = ReleaseProd; }; + 995886B52E6448850065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886B62E6448850065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 62182E1F063E9CE38CA426DD /* Pods-App-Dashboard.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Dashboard; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886B72E6448850065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 97B43AAB00F57C5433DE9D3A /* Pods-App-Dashboard-DashboardTests.debugprodtenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DashboardTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1E32E60376A0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1E42E60376A0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 58318522C8BCB420C91906FF /* Pods-App-Dashboard.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Dashboard; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1E52E60376A0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D1621B3181F9FA360501CBE3 /* Pods-App-Dashboard-DashboardTests.openedxmultitenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DashboardTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1494,11 +1735,13 @@ isa = XCConfigurationList; buildConfigurations = ( 02A9A90F2978194100B55797 /* Debug */, + 9972D1E52E60376A0020CFBD /* OpenEdXMultiTenants */, 02A9A9102978194100B55797 /* DebugProd */, 02DD1CAD29E80D2000F35DCE /* DebugStage */, 02A9A9112978194100B55797 /* DebugDev */, 02A9A9122978194100B55797 /* Release */, 02A9A9132978194100B55797 /* ReleaseProd */, + 995886B72E6448850065D132 /* DebugProdTenants */, 02DD1CB029E80D2A00F35DCE /* ReleaseStage */, 02A9A9142978194100B55797 /* ReleaseDev */, ); @@ -1509,11 +1752,13 @@ isa = XCConfigurationList; buildConfigurations = ( 02EF39EC28D89F560058F6BD /* Debug */, + 9972D1E32E60376A0020CFBD /* OpenEdXMultiTenants */, 02EF39F728D89FAC0058F6BD /* DebugProd */, 02DD1CAB29E80D2000F35DCE /* DebugStage */, 02EF39F128D89F870058F6BD /* DebugDev */, 02EF39ED28D89F560058F6BD /* Release */, 02EF39F928D89FB20058F6BD /* ReleaseProd */, + 995886B52E6448850065D132 /* DebugProdTenants */, 02DD1CAE29E80D2A00F35DCE /* ReleaseStage */, 02EF39F528D89F9B0058F6BD /* ReleaseDev */, ); @@ -1524,11 +1769,13 @@ isa = XCConfigurationList; buildConfigurations = ( 02EF39EF28D89F560058F6BD /* Debug */, + 9972D1E42E60376A0020CFBD /* OpenEdXMultiTenants */, 02EF39F828D89FAC0058F6BD /* DebugProd */, 02DD1CAC29E80D2000F35DCE /* DebugStage */, 02EF39F228D89F870058F6BD /* DebugDev */, 02EF39F028D89F560058F6BD /* Release */, 02EF39FA28D89FB20058F6BD /* ReleaseProd */, + 995886B62E6448850065D132 /* DebugProdTenants */, 02DD1CAF29E80D2A00F35DCE /* ReleaseStage */, 02EF39F628D89F9B0058F6BD /* ReleaseDev */, ); diff --git a/Dashboard/Dashboard/Data/DashboardRepository.swift b/Dashboard/Dashboard/Data/DashboardRepository.swift index 028b5cd3f..edaae0ca7 100644 --- a/Dashboard/Dashboard/Data/DashboardRepository.swift +++ b/Dashboard/Dashboard/Data/DashboardRepository.swift @@ -23,12 +23,20 @@ public actor DashboardRepository: DashboardRepositoryProtocol { private let storage: CoreStorage private let config: ConfigProtocol private let persistence: DashboardPersistenceProtocol + private let tenantProvider: () -> TenantProvider - public init(api: API, storage: CoreStorage, config: ConfigProtocol, persistence: DashboardPersistenceProtocol) { + public init( + api: API, + storage: CoreStorage, + config: ConfigProtocol, + persistence: DashboardPersistenceProtocol, + tenantProvider: @escaping () -> TenantProvider + ) { self.api = api self.storage = storage self.config = config self.persistence = persistence + self.tenantProvider = tenantProvider } public func getEnrollments(page: Int) async throws -> [CourseItem] { @@ -36,7 +44,7 @@ public actor DashboardRepository: DashboardRepositoryProtocol { DashboardEndpoint.getEnrollments(username: storage.user?.username ?? "", page: page) ) .mapResponse(DataLayer.CourseEnrollments.self) - .domain(baseURL: config.baseURL.absoluteString) + .domain(baseURL: tenantProvider().baseURL.absoluteString) await persistence.saveEnrollments(items: result) return result @@ -54,7 +62,7 @@ public actor DashboardRepository: DashboardRepositoryProtocol { ) ) .mapResponse(DataLayer.PrimaryEnrollment.self) - .domain(baseURL: config.baseURL.absoluteString) + .domain(baseURL: tenantProvider().baseURL.absoluteString) await persistence.savePrimaryEnrollment(enrollments: result) return result } @@ -72,7 +80,7 @@ public actor DashboardRepository: DashboardRepositoryProtocol { ) ) .mapResponse(DataLayer.PrimaryEnrollment.self) - .domain(baseURL: config.baseURL.absoluteString) + .domain(baseURL: tenantProvider().baseURL.absoluteString) return result } } diff --git a/Dashboard/Dashboard/Presentation/AllCoursesView.swift b/Dashboard/Dashboard/Presentation/AllCoursesView.swift index 4ab5fd905..c920c6f10 100644 --- a/Dashboard/Dashboard/Presentation/AllCoursesView.swift +++ b/Dashboard/Dashboard/Presentation/AllCoursesView.swift @@ -133,6 +133,7 @@ public struct AllCoursesView: View { await viewModel.getCourses(page: 1, refresh: true) } ) + .environmentObject(ThemeManager.shared) // MARK: - Error Alert if viewModel.showError { diff --git a/Dashboard/Dashboard/Presentation/Elements/DropDownMenu.swift b/Dashboard/Dashboard/Presentation/Elements/DropDownMenu.swift index 3c6d678a0..d995f4a44 100644 --- a/Dashboard/Dashboard/Presentation/Elements/DropDownMenu.swift +++ b/Dashboard/Dashboard/Presentation/Elements/DropDownMenu.swift @@ -65,8 +65,9 @@ struct DropDownMenu: View { Text(option.text) .font(Theme.Fonts.titleSmall) .foregroundColor( - option == selectedOption ? Theme.Colors.primaryButtonTextColor : - Theme.Colors.textPrimary + option == selectedOption ? + Theme.Colors.primaryButtonTextColor + : Theme.Colors.textPrimary ) Spacer() } diff --git a/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift b/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift index 100a75e48..092f98309 100644 --- a/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift +++ b/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift @@ -134,7 +134,7 @@ public struct PrimaryCardView: View { title: pastAssignment.title, description: DashboardLocalization.Learn.PrimaryCard.onePastAssignment, icon: CoreAssets.warning.swiftUIImage, - selected: false, + selected: false, bgColor: Theme.Colors.secondaryButtonBGColor, action: { assignmentAction(pastAssignments.first?.firstComponentBlockId) } ) } else if pastAssignments.count > 1 { @@ -142,7 +142,7 @@ public struct PrimaryCardView: View { title: DashboardLocalization.Learn.PrimaryCard.viewAssignments, description: DashboardLocalization.Learn.PrimaryCard.pastAssignments(pastAssignments.count), icon: CoreAssets.warning.swiftUIImage, - selected: false, + selected: false, bgColor: Theme.Colors.primaryCardCautionBG, action: { assignmentAction(nil) } ) } @@ -158,7 +158,7 @@ public struct PrimaryCardView: View { dueIn: true ), icon: CoreAssets.chapter.swiftUIImage, - selected: false, + selected: false, bgColor: Theme.Colors.secondaryButtonBGColor, action: { assignmentAction(futureAssignments.first?.firstComponentBlockId) } @@ -172,7 +172,7 @@ public struct PrimaryCardView: View { ), description: nil, icon: CoreAssets.chapter.swiftUIImage, - selected: false, + selected: false, bgColor: Theme.Colors.secondaryButtonBGColor, action: { assignmentAction(nil) } @@ -209,7 +209,7 @@ public struct PrimaryCardView: View { description: String?, icon: Image, selected: Bool, - bgColor: Color = Theme.Colors.primaryCardCautionBG, + bgColor: Color, action: @escaping () -> Void ) -> some View { Button(action: { diff --git a/Dashboard/Dashboard/Presentation/ListDashboardView.swift b/Dashboard/Dashboard/Presentation/ListDashboardView.swift index 8f668dcc5..7e913e8c1 100644 --- a/Dashboard/Dashboard/Presentation/ListDashboardView.swift +++ b/Dashboard/Dashboard/Presentation/ListDashboardView.swift @@ -128,6 +128,7 @@ public struct ListDashboardView: View { reloadAction: { await viewModel.getMyCourses(page: 1, refresh: true) }) + .environmentObject(ThemeManager.shared) // MARK: - Error Alert if viewModel.showError { diff --git a/Dashboard/Dashboard/Presentation/PrimaryCourseDashboardView.swift b/Dashboard/Dashboard/Presentation/PrimaryCourseDashboardView.swift index 905dcaaae..f6587bb03 100644 --- a/Dashboard/Dashboard/Presentation/PrimaryCourseDashboardView.swift +++ b/Dashboard/Dashboard/Presentation/PrimaryCourseDashboardView.swift @@ -39,6 +39,7 @@ public struct PrimaryCourseDashboardView: View { NoCoursesView(openDiscovery: { openDiscoveryPage() }).zIndex(1) + } learnTitleAndSearch(proxy: proxy) .zIndex(1) @@ -164,7 +165,9 @@ public struct PrimaryCourseDashboardView: View { reloadAction: { await viewModel.getEnrollments(showProgress: false) } - ).zIndex(2) + ) + .zIndex(2) + .environmentObject(ThemeManager.shared) // MARK: - Error Alert if viewModel.showError { @@ -202,6 +205,12 @@ public struct PrimaryCourseDashboardView: View { .navigationBarHidden(true) .navigationTitle(DashboardLocalization.title) } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } } @ViewBuilder diff --git a/Discovery/Discovery.xcodeproj/project.pbxproj b/Discovery/Discovery.xcodeproj/project.pbxproj index 9669212f1..06b92b10a 100644 --- a/Discovery/Discovery.xcodeproj/project.pbxproj +++ b/Discovery/Discovery.xcodeproj/project.pbxproj @@ -96,17 +96,20 @@ 1402A0C82B61012F00A0A00B /* ProgramWebviewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgramWebviewViewModel.swift; sourceTree = ""; }; 2334C76D248D0A95634AFFD9 /* Pods-App-Discovery-DiscoveryUnitTests.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.debugstage.xcconfig"; sourceTree = ""; }; 2760B1F234E01FFCB73F41C2 /* Pods-App-Discovery.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.debug.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.debug.xcconfig"; sourceTree = ""; }; + 3326B41CA254B8893BCB6670 /* Pods-App-Discovery.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.openedxmultitenants.xcconfig"; sourceTree = ""; }; 445F0675BF0E1DEB78F3CE73 /* Pods-App-Discovery-DiscoveryUnitTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.releasedev.xcconfig"; sourceTree = ""; }; 4786022BA3ED2D55DD0E5C8F /* Pods-App-Discovery.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.debugdev.xcconfig"; sourceTree = ""; }; 57E62A3FCA858F5A1FF77347 /* Pods-App-Discovery.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.releaseprod.xcconfig"; sourceTree = ""; }; 617697245CE8F67AF2BBE250 /* Pods-App-Discovery.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.debugprod.xcconfig"; sourceTree = ""; }; 69F97EEB323CA56E818CD6C4 /* Pods-App-Discovery-DiscoveryUnitTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.debugprod.xcconfig"; sourceTree = ""; }; 780FC373E1D479E58870BD85 /* Pods_App_Discovery_DiscoveryUnitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Discovery_DiscoveryUnitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 814B56397435F8B0862C7697 /* Pods-App-Discovery-DiscoveryUnitTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; 836BEF3BBFF8FD02C62D862C /* Pods-App-Discovery.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.debugstage.xcconfig"; sourceTree = ""; }; 83FB998DD9C5B57B61B88170 /* Pods-App-Discovery-DiscoveryUnitTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.releasestage.xcconfig"; sourceTree = ""; }; 919E55130969D91EF03C4C0B /* Pods_App_Discovery.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Discovery.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9F968F74AD7F4B5F6E5A6084 /* Pods-App-Discovery-DiscoveryUnitTests.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.debugdev.xcconfig"; sourceTree = ""; }; AAC0D83F5D34491E9FABCABC /* Pods-App-Discovery-DiscoveryUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.debug.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.debug.xcconfig"; sourceTree = ""; }; + B12E8D6CB2EF9FC375A9EC88 /* Pods-App-Discovery-DiscoveryUnitTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.debugprodtenants.xcconfig"; sourceTree = ""; }; CFC8494D299A66080055E497 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; CFC8494F299BE52C0055E497 /* SearchViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewModelTests.swift; sourceTree = ""; }; E08D12E22B482D720096311A /* Course.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Course.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -126,6 +129,7 @@ E0D586242B300134009B4BA7 /* URL+PathExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+PathExtension.swift"; sourceTree = ""; }; E0D586282B302C3A009B4BA7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; E192F9B4A7EECED9665AB8A7 /* Pods-App-Discovery.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.releasedev.xcconfig"; sourceTree = ""; }; + E4FAEE6C2CBF1988F8C15058 /* Pods-App-Discovery.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Discovery/Pods-App-Discovery.debugprodtenants.xcconfig"; sourceTree = ""; }; F340BD73D38B0DF9E4EA6482 /* Pods-App-Discovery-DiscoveryUnitTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.releaseprod.xcconfig"; sourceTree = ""; }; FF565519B9BBC73E92249648 /* Pods-App-Discovery-DiscoveryUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discovery-DiscoveryUnitTests.release.xcconfig"; path = "Target Support Files/Pods-App-Discovery-DiscoveryUnitTests/Pods-App-Discovery-DiscoveryUnitTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -315,6 +319,10 @@ 0692409931272CDA39B10321 /* Pods-App-Discovery.releasestage.xcconfig */, 2334C76D248D0A95634AFFD9 /* Pods-App-Discovery-DiscoveryUnitTests.debugstage.xcconfig */, 83FB998DD9C5B57B61B88170 /* Pods-App-Discovery-DiscoveryUnitTests.releasestage.xcconfig */, + 3326B41CA254B8893BCB6670 /* Pods-App-Discovery.openedxmultitenants.xcconfig */, + 814B56397435F8B0862C7697 /* Pods-App-Discovery-DiscoveryUnitTests.openedxmultitenants.xcconfig */, + E4FAEE6C2CBF1988F8C15058 /* Pods-App-Discovery.debugprodtenants.xcconfig */, + B12E8D6CB2EF9FC375A9EC88 /* Pods-App-Discovery-DiscoveryUnitTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -1571,6 +1579,241 @@ }; name = ReleaseDev; }; + 995886AC2E6447680065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886AD2E6447680065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E4FAEE6C2CBF1988F8C15058 /* Pods-App-Discovery.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Discovery/Info.plist; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Discovery; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886AE2E6447680065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B12E8D6CB2EF9FC375A9EC88 /* Pods-App-Discovery-DiscoveryUnitTests.debugprodtenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DiscoveryUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1E02E6037630020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1E12E6037630020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3326B41CA254B8893BCB6670 /* Pods-App-Discovery.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Discovery/Info.plist; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Discovery; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1E22E6037630020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 814B56397435F8B0862C7697 /* Pods-App-Discovery-DiscoveryUnitTests.openedxmultitenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DiscoveryUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1578,12 +1821,14 @@ isa = XCConfigurationList; buildConfigurations = ( 022D048E2976D7E100E0059B /* Debug */, + 9972D1E22E6037630020CFBD /* OpenEdXMultiTenants */, 022D048F2976D7E100E0059B /* DebugDev */, 022D04902976D7E100E0059B /* DebugProd */, 02DD1CA729E80D1000F35DCE /* DebugStage */, 022D04912976D7E100E0059B /* Release */, 022D04922976D7E100E0059B /* ReleaseDev */, 022D04932976D7E100E0059B /* ReleaseProd */, + 995886AE2E6447680065D132 /* DebugProdTenants */, 02DD1CAA29E80D1600F35DCE /* ReleaseStage */, ); defaultConfigurationIsVisible = 0; @@ -1593,12 +1838,14 @@ isa = XCConfigurationList; buildConfigurations = ( 0727879E28D34C03002E9142 /* Debug */, + 9972D1E02E6037630020CFBD /* OpenEdXMultiTenants */, 072787A528D34CE8002E9142 /* DebugDev */, 072787A328D34CE4002E9142 /* DebugProd */, 02DD1CA529E80D1000F35DCE /* DebugStage */, 0727879F28D34C03002E9142 /* Release */, 072787A928D34CF6002E9142 /* ReleaseDev */, 072787A728D34CF2002E9142 /* ReleaseProd */, + 995886AC2E6447680065D132 /* DebugProdTenants */, 02DD1CA829E80D1600F35DCE /* ReleaseStage */, ); defaultConfigurationIsVisible = 0; @@ -1608,12 +1855,14 @@ isa = XCConfigurationList; buildConfigurations = ( 072787A128D34C03002E9142 /* Debug */, + 9972D1E12E6037630020CFBD /* OpenEdXMultiTenants */, 072787A628D34CE8002E9142 /* DebugDev */, 072787A428D34CE4002E9142 /* DebugProd */, 02DD1CA629E80D1000F35DCE /* DebugStage */, 072787A228D34C03002E9142 /* Release */, 072787AA28D34CF6002E9142 /* ReleaseDev */, 072787A828D34CF2002E9142 /* ReleaseProd */, + 995886AD2E6447680065D132 /* DebugProdTenants */, 02DD1CA929E80D1600F35DCE /* ReleaseStage */, ); defaultConfigurationIsVisible = 0; diff --git a/Discovery/Discovery/Data/DiscoveryRepository.swift b/Discovery/Discovery/Data/DiscoveryRepository.swift index 9ce20c9c3..68b5f67e2 100644 --- a/Discovery/Discovery/Data/DiscoveryRepository.swift +++ b/Discovery/Discovery/Data/DiscoveryRepository.swift @@ -26,17 +26,20 @@ public actor DiscoveryRepository: DiscoveryRepositoryProtocol { private let coreStorage: CoreStorage private let config: ConfigProtocol private let persistence: DiscoveryPersistenceProtocol + private let tenantProvider: @Sendable () -> any TenantProvider public init( api: API, appStorage: CoreStorage, config: ConfigProtocol, - persistence: DiscoveryPersistenceProtocol + persistence: DiscoveryPersistenceProtocol, + tenantProvider: @Sendable @escaping () -> TenantProvider ) { self.api = api self.coreStorage = appStorage self.config = config self.persistence = persistence + self.tenantProvider = tenantProvider } public func getDiscovery(page: Int) async throws -> [CourseItem] { @@ -63,7 +66,7 @@ public actor DiscoveryRepository: DiscoveryRepositoryProtocol { let response = try await api.requestData( DiscoveryEndpoint.getCourseDetail(courseID: courseID, username: coreStorage.user?.username ?? "") ).mapResponse(DataLayer.CourseDetailsResponse.self) - .domain(baseURL: config.baseURL.absoluteString) + .domain(baseURL: tenantProvider().baseURL.absoluteString) await persistence.saveCourseDetails(course: response) diff --git a/Discovery/Discovery/Presentation/NativeDiscovery/CourseDetailsView.swift b/Discovery/Discovery/Presentation/NativeDiscovery/CourseDetailsView.swift index 2cbe294c1..c6c68108c 100644 --- a/Discovery/Discovery/Presentation/NativeDiscovery/CourseDetailsView.swift +++ b/Discovery/Discovery/Presentation/NativeDiscovery/CourseDetailsView.swift @@ -195,6 +195,7 @@ public struct CourseDetailsView: View { reloadAction: { await viewModel.getCourseDetail(courseID: courseID, withProgress: false) }) + .environmentObject(ThemeManager.shared) } // MARK: - Error Alert @@ -217,6 +218,12 @@ public struct CourseDetailsView: View { Theme.Colors.background .ignoresSafeArea() ) + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } } } @@ -289,7 +296,10 @@ private struct CourseStateView: View { .multilineTextAlignment(.leading) .font(Theme.Fonts.titleSmall) Spacer() - }.cardStyle(paddingAll: 12, bgColor: Theme.Colors.textInputUnfocusedBackground, strokeColor: .clear) + }.cardStyle( + paddingAll: 12, + bgColor: Theme.Colors.textInputUnfocusedBackground, + strokeColor: .clear) } } .accessibilityIdentifier("enroll_button") diff --git a/Discovery/Discovery/Presentation/NativeDiscovery/DiscoveryView.swift b/Discovery/Discovery/Presentation/NativeDiscovery/DiscoveryView.swift index ffeb3451b..f4f465dbb 100644 --- a/Discovery/Discovery/Presentation/NativeDiscovery/DiscoveryView.swift +++ b/Discovery/Discovery/Presentation/NativeDiscovery/DiscoveryView.swift @@ -171,6 +171,7 @@ public struct DiscoveryView: View { reloadAction: { await viewModel.discovery(page: 1, withProgress: false) }) + .environmentObject(ThemeManager.shared) // MARK: - Error Alert if viewModel.showError { @@ -202,6 +203,12 @@ public struct DiscoveryView: View { } } .background(Theme.Colors.background.ignoresSafeArea()) + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } } } diff --git a/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebview.swift b/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebview.swift index 2b7b48199..8feb10043 100644 --- a/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebview.swift +++ b/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebview.swift @@ -106,7 +106,7 @@ public struct DiscoveryWebview: View { webViewType: discoveryType.rawValue ) .accessibilityIdentifier("discovery_webview") - + if isLoading || viewModel.showProgress { HStack(alignment: .center) { ProgressBar( @@ -169,6 +169,12 @@ public struct DiscoveryWebview: View { } } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .navigationBarHidden(viewModel.sourceScreen == .default && discoveryType == .discovery) .navigationTitle(CoreLocalization.Mainscreen.discovery) .background(Theme.Colors.background.ignoresSafeArea()) diff --git a/Discovery/Discovery/Presentation/WebPrograms/ProgramWebviewView.swift b/Discovery/Discovery/Presentation/WebPrograms/ProgramWebviewView.swift index a206303d8..603181f3c 100644 --- a/Discovery/Discovery/Presentation/WebPrograms/ProgramWebviewView.swift +++ b/Discovery/Discovery/Presentation/WebPrograms/ProgramWebviewView.swift @@ -128,6 +128,12 @@ public struct ProgramWebviewView: View { .navigationTitle(CoreLocalization.Mainscreen.programs) .background(Theme.Colors.background.ignoresSafeArea()) .animation(.default, value: viewModel.showError) + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } } } diff --git a/Discussion/Discussion.xcodeproj/project.pbxproj b/Discussion/Discussion.xcodeproj/project.pbxproj index 3daa42fdb..a7949249e 100644 --- a/Discussion/Discussion.xcodeproj/project.pbxproj +++ b/Discussion/Discussion.xcodeproj/project.pbxproj @@ -150,6 +150,7 @@ 02F3BFEA2926A5B50051930C /* Data_CommentsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data_CommentsResponse.swift; sourceTree = ""; }; 02F3BFEC2926A6270051930C /* UserComment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserComment.swift; sourceTree = ""; }; 02F3BFEE2926AB9C0051930C /* UserThread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserThread.swift; sourceTree = ""; }; + 03BDF6B1D8DF3EE0E9EF28B5 /* Pods-App-Discussion.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Discussion/Pods-App-Discussion.debugprodtenants.xcconfig"; sourceTree = ""; }; 075DBBB0292631C600E56134 /* ThreadPostState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadPostState.swift; sourceTree = ""; }; 075DBBB229267D1D00E56134 /* PostState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostState.swift; sourceTree = ""; }; 0766DFBD299AA18A00EBEF6A /* DiscussionPost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscussionPost.swift; sourceTree = ""; }; @@ -161,11 +162,14 @@ 1DF890C9EF8CFBC7610676BF /* Pods-App-Discussion.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion.release.xcconfig"; path = "Target Support Files/Pods-App-Discussion/Pods-App-Discussion.release.xcconfig"; sourceTree = ""; }; 2F4E0FCAD2C351B8C3DCE0DA /* Pods-App-Discussion-DiscussionTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion-DiscussionTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Discussion-DiscussionTests/Pods-App-Discussion-DiscussionTests.debugprod.xcconfig"; sourceTree = ""; }; 307AD0C3C81316D6B0C04178 /* Pods-App-Discussion-DiscussionTests.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion-DiscussionTests.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Discussion-DiscussionTests/Pods-App-Discussion-DiscussionTests.debugdev.xcconfig"; sourceTree = ""; }; + 3FBDB80EA96C70B62AEDCCFC /* Pods-App-Discussion-DiscussionTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion-DiscussionTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Discussion-DiscussionTests/Pods-App-Discussion-DiscussionTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; 4D6EE7EAA4004C3BE8757E3E /* Pods-App-Discussion-DiscussionTests.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion-DiscussionTests.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Discussion-DiscussionTests/Pods-App-Discussion-DiscussionTests.debugstage.xcconfig"; sourceTree = ""; }; 55A6A0C34167EFFA9736A83E /* Pods-App-Discussion-DiscussionTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion-DiscussionTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Discussion-DiscussionTests/Pods-App-Discussion-DiscussionTests.releaseprod.xcconfig"; sourceTree = ""; }; 59F3BBE6ACFA3C87C2294DA0 /* Pods-App-Discussion-DiscussionTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion-DiscussionTests.release.xcconfig"; path = "Target Support Files/Pods-App-Discussion-DiscussionTests/Pods-App-Discussion-DiscussionTests.release.xcconfig"; sourceTree = ""; }; 5F59EC4433FF0AE0743D284D /* Pods-App-Discussion.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Discussion/Pods-App-Discussion.releaseprod.xcconfig"; sourceTree = ""; }; 66A7A0375EDDEB8948165EAD /* Pods_App_Discussion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Discussion.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 686BECEE87FEE847E66C4626 /* Pods-App-Discussion-DiscussionTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion-DiscussionTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Discussion-DiscussionTests/Pods-App-Discussion-DiscussionTests.debugprodtenants.xcconfig"; sourceTree = ""; }; + 7E72605E6C8C66CBCF91D1B5 /* Pods-App-Discussion.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Discussion/Pods-App-Discussion.openedxmultitenants.xcconfig"; sourceTree = ""; }; A55CEBCC51BDC30B8354E258 /* Pods-App-Discussion.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Discussion/Pods-App-Discussion.debugprod.xcconfig"; sourceTree = ""; }; ACA8EF2DEDDB7695162C381A /* Pods-App-Discussion.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion.debug.xcconfig"; path = "Target Support Files/Pods-App-Discussion/Pods-App-Discussion.debug.xcconfig"; sourceTree = ""; }; ACDA8EE733B97BCD8689A0B4 /* Pods-App-Discussion.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Discussion.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Discussion/Pods-App-Discussion.debugstage.xcconfig"; sourceTree = ""; }; @@ -518,6 +522,10 @@ F57B9404423B3E624DD25D81 /* Pods-App-Discussion.releasestage.xcconfig */, 4D6EE7EAA4004C3BE8757E3E /* Pods-App-Discussion-DiscussionTests.debugstage.xcconfig */, C214357310D8AC9185B38ABA /* Pods-App-Discussion-DiscussionTests.releasestage.xcconfig */, + 7E72605E6C8C66CBCF91D1B5 /* Pods-App-Discussion.openedxmultitenants.xcconfig */, + 3FBDB80EA96C70B62AEDCCFC /* Pods-App-Discussion-DiscussionTests.openedxmultitenants.xcconfig */, + 03BDF6B1D8DF3EE0E9EF28B5 /* Pods-App-Discussion.debugprodtenants.xcconfig */, + 686BECEE87FEE847E66C4626 /* Pods-App-Discussion-DiscussionTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -1752,6 +1760,237 @@ }; name = ReleaseStage; }; + 995886C12E6448DF0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886C22E6448DF0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 03BDF6B1D8DF3EE0E9EF28B5 /* Pods-App-Discussion.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Discussion; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886C32E6448DF0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 686BECEE87FEE847E66C4626 /* Pods-App-Discussion-DiscussionTests.debugprodtenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DiscussionTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1EF2E6037850020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1F02E6037850020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7E72605E6C8C66CBCF91D1B5 /* Pods-App-Discussion.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Discussion; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1F12E6037850020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3FBDB80EA96C70B62AEDCCFC /* Pods-App-Discussion-DiscussionTests.openedxmultitenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DiscussionTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1759,12 +1998,14 @@ isa = XCConfigurationList; buildConfigurations = ( 0218195228F7344A00202564 /* Debug */, + 9972D1EF2E6037850020CFBD /* OpenEdXMultiTenants */, 0218196828F7352100202564 /* DebugDev */, 0218196628F7351B00202564 /* DebugProd */, 02DD1CBD29E80D5300F35DCE /* DebugStage */, 0218195328F7344A00202564 /* Release */, 0218196C28F7352B00202564 /* ReleaseDev */, 0218196A28F7352600202564 /* ReleaseProd */, + 995886C12E6448DF0065D132 /* DebugProdTenants */, 02DD1CC029E80D5B00F35DCE /* ReleaseStage */, ); defaultConfigurationIsVisible = 0; @@ -1774,12 +2015,14 @@ isa = XCConfigurationList; buildConfigurations = ( 0218195528F7344A00202564 /* Debug */, + 9972D1F02E6037850020CFBD /* OpenEdXMultiTenants */, 0218196928F7352100202564 /* DebugDev */, 0218196728F7351B00202564 /* DebugProd */, 02DD1CBE29E80D5300F35DCE /* DebugStage */, 0218195628F7344A00202564 /* Release */, 0218196D28F7352B00202564 /* ReleaseDev */, 0218196B28F7352600202564 /* ReleaseProd */, + 995886C22E6448DF0065D132 /* DebugProdTenants */, 02DD1CC129E80D5B00F35DCE /* ReleaseStage */, ); defaultConfigurationIsVisible = 0; @@ -1789,12 +2032,14 @@ isa = XCConfigurationList; buildConfigurations = ( 0240D8D62987FE1F003CFE50 /* Debug */, + 9972D1F12E6037850020CFBD /* OpenEdXMultiTenants */, 0240D8D72987FE1F003CFE50 /* DebugDev */, 0240D8D82987FE1F003CFE50 /* DebugProd */, 02DD1CBF29E80D5300F35DCE /* DebugStage */, 0240D8D92987FE1F003CFE50 /* Release */, 0240D8DA2987FE1F003CFE50 /* ReleaseDev */, 0240D8DB2987FE1F003CFE50 /* ReleaseProd */, + 995886C32E6448DF0065D132 /* DebugProdTenants */, 02DD1CC229E80D5B00F35DCE /* ReleaseStage */, ); defaultConfigurationIsVisible = 0; diff --git a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift index 0b943be91..304e2f3a8 100644 --- a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift +++ b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift @@ -228,6 +228,12 @@ public struct ResponsesView: View { } } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .ignoresSafeArea(.all, edges: .horizontal) .navigationBarHidden(false) .navigationBarBackButtonHidden(true) diff --git a/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift b/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift index b673630bc..ca43183ba 100644 --- a/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift +++ b/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift @@ -244,6 +244,12 @@ public struct ThreadView: View { } } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .ignoresSafeArea(.all, edges: .horizontal) .navigationBarHidden(false) .navigationBarBackButtonHidden(true) diff --git a/Discussion/Discussion/Presentation/CreateNewThread/CreateNewThreadView.swift b/Discussion/Discussion/Presentation/CreateNewThread/CreateNewThreadView.swift index e630c9b8d..4c644bb2d 100644 --- a/Discussion/Discussion/Presentation/CreateNewThread/CreateNewThreadView.swift +++ b/Discussion/Discussion/Presentation/CreateNewThread/CreateNewThreadView.swift @@ -196,6 +196,12 @@ public struct CreateNewThreadView: View { } }.padding(.top, 8) } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .navigationBarHidden(false) .navigationBarBackButtonHidden(false) .navigationTitle(DiscussionLocalization.CreateThread.newPost) diff --git a/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift b/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift index 61106f87a..7f1805e82 100644 --- a/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift +++ b/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift @@ -116,7 +116,9 @@ public struct DiscussionTopicsView: View { Spacer(minLength: 0) } .frame(maxWidth: .infinity) - }).cardStyle(bgColor: Theme.Colors.textInputUnfocusedBackground) + }) + .cardStyle( + bgColor: Theme.Colors.textInputUnfocusedBackground) .padding(.trailing, -20) } if let followed = topics.first(where: { @@ -134,7 +136,9 @@ public struct DiscussionTopicsView: View { Spacer(minLength: 0) } .frame(maxWidth: .infinity) - }).cardStyle(bgColor: Theme.Colors.textInputUnfocusedBackground) + }) + .cardStyle( + bgColor: Theme.Colors.textInputUnfocusedBackground) .padding(.leading, -20) } @@ -147,7 +151,8 @@ public struct DiscussionTopicsView: View { HStack { Text("\(topic.name):") .font(Theme.Fonts.titleMedium) - .foregroundColor(Theme.Colors.textSecondary) + .foregroundColor( + Theme.Colors.textSecondary) Spacer() }.padding(.top, 12) .padding(.bottom, 8) @@ -200,6 +205,12 @@ public struct DiscussionTopicsView: View { await viewModel.getTopics(courseID: courseID) } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .navigationBarHidden(false) .navigationBarBackButtonHidden(false) .navigationTitle(viewModel.title) diff --git a/Discussion/Discussion/Presentation/Posts/PostsView.swift b/Discussion/Discussion/Presentation/Posts/PostsView.swift index f3bfd7dc1..dbc2e5be2 100644 --- a/Discussion/Discussion/Presentation/Posts/PostsView.swift +++ b/Discussion/Discussion/Presentation/Posts/PostsView.swift @@ -134,7 +134,8 @@ public struct PostsView: View { .foregroundColor(Theme.Colors.white) .background( Circle() - .foregroundColor(Theme.Colors.accentButtonColor) + .foregroundColor( + Theme.Colors.accentButtonColor) ) }) } @@ -237,6 +238,12 @@ public struct PostsView: View { ) } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .navigationBarHidden(!showTopMenu) .navigationBarBackButtonHidden(!showTopMenu) .navigationTitle(title) @@ -321,46 +328,45 @@ public struct PostsView: View { } } -#if DEBUG -struct PostsView_Previews: PreviewProvider { - static var previews: some View { - let topics = Topics(coursewareTopics: [], nonCoursewareTopics: []) - let router = DiscussionRouterMock() - let vm = PostsViewModel( - interactor: DiscussionInteractor.mock, - router: router, - config: ConfigMock(), - storage: CoreStorageMock() - ) - - PostsView(courseID: "course_id", - currentBlockID: "123", - topics: topics, - title: "Lesson question", - type: .allPosts, - viewModel: vm, - router: router) - .preferredColorScheme(.light) - .previewDisplayName("PostsView Light") - .loadFonts() - - PostsView(courseID: "course_id", - currentBlockID: "123", - topics: topics, - title: "Lesson question", - type: .allPosts, - viewModel: vm, - router: router) - .preferredColorScheme(.dark) - .previewDisplayName("PostsView Dark") - .loadFonts() - - } -} -#endif +//#if DEBUG +//struct PostsView_Previews: PreviewProvider { +// static var previews: some View { +// let topics = Topics(coursewareTopics: [], nonCoursewareTopics: []) +// let router = DiscussionRouterMock() +// let vm = PostsViewModel( +// interactor: DiscussionInteractor.mock, +// router: router, +// config: ConfigMock(), +// storage: CoreStorageMock() +// ) +// +// PostsView(courseID: "course_id", +// currentBlockID: "123", +// topics: topics, +// title: "Lesson question", +// type: .allPosts, +// viewModel: vm, +// router: router) +// .preferredColorScheme(.light) +// .previewDisplayName("PostsView Light") +// .loadFonts() +// +// PostsView(courseID: "course_id", +// currentBlockID: "123", +// topics: topics, +// title: "Lesson question", +// type: .allPosts, +// viewModel: vm, +// router: router) +// .preferredColorScheme(.dark) +// .previewDisplayName("PostsView Dark") +// .loadFonts() +// +// } +//} +//#endif public struct PostCell: View { - private var post: DiscussionPost public init(post: DiscussionPost) { diff --git a/Downloads/Downloads.xcodeproj/project.pbxproj b/Downloads/Downloads.xcodeproj/project.pbxproj index 2907f8e3d..fc6c1381b 100644 --- a/Downloads/Downloads.xcodeproj/project.pbxproj +++ b/Downloads/Downloads.xcodeproj/project.pbxproj @@ -70,6 +70,7 @@ 18A1A0C393E3870DFB03C9A0 /* Pods-App-Downloads-DownloadsTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads-DownloadsTests.release.xcconfig"; path = "Target Support Files/Pods-App-Downloads-DownloadsTests/Pods-App-Downloads-DownloadsTests.release.xcconfig"; sourceTree = ""; }; 1BC76E2F677366D97F4C8A50 /* Pods-App-Downloads-DownloadsTests.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads-DownloadsTests.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Downloads-DownloadsTests/Pods-App-Downloads-DownloadsTests.debugdev.xcconfig"; sourceTree = ""; }; 4E3A5F43F066E899910779EB /* Pods-App-Downloads-DownloadsTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads-DownloadsTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Downloads-DownloadsTests/Pods-App-Downloads-DownloadsTests.debugprod.xcconfig"; sourceTree = ""; }; + 528C7B105876C7C4FF944CFC /* Pods-App-Downloads-DownloadsTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads-DownloadsTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Downloads-DownloadsTests/Pods-App-Downloads-DownloadsTests.debugprodtenants.xcconfig"; sourceTree = ""; }; 5E786010692BE6984E8D1570 /* Pods-App-Downloads.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Downloads/Pods-App-Downloads.releasedev.xcconfig"; sourceTree = ""; }; 6BE90243EF91211FDA213B0F /* Pods-App-Downloads-DownloadsTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads-DownloadsTests.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Downloads-DownloadsTests/Pods-App-Downloads-DownloadsTests.releasestage.xcconfig"; sourceTree = ""; }; 9F39C3E83AF8F1DCD9CC6524 /* Pods-App-Downloads.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Downloads/Pods-App-Downloads.releaseprod.xcconfig"; sourceTree = ""; }; @@ -103,6 +104,9 @@ CEB36E412D6A0E2C00907A89 /* swiftgen.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = swiftgen.yml; sourceTree = ""; }; CEB36E552D6A2A0400907A89 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CEC873BF2D75E15C00A2626C /* Downloads Mock.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Downloads Mock.generated.swift"; sourceTree = ""; }; + E00EF8363DE8F855D5F2D7C4 /* Pods-App-Downloads-DownloadsTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads-DownloadsTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Downloads-DownloadsTests/Pods-App-Downloads-DownloadsTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; + EB2C1021935033315A14037E /* Pods-App-Downloads.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Downloads/Pods-App-Downloads.openedxmultitenants.xcconfig"; sourceTree = ""; }; + F436E0B3FC557F6F6E905D9E /* Pods-App-Downloads.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Downloads/Pods-App-Downloads.debugprodtenants.xcconfig"; sourceTree = ""; }; F88F26577D0F66933184E825 /* Pods-App-Downloads.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Downloads/Pods-App-Downloads.debugprod.xcconfig"; sourceTree = ""; }; FA71B94B494DEAD479651F27 /* Pods-App-Downloads.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Downloads.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Downloads/Pods-App-Downloads.releasestage.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -150,6 +154,10 @@ 0E8EBB4043682DB77566B7E3 /* Pods-App-Downloads-DownloadsTests.releaseprod.xcconfig */, 6BE90243EF91211FDA213B0F /* Pods-App-Downloads-DownloadsTests.releasestage.xcconfig */, B97FA1C25474F0A5C5805030 /* Pods-App-Downloads-DownloadsTests.releasedev.xcconfig */, + EB2C1021935033315A14037E /* Pods-App-Downloads.openedxmultitenants.xcconfig */, + E00EF8363DE8F855D5F2D7C4 /* Pods-App-Downloads-DownloadsTests.openedxmultitenants.xcconfig */, + F436E0B3FC557F6F6E905D9E /* Pods-App-Downloads.debugprodtenants.xcconfig */, + 528C7B105876C7C4FF944CFC /* Pods-App-Downloads-DownloadsTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -546,6 +554,254 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 995886B82E6448C40065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886B92E6448C40065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F436E0B3FC557F6F6E905D9E /* Pods-App-Downloads.debugprodtenants.xcconfig */; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Downloads; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886BA2E6448C40065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 528C7B105876C7C4FF944CFC /* Pods-App-Downloads-DownloadsTests.debugprodtenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DownloadsTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1E62E60376F0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1E72E60376F0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EB2C1021935033315A14037E /* Pods-App-Downloads.openedxmultitenants.xcconfig */; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Downloads; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1E82E60376F0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E00EF8363DE8F855D5F2D7C4 /* Pods-App-Downloads-DownloadsTests.openedxmultitenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.DownloadsTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; CEB36E1B2D6A0D0B00907A89 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 1109AE1E7971BC02E1BAB67E /* Pods-App-Downloads.debug.xcconfig */; @@ -1545,11 +1801,13 @@ isa = XCConfigurationList; buildConfigurations = ( CEB36E1D2D6A0D0B00907A89 /* Debug */, + 9972D1E62E60376F0020CFBD /* OpenEdXMultiTenants */, CEB36E2F2D6A0DB400907A89 /* DebugStage */, CEB36E2C2D6A0DAD00907A89 /* DebugProd */, CEB36E292D6A0DA500907A89 /* DebugDev */, CEB36E1E2D6A0D0B00907A89 /* Release */, CEB36E382D6A0DC900907A89 /* ReleaseProd */, + 995886B82E6448C40065D132 /* DebugProdTenants */, CEB36E352D6A0DC300907A89 /* ReleaseStage */, CEB36E322D6A0DBC00907A89 /* ReleaseDev */, ); @@ -1560,11 +1818,13 @@ isa = XCConfigurationList; buildConfigurations = ( CEB36E1B2D6A0D0B00907A89 /* Debug */, + 9972D1E72E60376F0020CFBD /* OpenEdXMultiTenants */, CEB36E302D6A0DB400907A89 /* DebugStage */, CEB36E2D2D6A0DAD00907A89 /* DebugProd */, CEB36E2A2D6A0DA500907A89 /* DebugDev */, CEB36E1C2D6A0D0B00907A89 /* Release */, CEB36E392D6A0DC900907A89 /* ReleaseProd */, + 995886B92E6448C40065D132 /* DebugProdTenants */, CEB36E362D6A0DC300907A89 /* ReleaseStage */, CEB36E332D6A0DBC00907A89 /* ReleaseDev */, ); @@ -1575,11 +1835,13 @@ isa = XCConfigurationList; buildConfigurations = ( CEB36E202D6A0D0B00907A89 /* Debug */, + 9972D1E82E60376F0020CFBD /* OpenEdXMultiTenants */, CEB36E312D6A0DB400907A89 /* DebugStage */, CEB36E2E2D6A0DAD00907A89 /* DebugProd */, CEB36E2B2D6A0DA500907A89 /* DebugDev */, CEB36E212D6A0D0B00907A89 /* Release */, CEB36E3A2D6A0DC900907A89 /* ReleaseProd */, + 995886BA2E6448C40065D132 /* DebugProdTenants */, CEB36E372D6A0DC300907A89 /* ReleaseStage */, CEB36E342D6A0DBC00907A89 /* ReleaseDev */, ); diff --git a/Downloads/Downloads/Data/DownloadsRepository.swift b/Downloads/Downloads/Data/DownloadsRepository.swift index f35758fa4..4911aa45e 100644 --- a/Downloads/Downloads/Data/DownloadsRepository.swift +++ b/Downloads/Downloads/Data/DownloadsRepository.swift @@ -21,17 +21,20 @@ public actor DownloadsRepository: DownloadsRepositoryProtocol { private let coreStorage: CoreStorage private let config: ConfigProtocol private let persistence: DownloadsPersistenceProtocol + private let tenantProvider: @Sendable () -> any TenantProvider public init( api: API, coreStorage: CoreStorage, config: ConfigProtocol, - persistence: DownloadsPersistenceProtocol + persistence: DownloadsPersistenceProtocol, + tenantProvider: @escaping @Sendable () -> any TenantProvider ) { self.api = api self.coreStorage = coreStorage self.config = config self.persistence = persistence + self.tenantProvider = tenantProvider } public func getDownloadCourses() async throws -> [DownloadCoursePreview] { @@ -41,7 +44,7 @@ public actor DownloadsRepository: DownloadsRepositoryProtocol { let response = try await api.requestData(DownloadsEndpoint.getDownloadCourses(username: username)) .mapResponse([DataLayer.DownloadCoursePreviewResponse].self) - .map { $0.domain(baseURL: config.baseURL.absoluteString) } + .map { $0.domain(baseURL: tenantProvider().baseURL.absoluteString) } await persistence.saveDownloadCourses(courses: response) return response diff --git a/OpenEdX MultiTenants-Info.plist b/OpenEdX MultiTenants-Info.plist new file mode 100644 index 000000000..ce702e73a --- /dev/null +++ b/OpenEdX MultiTenants-Info.plist @@ -0,0 +1,47 @@ + + + + + BGTaskSchedulerPermittedIdentifiers + + openEdx.offlineProgressSync + + Configuration + $(CONFIGURATION) + FirebaseAppDelegateProxyEnabled + + FirebaseAutomaticScreenReportingEnabled + + FirebaseCrashlyticsCollectionEnabled + + LSApplicationQueriesSchemes + + googlegmail + readdle-spark + airmail + ms-outlook + ymail + fastmail + protonmail + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsArbitraryLoadsInWebContent + + + NSCalendarsFullAccessUsageDescription + We would like to utilize your calendar list to subscribe you to your personalized calendar for this course. + UIAppFonts + + UIBackgroundModes + + audio + fetch + processing + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/OpenEdX.xcodeproj/project.pbxproj b/OpenEdX.xcodeproj/project.pbxproj index ddfa0c30b..0867a2715 100644 --- a/OpenEdX.xcodeproj/project.pbxproj +++ b/OpenEdX.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ 07D5DA3E28D075AB00752FD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 07D5DA3D28D075AB00752FD9 /* Assets.xcassets */; }; 149FF39E2B9F1AB50034B33F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 149FF39C2B9F1AB50034B33F /* LaunchScreen.storyboard */; }; 3ACA3A1E886F3F9B2735B9AF /* Pods_App_OpenEdX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D27E034A83DDEBF18D53B04 /* Pods_App_OpenEdX.framework */; }; + 628ABA79268BC03EC141D7E5 /* Pods_App_OpenEdX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D27E034A83DDEBF18D53B04 /* Pods_App_OpenEdX.framework */; }; A500668B2B613ED10024680B /* PushNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A500668A2B613ED10024680B /* PushNotificationsManager.swift */; }; A500668D2B6143000024680B /* FCMProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A500668C2B6143000024680B /* FCMProvider.swift */; }; A50066932B614DCD0024680B /* FCMListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50066922B614DCD0024680B /* FCMListener.swift */; }; @@ -56,6 +57,7 @@ A59568972B61653700ED4F90 /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59568962B61653700ED4F90 /* DeepLink.swift */; }; A59568992B616D9400ED4F90 /* PushLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59568982B616D9400ED4F90 /* PushLink.swift */; }; BA7468762B96201D00793145 /* DeepLinkRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7468752B96201D00793145 /* DeepLinkRouter.swift */; }; + BC6BEB793EF3687D2C5E1D9B /* Pods_App_OpenEdX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D27E034A83DDEBF18D53B04 /* Pods_App_OpenEdX.framework */; }; CE0BF0BA2CD9203A00D10289 /* MSAL in Frameworks */ = {isa = PBXBuildFile; productRef = CE0BF0B92CD9203A00D10289 /* MSAL */; }; CE1D5B7B2CE60E000019CA34 /* ContainerMainActor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1D5B7A2CE60E000019CA34 /* ContainerMainActor.swift */; }; CE3BD14E2CBEB0DA0026F4E3 /* PluginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3BD14D2CBEB0DA0026F4E3 /* PluginManager.swift */; }; @@ -95,7 +97,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 005D1F4D92679D24B3BAA8FE /* Pods-App-OpenEdX.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.releasedev.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.releasedev.xcconfig"; sourceTree = ""; }; 020CA5D82AA0A25300970AAF /* AppStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorage.swift; sourceTree = ""; }; 0218196328F734FA00202564 /* Discussion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Discussion.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0219C67628F4347600D64452 /* Course.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Course.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -136,9 +137,12 @@ 07D5DA3428D075AA00752FD9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 07D5DA3D28D075AB00752FD9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 149FF39D2B9F1AB50034B33F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 2386FD6B3D624DEF6AFB238C /* Pods-App-OpenEdX.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.debugprod.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.debugprod.xcconfig"; sourceTree = ""; }; + 2970FF3233FBA54F18D84830 /* Pods-App-OpenEdX.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.releasestage.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.releasestage.xcconfig"; sourceTree = ""; }; 3D27E034A83DDEBF18D53B04 /* Pods_App_OpenEdX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_OpenEdX.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4449C4D4F119C87B452DDFCD /* Pods-App-OpenEdX.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.releaseprod.xcconfig"; sourceTree = ""; }; - 8A45E2C9AF0CBE70A09FB37B /* Pods-App-OpenEdX.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.debugstage.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.debugstage.xcconfig"; sourceTree = ""; }; + 7FF58E06BF82C5F521F6AE4B /* Pods-App-OpenEdX.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.releasedev.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.releasedev.xcconfig"; sourceTree = ""; }; + 83C62BF15B02F75D4E5C4EBA /* Pods-App-OpenEdX.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.debugdev.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.debugdev.xcconfig"; sourceTree = ""; }; + 9972D1D32E60338C0020CFBD /* OpenEdX MultiTenants-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "OpenEdX MultiTenants-Info.plist"; path = "/Users/rawan/Documents/SwiftUI/ZeitLabs/CONTRIB/openedx-app-ios-contrib/OpenEdX MultiTenants-Info.plist"; sourceTree = ""; }; A500668A2B613ED10024680B /* PushNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationsManager.swift; sourceTree = ""; }; A500668C2B6143000024680B /* FCMProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FCMProvider.swift; sourceTree = ""; }; A50066922B614DCD0024680B /* FCMListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FCMListener.swift; sourceTree = ""; }; @@ -147,14 +151,15 @@ A59568962B61653700ED4F90 /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = ""; }; A59568982B616D9400ED4F90 /* PushLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushLink.swift; sourceTree = ""; }; BA7468752B96201D00793145 /* DeepLinkRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkRouter.swift; sourceTree = ""; }; - CCE1E0F850D3E25C0D6C6702 /* Pods-App-OpenEdX.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.debugdev.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.debugdev.xcconfig"; sourceTree = ""; }; CE1D5B7A2CE60E000019CA34 /* ContainerMainActor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerMainActor.swift; sourceTree = ""; }; CE3BD14D2CBEB0DA0026F4E3 /* PluginManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginManager.swift; sourceTree = ""; }; CEB36E512D6A29CE00907A89 /* Downloads.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Downloads.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CEE5EDED2D6E0A290089F67C /* DownloadsPersistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsPersistence.swift; sourceTree = ""; }; - D70D30110012B7D52D05E876 /* Pods-App-OpenEdX.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.debugprod.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.debugprod.xcconfig"; sourceTree = ""; }; E0D6E6A22B1626B10089F9C9 /* Theme.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Theme.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - FD0CE8D22B755B4003A113BB /* Pods-App-OpenEdX.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.releasestage.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.releasestage.xcconfig"; sourceTree = ""; }; + E0DB1212DA83993A05C5D9A1 /* Pods-App-OpenEdX.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.debugstage.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.debugstage.xcconfig"; sourceTree = ""; }; + E2811A5681E667E01535CD97 /* Pods-App-OpenEdX.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.releaseprod.xcconfig"; sourceTree = ""; }; + E4DE2FEECF2520F879B2256F /* Pods-App-OpenEdX.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.debugprodtenants.xcconfig"; sourceTree = ""; }; + ED2771DE2F5BBBC2214103B2 /* Pods-App-OpenEdX.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-OpenEdX.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-OpenEdX/Pods-App-OpenEdX.openedxmultitenants.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -177,6 +182,8 @@ CEBA52772CEBB69100619E2B /* OEXFirebaseAnalytics in Frameworks */, 027DB33028D8A063002B6862 /* Dashboard.framework in Frameworks */, 3ACA3A1E886F3F9B2735B9AF /* Pods_App_OpenEdX.framework in Frameworks */, + BC6BEB793EF3687D2C5E1D9B /* Pods_App_OpenEdX.framework in Frameworks */, + 628ABA79268BC03EC141D7E5 /* Pods_App_OpenEdX.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -234,6 +241,7 @@ 07D5DA3228D075AA00752FD9 /* Products */, 55A895025FB07897BA68E063 /* Pods */, 4E6FB43543890E90BB88D64D /* Frameworks */, + 9972D1D32E60338C0020CFBD /* OpenEdX MultiTenants-Info.plist */, ); sourceTree = ""; }; @@ -290,12 +298,14 @@ 55A895025FB07897BA68E063 /* Pods */ = { isa = PBXGroup; children = ( - D70D30110012B7D52D05E876 /* Pods-App-OpenEdX.debugprod.xcconfig */, - 8A45E2C9AF0CBE70A09FB37B /* Pods-App-OpenEdX.debugstage.xcconfig */, - CCE1E0F850D3E25C0D6C6702 /* Pods-App-OpenEdX.debugdev.xcconfig */, - 4449C4D4F119C87B452DDFCD /* Pods-App-OpenEdX.releaseprod.xcconfig */, - FD0CE8D22B755B4003A113BB /* Pods-App-OpenEdX.releasestage.xcconfig */, - 005D1F4D92679D24B3BAA8FE /* Pods-App-OpenEdX.releasedev.xcconfig */, + 2386FD6B3D624DEF6AFB238C /* Pods-App-OpenEdX.debugprod.xcconfig */, + E0DB1212DA83993A05C5D9A1 /* Pods-App-OpenEdX.debugstage.xcconfig */, + 83C62BF15B02F75D4E5C4EBA /* Pods-App-OpenEdX.debugdev.xcconfig */, + E2811A5681E667E01535CD97 /* Pods-App-OpenEdX.releaseprod.xcconfig */, + 2970FF3233FBA54F18D84830 /* Pods-App-OpenEdX.releasestage.xcconfig */, + 7FF58E06BF82C5F521F6AE4B /* Pods-App-OpenEdX.releasedev.xcconfig */, + ED2771DE2F5BBBC2214103B2 /* Pods-App-OpenEdX.openedxmultitenants.xcconfig */, + E4DE2FEECF2520F879B2256F /* Pods-App-OpenEdX.debugprodtenants.xcconfig */, ); path = Pods; sourceTree = ""; @@ -550,7 +560,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#!/bin/bash\n\nVENV_PATH=\"${SRCROOT}/venv\"\n\n/usr/bin/python3 -m venv \"$VENV_PATH\"\n\nsource \"$VENV_PATH/bin/activate\"\n\npip install --upgrade pip\npip install PyYAML\n\nscheme_mapping='{\n \"prod\": [\"ReleaseProd\", \"DebugProd\"],\n \"stage\": [\"ReleaseStage\", \"DebugStage\"],\n \"dev\": [\"ReleaseDev\", \"DebugDev\"]\n}'\n\npython config_script/process_config.py \"$CONFIGURATION\" \"$scheme_mapping\"\n\ndeactivate\n"; + shellScript = "#!/bin/bash\n\nVENV_PATH=\"${SRCROOT}/venv\"\n\n/usr/bin/python3 -m venv \"$VENV_PATH\"\n\nsource \"$VENV_PATH/bin/activate\"\n\npip install --upgrade pip\npip install PyYAML\n\nscheme_mapping='{\n \"prod\": [\"ReleaseProd\", \"DebugProd\"],\n \"stage\": [\"ReleaseStage\", \"DebugStage\"],\n \"dev\": [\"ReleaseDev\", \"DebugDev\"],\n \"tenants\": [\"DebugProdTenants\", \"OpenEdXMultiTenants\"]\n}'\n\npython config_script/process_config.py \"$CONFIGURATION\" \"$scheme_mapping\"\n\ndeactivate\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -694,18 +704,19 @@ }; 02DD1C9629E80CC200F35DCE /* DebugStage */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 8A45E2C9AF0CBE70A09FB37B /* Pods-App-OpenEdX.debugstage.xcconfig */; + baseConfigurationReference = E0DB1212DA83993A05C5D9A1 /* Pods-App-OpenEdX.debugstage.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = WKRCK9V34F; FULLSTORY_ENABLED = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = OpenEdX/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; @@ -718,8 +729,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.stage; + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.stage.rawan; PRODUCT_NAME = "$(TARGET_NAME) Stage"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -786,18 +797,19 @@ }; 02DD1C9829E80CCB00F35DCE /* ReleaseStage */ = { isa = XCBuildConfiguration; - baseConfigurationReference = FD0CE8D22B755B4003A113BB /* Pods-App-OpenEdX.releasestage.xcconfig */; + baseConfigurationReference = 2970FF3233FBA54F18D84830 /* Pods-App-OpenEdX.releasestage.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = WKRCK9V34F; FULLSTORY_ENABLED = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = OpenEdX/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; @@ -810,8 +822,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.stage; + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.stage.rawan; PRODUCT_NAME = "$(TARGET_NAME) Stage"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -884,18 +896,19 @@ }; 0727875928D231FD002E9142 /* DebugDev */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CCE1E0F850D3E25C0D6C6702 /* Pods-App-OpenEdX.debugdev.xcconfig */; + baseConfigurationReference = 83C62BF15B02F75D4E5C4EBA /* Pods-App-OpenEdX.debugdev.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = WKRCK9V34F; FULLSTORY_ENABLED = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = OpenEdX/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; @@ -908,8 +921,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.dev; + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.dev.rawan; PRODUCT_NAME = "$(TARGET_NAME) Dev"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -976,18 +989,19 @@ }; 0727875B28D23204002E9142 /* ReleaseDev */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 005D1F4D92679D24B3BAA8FE /* Pods-App-OpenEdX.releasedev.xcconfig */; + baseConfigurationReference = 7FF58E06BF82C5F521F6AE4B /* Pods-App-OpenEdX.releasedev.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = WKRCK9V34F; FULLSTORY_ENABLED = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = OpenEdX/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; @@ -1000,8 +1014,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.dev; + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.dev.rawan; PRODUCT_NAME = "$(TARGET_NAME) Dev"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -1128,18 +1142,19 @@ }; 07D5DA4628D075AB00752FD9 /* DebugProd */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D70D30110012B7D52D05E876 /* Pods-App-OpenEdX.debugprod.xcconfig */; + baseConfigurationReference = 2386FD6B3D624DEF6AFB238C /* Pods-App-OpenEdX.debugprod.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = WKRCK9V34F; FULLSTORY_ENABLED = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = OpenEdX/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; @@ -1152,8 +1167,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app; + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.rawan; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -1166,18 +1181,19 @@ }; 07D5DA4728D075AB00752FD9 /* ReleaseProd */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 4449C4D4F119C87B452DDFCD /* Pods-App-OpenEdX.releaseprod.xcconfig */; + baseConfigurationReference = E2811A5681E667E01535CD97 /* Pods-App-OpenEdX.releaseprod.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = WKRCK9V34F; FULLSTORY_ENABLED = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = OpenEdX/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; @@ -1190,8 +1206,8 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app; + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.rawan; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; @@ -1202,6 +1218,200 @@ }; name = ReleaseProd; }; + 995886972E64453D0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = DebugProdTenants; + }; + 995886982E64453D0065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E4DE2FEECF2520F879B2256F /* Pods-App-OpenEdX.debugprodtenants.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = WKRCK9V34F; + FULLSTORY_ENABLED = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = OpenEdX/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; + INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIStatusBarStyle = UIStatusBarStyleLightContent; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.rawan; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = TENANTS; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1D42E6033EF0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1D52E6033EF0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ED2771DE2F5BBBC2214103B2 /* Pods-App-OpenEdX.openedxmultitenants.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = WKRCK9V34F; + FULLSTORY_ENABLED = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = OpenEdX/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = ""; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; + INFOPLIST_KEY_NSCalendarsUsageDescription = "We would like to utilize your calendar list to subscribe you to your personalized calendar for this course."; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Allow access to your photo library so you can save photos in your gallery."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIStatusBarStyle = UIStatusBarStyleLightContent; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 2; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.rawan; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = TENANTS; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1209,9 +1419,11 @@ isa = XCConfigurationList; buildConfigurations = ( 07D5DA4328D075AB00752FD9 /* DebugProd */, + 9972D1D42E6033EF0020CFBD /* OpenEdXMultiTenants */, 02DD1C9529E80CC200F35DCE /* DebugStage */, 0727875828D231FD002E9142 /* DebugDev */, 07D5DA4428D075AB00752FD9 /* ReleaseProd */, + 995886972E64453D0065D132 /* DebugProdTenants */, 02DD1C9729E80CCB00F35DCE /* ReleaseStage */, 0727875A28D23204002E9142 /* ReleaseDev */, ); @@ -1222,9 +1434,11 @@ isa = XCConfigurationList; buildConfigurations = ( 07D5DA4628D075AB00752FD9 /* DebugProd */, + 9972D1D52E6033EF0020CFBD /* OpenEdXMultiTenants */, 02DD1C9629E80CC200F35DCE /* DebugStage */, 0727875928D231FD002E9142 /* DebugDev */, 07D5DA4728D075AB00752FD9 /* ReleaseProd */, + 995886982E64453D0065D132 /* DebugProdTenants */, 02DD1C9829E80CCB00F35DCE /* ReleaseStage */, 0727875B28D23204002E9142 /* ReleaseDev */, ); diff --git a/OpenEdX.xcodeproj/xcshareddata/xcschemes/OpenEdXTenants.xcscheme b/OpenEdX.xcodeproj/xcshareddata/xcschemes/OpenEdXTenants.xcscheme new file mode 100644 index 000000000..48f0f6fd7 --- /dev/null +++ b/OpenEdX.xcodeproj/xcshareddata/xcschemes/OpenEdXTenants.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenEdX/AppDelegate.swift b/OpenEdX/AppDelegate.swift index ae0ce7841..0ac43cddc 100644 --- a/OpenEdX/AppDelegate.swift +++ b/OpenEdX/AppDelegate.swift @@ -35,6 +35,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private var assembler: Assembler? private var lastForceLogoutTime: TimeInterval = 0 + let dbProvider = DatabaseManagerProvider() func application( _ application: UIApplication, @@ -95,6 +96,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { object: nil ) + NotificationCenter.default.addObserver( + self, + selector: #selector(handleTenantChange(_:)), + name: .tenantDidChange, + object: nil + ) return true } @@ -162,6 +169,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private func initDI() { let navigation = UINavigationController() navigation.modalPresentationStyle = .fullScreen + navigation.navigationBar.standardAppearance.configureWithOpaqueBackground() + navigation.navigationBar.standardAppearance.backgroundColor = + UIColor(Theme.Colors.navigationBarColor) + navigation.navigationBar.standardAppearance + .titleTextAttributes = + [.foregroundColor: UIColor(Theme.Colors.navigationBarTintColor)] + + navigation.navigationBar.standardAppearance + .largeTitleTextAttributes = + [.foregroundColor: UIColor(Theme.Colors.navigationBarTintColor)] + + NavigationAppearanceManager.shared.navigationController = navigation assembler = Assembler( [ @@ -270,4 +289,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { debugLog("Could not schedule app refresh: \(error)") } } + + @objc func handleTenantChange(_ notification: Notification) { + guard let tenant = notification.userInfo?["tenant"] as? Tenant else { return } + dbProvider.resetContainer(for: tenant.name) + } } diff --git a/OpenEdX/DI/AppAssembly.swift b/OpenEdX/DI/AppAssembly.swift index f90b6a500..2d1095bc1 100644 --- a/OpenEdX/DI/AppAssembly.swift +++ b/OpenEdX/DI/AppAssembly.swift @@ -39,6 +39,23 @@ class AppAssembly: Assembly { self.pluginManager }.inObjectScope(.container) + // Multi-Tenant + container.register(TenantViewModel.self) { r in + TenantViewModel( + router: r.resolve(AuthorizationRouter.self)!, + config: r.resolve(ConfigProtocol.self)!, + analytics: r.resolve(AuthorizationAnalytics.self)!, + storage: r.resolve(CoreStorage.self)! + ) + } + .inObjectScope(.container) + + // Make TenantProvider resolve to TenantViewModel + container.register(TenantProvider.self) { r in + r.resolve(TenantViewModel.self)! + } + .inObjectScope(.container) + container.register(Router.self) { @MainActor r in Router(navigationController: r.resolve(UINavigationController.self)!, container: container) } @@ -91,16 +108,19 @@ class AppAssembly: Assembly { Connectivity() } - container.register(DatabaseManager.self) { _ in - DatabaseManager(databaseName: "Database") + container.register(DatabaseManagerProvider.self) { _ in + DatabaseManagerProvider() }.inObjectScope(.container) container.register(CoreDataHandlerProtocol.self) { r in - r.resolve(DatabaseManager.self)! + let tenantVM = r.resolve(TenantViewModel.self)! + return r.resolve(DatabaseManagerProvider.self)!.manager(for: tenantVM) }.inObjectScope(.container) - + container.register(CorePersistenceProtocol.self) { r in - CorePersistence(container: r.resolve(DatabaseManager.self)!.getPersistentContainer()) + let tenantVM = r.resolve(TenantViewModel.self)! + let container = r.resolve(DatabaseManagerProvider.self)!.manager(for: tenantVM).getPersistentContainer() + return CorePersistence(container: container) }.inObjectScope(.container) container.register(DownloadManagerProtocol.self) { @MainActor r in @@ -148,9 +168,9 @@ class AppAssembly: Assembly { }.inObjectScope(.container) container.register(CSSInjector.self) { r in - CSSInjector( - config: r.resolve(ConfigProtocol.self)! - ) + CSSInjector(config: r.resolve(ConfigProtocol.self)!, + tenantProvider: r.resolve(TenantProvider.self)! + ) }.inObjectScope(.container) container.register(KeychainSwift.self) { _ in @@ -206,13 +226,13 @@ class AppAssembly: Assembly { }.inObjectScope(.container) container.register(CalendarManagerProtocol.self) { @MainActor r in - CalendarManager( - persistence: r.resolve(ProfilePersistenceProtocol.self)!, + let tenantVM = r.resolve(TenantViewModel.self)! + return CalendarManager( + persistence: r.resolve(ProfilePersistenceProtocol.self, argument: tenantVM)!, interactor: r.resolve(ProfileInteractorProtocol.self)!, profileStorage: r.resolve(ProfileStorage.self)! ) - } - .inObjectScope(.container) + }.inObjectScope(.container) container.register(DeepLinkManager.self) { @MainActor r in DeepLinkManager( diff --git a/OpenEdX/DI/NetworkAssembly.swift b/OpenEdX/DI/NetworkAssembly.swift index 904c1ea44..1e11c0e8c 100644 --- a/OpenEdX/DI/NetworkAssembly.swift +++ b/OpenEdX/DI/NetworkAssembly.swift @@ -9,12 +9,15 @@ import Foundation import Core import OEXFoundation import Alamofire -import Swinject +@preconcurrency import Swinject +import Authorization class NetworkAssembly: Assembly { func assemble(container: Container) { container.register(RequestInterceptor.self) { r in - RequestInterceptor(config: r.resolve(ConfigProtocol.self)!, storage: r.resolve(CoreStorage.self)!) + RequestInterceptor(config: r.resolve(ConfigProtocol.self)!, + storage: r.resolve(CoreStorage.self)!, + tenantProvider: { r.resolve(TenantProvider.self)! }) }.inObjectScope(.container) container.register(Alamofire.Session.self) { r in @@ -38,8 +41,18 @@ class NetworkAssembly: Assembly { ) }.inObjectScope(.container) - container.register(API.self) {r in - API(session: r.resolve(Alamofire.Session.self)!, baseURL: r.resolve(ConfigProtocol.self)!.baseURL) + container.register(RequestInterceptor.self) { r in + RequestInterceptor(config: r.resolve(ConfigProtocol.self)!, + storage: r.resolve(CoreStorage.self)!, + tenantProvider: { r.resolve(TenantViewModel.self)! }) + }.inObjectScope(.container) + + container.register(API.self) { r in + let tenantVM = r.resolve(TenantViewModel.self)! + return API( + session: r.resolve(Alamofire.Session.self)!, + baseURL: tenantVM.baseURL + ) }.inObjectScope(.container) } } diff --git a/OpenEdX/DI/ScreenAssembly.swift b/OpenEdX/DI/ScreenAssembly.swift index 697d238db..5c003485e 100644 --- a/OpenEdX/DI/ScreenAssembly.swift +++ b/OpenEdX/DI/ScreenAssembly.swift @@ -39,7 +39,8 @@ class ScreenAssembly: Assembly { OfflineSyncManager( persistence: r.resolve(CorePersistenceProtocol.self)!, interactor: r.resolve(OfflineSyncInteractorProtocol.self)!, - connectivity: r.resolve(ConnectivityProtocol.self)! + connectivity: r.resolve(ConnectivityProtocol.self)!, + tenantProvider: { r.resolve(TenantProvider.self)! } ) } @@ -48,9 +49,11 @@ class ScreenAssembly: Assembly { AuthRepository( api: r.resolve(API.self)!, appStorage: r.resolve(CoreStorage.self)!, - config: r.resolve(ConfigProtocol.self)! + config: r.resolve(ConfigProtocol.self)!, + tenantProvider: { r.resolve(TenantProvider.self)! } ) - } + }.inObjectScope(.container) + container.register(AuthInteractorProtocol.self) { r in AuthInteractor( repository: r.resolve(AuthRepositoryProtocol.self)! @@ -90,7 +93,8 @@ class ScreenAssembly: Assembly { analytics: r.resolve(AuthorizationAnalytics.self)!, validator: r.resolve(Validator.self)!, storage: r.resolve(CoreStorage.self)!, - sourceScreen: sourceScreen + sourceScreen: sourceScreen, + tenantProvider: { r.resolve(TenantProvider.self)! } ) } container.register(SSOWebViewModel.self) { @MainActor r in @@ -99,7 +103,8 @@ class ScreenAssembly: Assembly { router: r.resolve(AuthorizationRouter.self)!, config: r.resolve(ConfigProtocol.self)!, analytics: r.resolve(AuthorizationAnalytics.self)!, - ssoHelper: r.resolve(SSOHelper.self)! + ssoHelper: r.resolve(SSOHelper.self)!, + tenantProvider: { r.resolve(TenantProvider.self)! } ) } container.register(SignUpViewModel.self) { @MainActor r, sourceScreen in @@ -124,16 +129,22 @@ class ScreenAssembly: Assembly { } // MARK: Discovery - container.register(DiscoveryPersistenceProtocol.self) { r in - return DiscoveryPersistence(container: r.resolve(DatabaseManager.self)!.getPersistentContainer()) - } - + container.register(DiscoveryPersistenceProtocol.self) { (r: Resolver, tenantViewModel: TenantViewModel) in + let provider = r.resolve(DatabaseManagerProvider.self)! + let dbManager = provider.manager(for: tenantViewModel) + return DiscoveryPersistence(container: dbManager.getPersistentContainer()) + }.inObjectScope(.transient) + container.register(DiscoveryRepositoryProtocol.self) { r in - DiscoveryRepository( + let tenantVM = r.resolve(TenantViewModel.self)! + let persistence = r.resolve(DiscoveryPersistenceProtocol.self, argument: tenantVM) + + return DiscoveryRepository( api: r.resolve(API.self)!, appStorage: r.resolve(CoreStorage.self)!, config: r.resolve(ConfigProtocol.self)!, - persistence: r.resolve(DiscoveryPersistenceProtocol.self)! + persistence: persistence!, + tenantProvider: { r.resolve(TenantViewModel.self)! } ) } container.register(DiscoveryInteractorProtocol.self) { r in @@ -187,16 +198,20 @@ class ScreenAssembly: Assembly { } // MARK: Dashboard - container.register(DashboardPersistenceProtocol.self) { r in - DashboardPersistence(container: r.resolve(DatabaseManager.self)!.getPersistentContainer()) - } + container.register(DashboardPersistenceProtocol.self) { (r: Resolver, tenantViewModel: TenantViewModel) in + let provider = r.resolve(DatabaseManagerProvider.self)! + let dbManager = provider.manager(for: tenantViewModel) + return DashboardPersistence(container: dbManager.getPersistentContainer()) + }.inObjectScope(.transient) container.register(DashboardRepositoryProtocol.self) { r in DashboardRepository( api: r.resolve(API.self)!, storage: r.resolve(CoreStorage.self)!, config: r.resolve(ConfigProtocol.self)!, - persistence: r.resolve(DashboardPersistenceProtocol.self)! + persistence: r.resolve(DashboardPersistenceProtocol.self, + argument: r.resolve(TenantViewModel.self)!)!, + tenantProvider: { r.resolve(TenantViewModel.self)! } ) } container.register(DashboardInteractorProtocol.self) { r in @@ -235,20 +250,23 @@ class ScreenAssembly: Assembly { // MARK: Profile - // MARK: Course - container.register(ProfilePersistenceProtocol.self) { r in - ProfilePersistence(container: r.resolve(DatabaseManager.self)!.getPersistentContainer()) - } - + container.register(ProfilePersistenceProtocol.self) { (r: Resolver, tenantViewModel: TenantViewModel) in + let provider = r.resolve(DatabaseManagerProvider.self)! + let dbManager = provider.manager(for: tenantViewModel) + return ProfilePersistence(container: dbManager.getPersistentContainer()) + }.inObjectScope(.transient) + container.register(ProfileRepositoryProtocol.self) { r in ProfileRepository( api: r.resolve(API.self)!, storage: r.resolve(AppStorage.self)!, coreDataHandler: r.resolve(CoreDataHandlerProtocol.self)!, downloadManager: r.resolve(DownloadManagerProtocol.self)!, - config: r.resolve(ConfigProtocol.self)! + config: r.resolve(ConfigProtocol.self)!, + tenantProvider: { r.resolve(TenantViewModel.self)! } ) - } + }.inObjectScope(.container) + container.register(ProfileInteractorProtocol.self) { r in ProfileInteractor( repository: r.resolve(ProfileRepositoryProtocol.self)! @@ -282,7 +300,8 @@ class ScreenAssembly: Assembly { config: r.resolve(ConfigProtocol.self)!, corePersistence: r.resolve(CorePersistenceProtocol.self)!, connectivity: r.resolve(ConnectivityProtocol.self)!, - coreStorage: r.resolve(AppStorage.self)! + coreStorage: r.resolve(AppStorage.self)!, + tenantProvider: { r.resolve(TenantProvider.self)! } ) } @@ -318,10 +337,12 @@ class ScreenAssembly: Assembly { } // MARK: Course - container.register(CoursePersistenceProtocol.self) { r in - CoursePersistence(container: r.resolve(DatabaseManager.self)!.getPersistentContainer()) - } - + container.register(CoursePersistenceProtocol.self) { (r: Resolver, tenantViewModel: TenantViewModel) in + let provider = r.resolve(DatabaseManagerProvider.self)! + let dbManager = provider.manager(for: tenantViewModel) + return CoursePersistence(container: dbManager.getPersistentContainer()) + }.inObjectScope(.transient) + container.register(CourseDetailsViewModel.self) { @MainActor r in CourseDetailsViewModel( interactor: r.resolve(DiscoveryInteractorProtocol.self)!, @@ -355,7 +376,8 @@ class ScreenAssembly: Assembly { lastVisitedBlockID: lastVisitedBlockID, coreAnalytics: r.resolve(CoreAnalytics.self)!, selection: selection, - courseHelper: r.resolve(CourseDownloadHelperProtocol.self)! + courseHelper: r.resolve(CourseDownloadHelperProtocol.self)!, + tenantProvider: { r.resolve(TenantProvider.self)! } ) } container.register( @@ -399,7 +421,8 @@ class ScreenAssembly: Assembly { WebUnitViewModel( authInteractor: r.resolve(AuthInteractorProtocol.self)!, config: r.resolve(ConfigProtocol.self)!, - syncManager: r.resolve(OfflineSyncManagerProtocol.self)! + syncManager: r.resolve(OfflineSyncManagerProtocol.self)!, + tenantProvider: { r.resolve(TenantProvider.self)! } ) } container.register( @@ -635,11 +658,14 @@ class ScreenAssembly: Assembly { } container.register(CourseRepositoryProtocol.self) { r in - CourseRepository( + let tenantVM = r.resolve(TenantViewModel.self)! + let persistence = r.resolve(CoursePersistenceProtocol.self, argument: tenantVM)! + return CourseRepository( api: r.resolve(API.self)!, coreStorage: r.resolve(CoreStorage.self)!, config: r.resolve(ConfigProtocol.self)!, - persistence: r.resolve(CoursePersistenceProtocol.self)! + persistence: persistence, + tenantProvider: { r.resolve(TenantViewModel.self)! } ) } container.register(CourseInteractorProtocol.self) { r in @@ -658,16 +684,20 @@ class ScreenAssembly: Assembly { // MARK: Downloads - container.register(DownloadsPersistenceProtocol.self) { r in - DownloadsPersistence(container: r.resolve(DatabaseManager.self)!.getPersistentContainer()) - } - + container.register(DownloadsPersistenceProtocol.self) { (r: Resolver, tenantViewModel: TenantViewModel) in + let provider = r.resolve(DatabaseManagerProvider.self)! + let dbManager = provider.manager(for: tenantViewModel) + return DownloadsPersistence(container: dbManager.getPersistentContainer()) + }.inObjectScope(.transient) + container.register(DownloadsRepositoryProtocol.self) { r in DownloadsRepository( api: r.resolve(API.self)!, coreStorage: r.resolve(CoreStorage.self)!, config: r.resolve(ConfigProtocol.self)!, - persistence: r.resolve(DownloadsPersistenceProtocol.self)! + persistence: r.resolve(DownloadsPersistenceProtocol.self, + argument: r.resolve(TenantViewModel.self)!)!, + tenantProvider: { r.resolve(TenantViewModel.self)! } ) } diff --git a/OpenEdX/Data/DatabaseManager.swift b/OpenEdX/Data/DatabaseManager.swift index 567f580c7..fb91d6cdc 100644 --- a/OpenEdX/Data/DatabaseManager.swift +++ b/OpenEdX/Data/DatabaseManager.swift @@ -13,6 +13,26 @@ import Dashboard import Course import Downloads import Profile +import Authorization + +final class DatabaseManagerProvider { + private var containers: [String: DatabaseManager] = [:] + + func manager(for tenant: TenantViewModel) -> DatabaseManager { + let key = tenant.selectedTenant?.name ?? "default" + if let existingManager = containers[key] { + return existingManager + } + let dbName = "openedx_\(key)_db" + let newManager = DatabaseManager(databaseName: dbName) + containers[key] = newManager + return newManager + } + + public func resetContainer(for tenantName: String) { + containers[tenantName] = nil + } +} final class DatabaseManager: CoreDataHandlerProtocol { diff --git a/OpenEdX/Info.plist b/OpenEdX/Info.plist index e9bd32e58..ce702e73a 100644 --- a/OpenEdX/Info.plist +++ b/OpenEdX/Info.plist @@ -14,8 +14,6 @@ FirebaseCrashlyticsCollectionEnabled - ITSAppUsesNonExemptEncryption - LSApplicationQueriesSchemes googlegmail diff --git a/OpenEdX/RouteController.swift b/OpenEdX/RouteController.swift index f9a377ffe..8dd95665e 100644 --- a/OpenEdX/RouteController.swift +++ b/OpenEdX/RouteController.swift @@ -11,6 +11,7 @@ import Core import Authorization import WhatsNew import Swinject +import Theme class RouteController: UIViewController { @@ -38,6 +39,7 @@ class RouteController: UIViewController { DispatchQueue.main.async { self.showMainOrWhatsNewScreen() } + ThemeManager.shared.applyTheme(for: "", localizedName: "") } else { DispatchQueue.main.async { self.showStartupScreen() @@ -55,15 +57,27 @@ class RouteController: UIViewController { navigation.viewControllers = [controller] present(navigation, animated: false) } else { - let controller = UIHostingController( - rootView: SignInView( - viewModel: diContainer.resolve( - SignInViewModel.self, - argument: LogistrationSourceScreen.default - )! + guard let viewModel = Container.shared.resolve( + TenantViewModel.self + ) else { return } + if viewModel.config.tenantsConfig.tenants.count > 1 { + let controller = UIHostingController( + rootView: TenantContentView(viewModel: viewModel) + .environmentObject(ThemeManager.shared) ) - ) - navigation.viewControllers = [controller] + navigation.viewControllers = [controller] + } else { + let controller = UIHostingController( + rootView: SignInView( + viewModel: diContainer.resolve( + SignInViewModel.self, + argument: LogistrationSourceScreen.default + )!, tenantViewModel: viewModel + ) + .environmentObject(ThemeManager.shared) + ) + navigation.viewControllers = [controller] + } present(navigation, animated: false) } } @@ -88,7 +102,7 @@ class RouteController: UIViewController { router: Container.shared.resolve(WhatsNewRouter.self)!, viewModel: viewModel ) - let controller = UIHostingController(rootView: whatsNewView) + let controller = UIHostingController(rootView: whatsNewView.environmentObject(ThemeManager.shared)) navigation.viewControllers = [controller] } else { let postLoginDataDefault: PostLoginData? = PostLoginData() @@ -97,7 +111,9 @@ class RouteController: UIViewController { arguments: LogistrationSourceScreen.default, postLoginDataDefault )! - let controller = UIHostingController(rootView: MainScreenView(viewModel: viewModel)) + let controller = UIHostingController(rootView: MainScreenView(viewModel: viewModel) + .environmentObject(ThemeManager.shared) + ) navigation.viewControllers = [controller] } present(navigation, animated: false) diff --git a/OpenEdX/Router.swift b/OpenEdX/Router.swift index 919eb253a..1aba1630b 100644 --- a/OpenEdX/Router.swift +++ b/OpenEdX/Router.swift @@ -19,6 +19,7 @@ import Downloads import Profile import WhatsNew import Combine +import Theme // swiftlint:disable type_body_length file_length public class Router: AuthorizationRouter, @@ -95,7 +96,7 @@ public class Router: AuthorizationRouter, if let jsonVersion = viewModel.getVersion() { whatsNewStorage.whatsNewVersion = jsonVersion } - let controller = UIHostingController(rootView: whatsNew) + let controller = UIHostingController(rootView: whatsNew.environmentObject(ThemeManager.shared)) navigationController.viewControllers = [controller] navigationController.setViewControllers([controller], animated: true) } else { @@ -105,7 +106,10 @@ public class Router: AuthorizationRouter, postLoginData )! - let controller = UIHostingController(rootView: MainScreenView(viewModel: viewModel)) + let controller = UIHostingController(rootView: + MainScreenView(viewModel: viewModel) + .environmentObject(ThemeManager.shared) + ) navigationController.viewControllers = [controller] navigationController.setViewControllers([controller], animated: true) if case .courseDetail = sourceScreen { @@ -114,16 +118,41 @@ public class Router: AuthorizationRouter, } } + public func showLearningCenter() { + guard let viewModel = Container.shared.resolve( + TenantViewModel.self + ) else { return } + + let view = TenantContentView(viewModel: viewModel, isSwitchTenant: true) + + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) + navigationController.pushViewController(controller, animated: true) + } + public func showTenantScreen(sourceScreen: LogistrationSourceScreen) { + guard let viewModel = Container.shared.resolve(TenantViewModel.self) + else { return } + + let view = TenantSelectionView(viewModel: viewModel) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) + navigationController.pushViewController(controller, animated: true) + + } + public func showLoginScreen(sourceScreen: LogistrationSourceScreen) { guard let viewModel = Container.shared.resolve( SignInViewModel.self, argument: sourceScreen + ), let tenantViewModel = Container.shared.resolve( + TenantViewModel.self ), let authAnalytics = Container.shared.resolve( AuthorizationAnalytics.self ) else { return } - let view = SignInView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let view = SignInView(viewModel: viewModel, tenantViewModel: tenantViewModel) + let controller = UIHostingController(rootView: + view + .environmentObject(ThemeManager.shared) + .environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) authAnalytics.signInClicked() @@ -132,17 +161,31 @@ public class Router: AuthorizationRouter, public func showStartupScreen() { if let config = Container.shared.resolve(ConfigProtocol.self), config.features.startupScreenEnabled { let view = StartupView(viewModel: Container.shared.resolve(StartupViewModel.self)!) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.setViewControllers([controller], animated: true) } else { - let view = SignInView( - viewModel: Container.shared.resolve( - SignInViewModel.self, - argument: LogistrationSourceScreen.default - )! - ) - let controller = UIHostingController(rootView: view) - navigationController.setViewControllers([controller], animated: false) + + guard let viewModel = Container.shared.resolve( + TenantViewModel.self + ) else { return } + + if viewModel.config.tenantsConfig.tenants.count > 1 { + let controller = UIHostingController( + rootView: TenantContentView(viewModel: viewModel) + .environmentObject(ThemeManager.shared) + ) + navigationController.setViewControllers([controller], animated: false) + } else { + let view = SignInView( + viewModel: Container.shared.resolve( + SignInViewModel.self, + argument: LogistrationSourceScreen.default + )!, tenantViewModel: Container.shared.resolve(TenantViewModel.self)! + ) + .environmentObject(ThemeManager.shared) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) + navigationController.setViewControllers([controller], animated: false) + } } } @@ -153,7 +196,10 @@ public class Router: AuthorizationRouter, let analytics = Container.shared.resolve(CoreAnalytics.self), connectivity.isInternetAvaliable else { return } - let vm = AppReviewViewModel(config: config, storage: storage, analytics: analytics) + let vm = AppReviewViewModel(config: config, + storage: storage, + analytics: analytics, + tenantProvider: { Container.shared.resolve(TenantProvider.self)! }) if vm.shouldShowRatingView() { presentView( transitionStyle: .crossDissolve, @@ -229,8 +275,14 @@ public class Router: AuthorizationRouter, AuthorizationAnalytics.self ) else { return } + if let tenantViewModel = Container.shared.resolve( + TenantViewModel.self + ), let selectedTenant = tenantViewModel.selectedTenant { + viewModel.selectedTenant = selectedTenant + } + let view = SignUpView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) authAnalytics.registerClicked() @@ -238,7 +290,7 @@ public class Router: AuthorizationRouter, public func showForgotPasswordScreen() { let view = ResetPasswordView(viewModel: Container.shared.resolve(ResetPasswordViewModel.self)!) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -248,7 +300,7 @@ public class Router: AuthorizationRouter, courseID: courseID, title: title ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -267,7 +319,7 @@ public class Router: AuthorizationRouter, ) DispatchQueue.main.async { [weak self] in - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) self?.navigationController.pushViewController(controller, animated: true) } } @@ -282,7 +334,7 @@ public class Router: AuthorizationRouter, viewType: viewType, pathID: pathID ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -290,7 +342,7 @@ public class Router: AuthorizationRouter, let viewModel = Container.shared.resolve(SearchViewModel.self)! let view = SearchView(viewModel: viewModel, searchQuery: searchQuery) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushFade(viewController: controller) } @@ -303,7 +355,7 @@ public class Router: AuthorizationRouter, searchQuery: searchQuery, sourceScreen: sourceScreen ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } else if config?.discovery.type == .webview { let view = DiscoveryWebview( @@ -315,7 +367,7 @@ public class Router: AuthorizationRouter, searchQuery: searchQuery ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } } @@ -325,7 +377,7 @@ public class Router: AuthorizationRouter, let view = DiscussionSearchTopicsView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushFade(viewController: controller) } @@ -454,7 +506,7 @@ public class Router: AuthorizationRouter, public func showAllCourses(courses: [CourseItem]) { let vm = Container.shared.resolve(AllCoursesViewModel.self)! let view = AllCoursesView(viewModel: vm, router: self) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -472,7 +524,7 @@ public class Router: AuthorizationRouter, cssInjector: cssInjector, type: type ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -517,10 +569,13 @@ public class Router: AuthorizationRouter, verticalIndex )! - let config = Container.shared.resolve(ConfigProtocol.self) + let config = Container.shared.resolve( + ConfigProtocol.self) let isDropdownActive = config?.uiComponents.courseDropDownNavigationEnabled ?? false - let view = CourseUnitView(viewModel: viewModel, isDropdownActive: isDropdownActive) + let view = CourseUnitView( + viewModel: viewModel, + isDropdownActive: isDropdownActive) return UIHostingController(rootView: view) } @@ -660,7 +715,7 @@ public class Router: AuthorizationRouter, router: router, isBlackedOut: isBlackedOut ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: animated) } @@ -695,7 +750,7 @@ public class Router: AuthorizationRouter, parentComment: parentComment, isBlackedOut: isBlackedOut ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: animated) } @@ -711,7 +766,7 @@ public class Router: AuthorizationRouter, courseID: courseID, onPostCreated: onPostCreated ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -721,7 +776,7 @@ public class Router: AuthorizationRouter, let vm = UserProfileViewModel(interactor: interactor, username: username) let view = UserProfileView(viewModel: vm) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -736,14 +791,14 @@ public class Router: AuthorizationRouter, avatar: avatar, profileDidEdit: profileDidEdit ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } public func showSettings() { let viewModel = Container.shared.resolve(SettingsViewModel.self)! let view = SettingsView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -765,34 +820,34 @@ public class Router: AuthorizationRouter, view = AnyView(SyncCalendarOptionsView(viewModel: viewModel)) } - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } public func showSyncCalendarOptions() { let viewModel = Container.shared.resolve(DatesAndCalendarViewModel.self)! let view = SyncCalendarOptionsView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } public func showCoursesToSync() { let viewModel = Container.shared.resolve(DatesAndCalendarViewModel.self)! let view = CoursesToSyncView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } public func showManageAccount() { let viewModel = Container.shared.resolve(ManageAccountViewModel.self)! let view = ManageAccountView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } public func showVideoQualityView(viewModel: SettingsViewModel) { let view = VideoQualityView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -807,7 +862,7 @@ public class Router: AuthorizationRouter, analytics: analytics, router: self ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -826,7 +881,7 @@ public class Router: AuthorizationRouter, let viewModel = Container.shared.resolve(DeleteAccountViewModel.self)! let view = DeleteAccountView(viewModel: viewModel) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } @@ -836,7 +891,7 @@ public class Router: AuthorizationRouter, config: Container.shared.resolve(ConfigProtocol.self)!, showAccountLink: showAccountLink ) - let controller = UIHostingController(rootView: view) + let controller = UIHostingController(rootView: view.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: false) } @@ -847,7 +902,7 @@ public class Router: AuthorizationRouter, private func prepareToPresent (_ toPresent: ToPresent, transitionStyle: UIModalTransitionStyle) -> UIViewController { - let hosting = UIHostingController(rootView: toPresent) + let hosting = UIHostingController(rootView: toPresent.environmentObject(ThemeManager.shared)) hosting.view.backgroundColor = .clear hosting.modalTransitionStyle = transitionStyle hosting.modalPresentationStyle = .overFullScreen @@ -865,18 +920,21 @@ public class Router: AuthorizationRouter, showProgress: true, connectivity: Container.shared.resolve(ConnectivityProtocol.self)! ) - let controller = UIHostingController(rootView: webBrowser) + let controller = UIHostingController(rootView: webBrowser.environmentObject(ThemeManager.shared)) navigationController.pushViewController(controller, animated: true) } public func showSSOWebBrowser(title: String) { - let config = Container.shared.resolve(ConfigProtocol.self)! - let webBrowser = ContainerWebView( - config.baseSSOURL.absoluteString, - title: title - ) - let controller = UIHostingController(rootView: webBrowser) - navigationController.pushViewController(controller, animated: true) + if let viewModel = Container.shared.resolve( + TenantViewModel.self + ), let selectedTenant = viewModel.selectedTenant { + let webBrowser = ContainerWebView( + selectedTenant.baseSSOURL?.absoluteString + ?? "http://localhost:8000", title: title) + let controller = UIHostingController(rootView: webBrowser.environmentObject(ThemeManager.shared)) + navigationController.pushViewController(controller, animated: true) + } + } } diff --git a/OpenEdX/View/MainScreenView.swift b/OpenEdX/View/MainScreenView.swift index 786719f37..e6aac4eba 100644 --- a/OpenEdX/View/MainScreenView.swift +++ b/OpenEdX/View/MainScreenView.swift @@ -21,20 +21,10 @@ struct MainScreenView: View { @State private var disableAllTabs: Bool = false @State private var updateAvailable: Bool = false - @ObservedObject private(set) var viewModel: MainScreenViewModel init(viewModel: MainScreenViewModel) { self.viewModel = viewModel - UITabBar.appearance().isTranslucent = false - UITabBar.appearance().barTintColor = Theme.UIColors.tabbarActiveColor - UITabBar.appearance().backgroundColor = Theme.UIColors.tabbarBGColor - UITabBar.appearance().unselectedItemTintColor = Theme.UIColors.tabbarInactiveColor - - UITabBarItem.appearance().setTitleTextAttributes( - [NSAttributedString.Key.font: Theme.UIFonts.labelSmall()], - for: .normal - ) } var body: some View { @@ -158,6 +148,21 @@ struct MainScreenView: View { .tag(MainTab.profile) .accessibilityIdentifier("profile_tabitem") } + .onAppear { + UITabBar.appearance().isTranslucent = false + UITabBar.appearance().barTintColor = UIColor(Theme.Colors.tabbarColor) + UITabBar.appearance().backgroundColor = UIColor(Theme.Colors.tabbarColor) + UITabBar.appearance().unselectedItemTintColor = UIColor(Theme.Colors.textSecondaryLight) + + UITabBarItem.appearance().setTitleTextAttributes( + [NSAttributedString.Key.font: Theme.UIFonts.labelSmall()], + for: .normal + ) + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .navigationBarHidden(viewModel.selection == .dashboard || viewModel.selection == .downloads) .navigationBarBackButtonHidden(viewModel.selection == .dashboard || viewModel.selection == .downloads) .navigationTitle(titleBar()) diff --git a/Profile/Profile.xcodeproj/project.pbxproj b/Profile/Profile.xcodeproj/project.pbxproj index 5fb306ab5..18d738308 100644 --- a/Profile/Profile.xcodeproj/project.pbxproj +++ b/Profile/Profile.xcodeproj/project.pbxproj @@ -141,9 +141,12 @@ 02FE9A7F2BC707D400B3C206 /* SettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SettingsViewModelTests.swift; path = ProfileTests/Presentation/Settings/SettingsViewModelTests.swift; sourceTree = SOURCE_ROOT; }; 0796C8C829B7905300444B05 /* ProfileBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileBottomSheet.swift; sourceTree = ""; }; 0E5054C44435557666B6D885 /* Pods-App-Profile.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.debugstage.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.debugstage.xcconfig"; sourceTree = ""; }; + 275B896289277F109A8E88BB /* Pods-App-Profile.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.debugprodtenants.xcconfig"; sourceTree = ""; }; 3674C51E1BE41D834B5C4E99 /* Pods-App-Profile.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.debugdev.xcconfig"; sourceTree = ""; }; + 50E5A024649A4012A3AF2B4C /* Pods-App-Profile-ProfileTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile-ProfileTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Profile-ProfileTests/Pods-App-Profile-ProfileTests.debugprodtenants.xcconfig"; sourceTree = ""; }; 52AFEEDE612F39072A418B1B /* Pods-App-Profile-ProfileTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile-ProfileTests.debug.xcconfig"; path = "Target Support Files/Pods-App-Profile-ProfileTests/Pods-App-Profile-ProfileTests.debug.xcconfig"; sourceTree = ""; }; 5788D9F297637D0D4A327E3B /* Pods-App-Profile-ProfileTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile-ProfileTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Profile-ProfileTests/Pods-App-Profile-ProfileTests.debugprod.xcconfig"; sourceTree = ""; }; + 5A2F9CBB57F90459515BF4E5 /* Pods-App-Profile-ProfileTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile-ProfileTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Profile-ProfileTests/Pods-App-Profile-ProfileTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; 7353334255A8C1EC85A413DE /* Pods-App-Profile.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.releaseprod.xcconfig"; sourceTree = ""; }; 7866F14F89F9B83062105100 /* Pods-App-Profile-ProfileTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile-ProfileTests.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Profile-ProfileTests/Pods-App-Profile-ProfileTests.releasestage.xcconfig"; sourceTree = ""; }; 7B80961BB9886B28B90B9ECB /* Pods-App-Profile.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.releasestage.xcconfig"; sourceTree = ""; }; @@ -152,6 +155,7 @@ 99E3D23305C745FE0FF57A62 /* Pods-App-Profile.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.release.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.release.xcconfig"; sourceTree = ""; }; 9AC2F1A5AE5AC7F0CFCB9FE3 /* Pods-App-Profile-ProfileTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile-ProfileTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Profile-ProfileTests/Pods-App-Profile-ProfileTests.releasedev.xcconfig"; sourceTree = ""; }; 9D125F82E0EAC4B6C0CE280F /* Pods-App-Profile-ProfileTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile-ProfileTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Profile-ProfileTests/Pods-App-Profile-ProfileTests.releaseprod.xcconfig"; sourceTree = ""; }; + A1CC5BC916FEB2C2CDF468DC /* Pods-App-Profile.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.openedxmultitenants.xcconfig"; sourceTree = ""; }; A9F98CD65D1F657EB8F9EA59 /* Pods-App-Profile.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.releasedev.xcconfig"; sourceTree = ""; }; B3F05DC21379BD4FE1AFCCF1 /* Pods-App-Profile.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Profile.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Profile/Pods-App-Profile.debugprod.xcconfig"; sourceTree = ""; }; BAD9CA3E2B29BF5C00DE790A /* ProfileSupportInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSupportInfoView.swift; sourceTree = ""; }; @@ -451,6 +455,10 @@ 7B80961BB9886B28B90B9ECB /* Pods-App-Profile.releasestage.xcconfig */, FB33709D5DBACDEA33BD016F /* Pods-App-Profile-ProfileTests.debugstage.xcconfig */, 7866F14F89F9B83062105100 /* Pods-App-Profile-ProfileTests.releasestage.xcconfig */, + A1CC5BC916FEB2C2CDF468DC /* Pods-App-Profile.openedxmultitenants.xcconfig */, + 5A2F9CBB57F90459515BF4E5 /* Pods-App-Profile-ProfileTests.openedxmultitenants.xcconfig */, + 275B896289277F109A8E88BB /* Pods-App-Profile.debugprodtenants.xcconfig */, + 50E5A024649A4012A3AF2B4C /* Pods-App-Profile-ProfileTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -1696,6 +1704,237 @@ }; name = ReleaseStage; }; + 995886BB2E6448D10065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886BC2E6448D10065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 275B896289277F109A8E88BB /* Pods-App-Profile.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Profile; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886BD2E6448D10065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 50E5A024649A4012A3AF2B4C /* Pods-App-Profile-ProfileTests.debugprodtenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.ProfileTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1E92E6037750020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1EA2E6037750020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A1CC5BC916FEB2C2CDF468DC /* Pods-App-Profile.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Profile; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1EB2E6037750020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5A2F9CBB57F90459515BF4E5 /* Pods-App-Profile-ProfileTests.openedxmultitenants.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MACOSX_DEPLOYMENT_TARGET = 12.6; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.ProfileTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1703,11 +1942,13 @@ isa = XCConfigurationList; buildConfigurations = ( 020F834F28DB4CCD0062FA70 /* Debug */, + 9972D1E92E6037750020CFBD /* OpenEdXMultiTenants */, 020F835628DB4CEB0062FA70 /* DebugDev */, 020F835428DB4CE50062FA70 /* DebugProd */, 02DD1CB129E80D3300F35DCE /* DebugStage */, 020F835028DB4CCD0062FA70 /* Release */, 020F835A28DB4CF50062FA70 /* ReleaseProd */, + 995886BB2E6448D10065D132 /* DebugProdTenants */, 02DD1CB429E80D3800F35DCE /* ReleaseStage */, 020F835828DB4CF10062FA70 /* ReleaseDev */, ); @@ -1718,11 +1959,13 @@ isa = XCConfigurationList; buildConfigurations = ( 020F835228DB4CCD0062FA70 /* Debug */, + 9972D1EA2E6037750020CFBD /* OpenEdXMultiTenants */, 020F835728DB4CEB0062FA70 /* DebugDev */, 020F835528DB4CE50062FA70 /* DebugProd */, 02DD1CB229E80D3300F35DCE /* DebugStage */, 020F835328DB4CCD0062FA70 /* Release */, 020F835B28DB4CF50062FA70 /* ReleaseProd */, + 995886BC2E6448D10065D132 /* DebugProdTenants */, 02DD1CB529E80D3800F35DCE /* ReleaseStage */, 020F835928DB4CF10062FA70 /* ReleaseDev */, ); @@ -1733,11 +1976,13 @@ isa = XCConfigurationList; buildConfigurations = ( 02A9A9212978194A00B55797 /* Debug */, + 9972D1EB2E6037750020CFBD /* OpenEdXMultiTenants */, 02A9A9222978194A00B55797 /* DebugDev */, 02A9A9232978194A00B55797 /* DebugProd */, 02DD1CB329E80D3300F35DCE /* DebugStage */, 02A9A9242978194A00B55797 /* Release */, 02A9A9252978194A00B55797 /* ReleaseProd */, + 995886BD2E6448D10065D132 /* DebugProdTenants */, 02DD1CB629E80D3800F35DCE /* ReleaseStage */, 02A9A9262978194A00B55797 /* ReleaseDev */, ); diff --git a/Profile/Profile/Data/ProfileRepository.swift b/Profile/Profile/Data/ProfileRepository.swift index f5c3bf041..5ed09dac4 100644 --- a/Profile/Profile/Data/ProfileRepository.swift +++ b/Profile/Profile/Data/ProfileRepository.swift @@ -34,19 +34,22 @@ public actor ProfileRepository: ProfileRepositoryProtocol { private let downloadManager: DownloadManagerProtocol private let coreDataHandler: CoreDataHandlerProtocol private let config: ConfigProtocol + private let tenantProvider: () -> TenantProvider public init( api: API, storage: CoreStorage & ProfileStorage, coreDataHandler: CoreDataHandlerProtocol, downloadManager: DownloadManagerProtocol, - config: ConfigProtocol + config: ConfigProtocol, + tenantProvider: @escaping () -> TenantProvider ) { self.api = api self.storage = storage self.coreDataHandler = coreDataHandler self.downloadManager = downloadManager self.config = config + self.tenantProvider = tenantProvider } public func getUserProfile(username: String) async throws -> UserProfile { @@ -72,7 +75,7 @@ public actor ProfileRepository: ProfileRepositoryProtocol { public func logOut() async throws { guard let refreshToken = storage.refreshToken else { return } _ = try await api.request( - ProfileEndpoint.logOut(refreshToken: refreshToken, clientID: config.oAuthClientId) + ProfileEndpoint.logOut(refreshToken: refreshToken, clientID: tenantProvider().oAuthClientId) ) storage.clear() } diff --git a/Profile/Profile/Presentation/DatesAndCalendar/CalendarManager.swift b/Profile/Profile/Presentation/DatesAndCalendar/CalendarManager.swift index fd29e33af..7bcb02e6d 100644 --- a/Profile/Profile/Presentation/DatesAndCalendar/CalendarManager.swift +++ b/Profile/Profile/Presentation/DatesAndCalendar/CalendarManager.swift @@ -92,7 +92,7 @@ public final class CalendarManager: CalendarManagerProtocol { let uiColor = UIColor(swiftUIColor) calendar.cgColor = uiColor.cgColor } else { - calendar.cgColor = Theme.Colors.accentColor.cgColor + calendar.cgColor = ThemeManager.shared.theme.colors.accentColor.cgColor } calendar.source = calendarSource diff --git a/Profile/Profile/Presentation/DatesAndCalendar/DatesAndCalendarView.swift b/Profile/Profile/Presentation/DatesAndCalendar/DatesAndCalendarView.swift index 52ef209f9..57846f416 100644 --- a/Profile/Profile/Presentation/DatesAndCalendar/DatesAndCalendarView.swift +++ b/Profile/Profile/Presentation/DatesAndCalendar/DatesAndCalendarView.swift @@ -45,6 +45,7 @@ public struct DatesAndCalendarView: View { Group { calendarSyncCard RelativeDatesToggleView(useRelativeDates: $viewModel.profileStorage.useRelativeDates) + } .padding(.horizontal, isHorizontal ? 48 : 0) } diff --git a/Profile/Profile/Presentation/DatesAndCalendar/Elements/ToggleWithDescriptionView.swift b/Profile/Profile/Presentation/DatesAndCalendar/Elements/ToggleWithDescriptionView.swift index fed25a7df..b4eaecca1 100644 --- a/Profile/Profile/Presentation/DatesAndCalendar/Elements/ToggleWithDescriptionView.swift +++ b/Profile/Profile/Presentation/DatesAndCalendar/Elements/ToggleWithDescriptionView.swift @@ -78,7 +78,6 @@ struct ToggleWithDescriptionView: View { struct CustomToggle: View { @Binding var isOn: Bool - var body: some View { Button(action: { isOn.toggle() diff --git a/Profile/Profile/Presentation/DatesAndCalendar/SyncCalendarOptionsView.swift b/Profile/Profile/Presentation/DatesAndCalendar/SyncCalendarOptionsView.swift index b5aa1e691..4d271328e 100644 --- a/Profile/Profile/Presentation/DatesAndCalendar/SyncCalendarOptionsView.swift +++ b/Profile/Profile/Presentation/DatesAndCalendar/SyncCalendarOptionsView.swift @@ -15,7 +15,6 @@ public struct SyncCalendarOptionsView: View { private var viewModel: DatesAndCalendarViewModel @State private var screenDimmed: Bool = false - @Environment(\.isHorizontal) private var isHorizontal public init(viewModel: DatesAndCalendarViewModel) { @@ -96,6 +95,7 @@ public struct SyncCalendarOptionsView: View { .padding(.bottom, 24) } RelativeDatesToggleView(useRelativeDates: $viewModel.profileStorage.useRelativeDates) + } .padding(.horizontal, isHorizontal ? 48 : 0) .frameLimit(width: proxy.size.width) diff --git a/Profile/Profile/Presentation/DeleteAccount/DeleteAccountView.swift b/Profile/Profile/Presentation/DeleteAccount/DeleteAccountView.swift index 585c06279..761cc934b 100644 --- a/Profile/Profile/Presentation/DeleteAccount/DeleteAccountView.swift +++ b/Profile/Profile/Presentation/DeleteAccount/DeleteAccountView.swift @@ -146,6 +146,12 @@ public struct DeleteAccountView: View { maxHeight: .infinity, alignment: .top) .padding(.top, 8) + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .navigationBarHidden(false) .navigationBarBackButtonHidden(true) .navigationTitle(ProfileLocalization.DeleteAccount.title) diff --git a/Profile/Profile/Presentation/EditProfile/EditProfileView.swift b/Profile/Profile/Presentation/EditProfile/EditProfileView.swift index e82df4e6a..d3881efa3 100644 --- a/Profile/Profile/Presentation/EditProfile/EditProfileView.swift +++ b/Profile/Profile/Presentation/EditProfile/EditProfileView.swift @@ -253,6 +253,12 @@ public struct EditProfileView: View { viewModel.trackScreenEvent() } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } } } diff --git a/Profile/Profile/Presentation/EditProfile/ProfileBottomSheet.swift b/Profile/Profile/Presentation/EditProfile/ProfileBottomSheet.swift index 54a3c7ff5..ed908ae0b 100644 --- a/Profile/Profile/Presentation/EditProfile/ProfileBottomSheet.swift +++ b/Profile/Profile/Presentation/EditProfile/ProfileBottomSheet.swift @@ -191,6 +191,7 @@ extension ProfileBottomSheet { case remove case cancel + @MainActor func bgColor() -> Color { switch self { case .gallery: @@ -202,6 +203,7 @@ extension ProfileBottomSheet { } } + @MainActor func frameColor() -> Color { switch self { case .gallery: @@ -213,6 +215,7 @@ extension ProfileBottomSheet { } } + @MainActor func textColor() -> Color { switch self { case .gallery: diff --git a/Profile/Profile/Presentation/Profile/ProfileView.swift b/Profile/Profile/Presentation/Profile/ProfileView.swift index 1691afc3d..6eb93ee35 100644 --- a/Profile/Profile/Presentation/Profile/ProfileView.swift +++ b/Profile/Profile/Presentation/Profile/ProfileView.swift @@ -45,7 +45,7 @@ public struct ProfileView: View { reloadAction: { await viewModel.getMyProfile(withProgress: false) } - ) + ).environmentObject(ThemeManager.shared) // MARK: - Error Alert if viewModel.showError { @@ -80,6 +80,12 @@ public struct ProfileView: View { await viewModel.getMyProfile() } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } } } diff --git a/Profile/Profile/Presentation/Profile/Subviews/ProfileSupportInfoView.swift b/Profile/Profile/Presentation/Profile/Subviews/ProfileSupportInfoView.swift index 986426d87..7d0fe4ac9 100644 --- a/Profile/Profile/Presentation/Profile/Subviews/ProfileSupportInfoView.swift +++ b/Profile/Profile/Presentation/Profile/Subviews/ProfileSupportInfoView.swift @@ -21,7 +21,7 @@ struct ProfileSupportInfoView: View { } @ObservedObject var viewModel: SettingsViewModel - + var body: some View { Text(ProfileLocalization.supportInfo) .padding(.horizontal, 24) diff --git a/Profile/Profile/Presentation/Profile/UserProfile/UserProfileView.swift b/Profile/Profile/Presentation/Profile/UserProfile/UserProfileView.swift index da7e80fd6..c211e7170 100644 --- a/Profile/Profile/Presentation/Profile/UserProfile/UserProfileView.swift +++ b/Profile/Profile/Presentation/Profile/UserProfile/UserProfileView.swift @@ -15,7 +15,7 @@ public struct UserProfileView: View { @Environment(\.dismiss) private var dismiss @ObservedObject private var viewModel: UserProfileViewModel - + public var isSheet: Bool public init(viewModel: UserProfileViewModel, isSheet: Bool = false) { @@ -106,6 +106,12 @@ public struct UserProfileView: View { } } } + .onAppear { + NavigationAppearanceManager.shared.updateAppearance( + backgroundColor: Theme.Colors.navigationBarColor.uiColor(), + titleColor: .white + ) + } .onFirstAppear { Task { await viewModel.getUserProfile() diff --git a/Profile/Profile/Presentation/ProfileRouter.swift b/Profile/Profile/Presentation/ProfileRouter.swift index 246e0cdf1..45ea88919 100644 --- a/Profile/Profile/Presentation/ProfileRouter.swift +++ b/Profile/Profile/Presentation/ProfileRouter.swift @@ -25,6 +25,8 @@ public protocol ProfileRouter: BaseRouter { func showManageAccount() + func showLearningCenter() + func showDatesAndCalendar() func showSyncCalendarOptions() @@ -67,6 +69,8 @@ public class ProfileRouterMock: BaseRouterMock, ProfileRouter { public func showManageAccount() {} + public func showLearningCenter() {} + public func showVideoQualityView(viewModel: SettingsViewModel) {} public func showVideoDownloadQualityView( diff --git a/Profile/Profile/Presentation/Settings/ManageAccountView.swift b/Profile/Profile/Presentation/Settings/ManageAccountView.swift index 8b791d42b..1e119a857 100644 --- a/Profile/Profile/Presentation/Settings/ManageAccountView.swift +++ b/Profile/Profile/Presentation/Settings/ManageAccountView.swift @@ -16,6 +16,7 @@ public struct ManageAccountView: View { private var viewModel: ManageAccountViewModel @Environment(\.isHorizontal) private var isHorizontal + @EnvironmentObject var themeManager: ThemeManager public init(viewModel: ManageAccountViewModel) { self.viewModel = viewModel @@ -37,12 +38,12 @@ public struct ManageAccountView: View { ZStack { HStack { Text(ProfileLocalization.manageAccount) - .titleSettings(color: Theme.Colors.loginNavigationText) + .titleSettings(color: themeManager.theme.colors.loginNavigationText) .accessibilityIdentifier("manage_account_text") } VStack { BackNavigationButton( - color: Theme.Colors.loginNavigationText, + color: themeManager.theme.colors.loginNavigationText, action: { viewModel.router.back() } @@ -79,7 +80,7 @@ public struct ManageAccountView: View { .frameLimit(width: proxy.size.width) .padding(.top, 24) .padding(.horizontal, isHorizontal ? 24 : 0) - .roundedBackground(Theme.Colors.background) + .roundedBackground(themeManager.theme.colors.background) } .navigationBarHidden(true) .navigationBarBackButtonHidden(true) @@ -91,7 +92,7 @@ public struct ManageAccountView: View { reloadAction: { await viewModel.getMyProfile(withProgress: false) } - ) + ).environmentObject(ThemeManager.shared) // MARK: - Error Alert if viewModel.showError { @@ -109,7 +110,7 @@ public struct ManageAccountView: View { } } .background( - Theme.Colors.background + themeManager.theme.colors.background .ignoresSafeArea() ) .ignoresSafeArea(.all, edges: .horizontal) @@ -127,11 +128,11 @@ public struct ManageAccountView: View { VStack(alignment: .leading, spacing: 4) { Text(viewModel.userModel?.name ?? "") .font(Theme.Fonts.headlineSmall) - .foregroundColor(Theme.Colors.textPrimary) + .foregroundColor(themeManager.theme.colors.textPrimary) .accessibilityIdentifier("user_name_text") Text("\(viewModel.userModel?.email ?? "")") .font(Theme.Fonts.labelLarge) - .foregroundColor(Theme.Colors.textSecondary) + .foregroundColor(themeManager.theme.colors.textSecondary) .accessibilityIdentifier("user_username_text") } Spacer() @@ -159,7 +160,7 @@ public struct ManageAccountView: View { alignment: .center ) .font(Theme.Fonts.labelLarge) - .foregroundColor(Theme.Colors.alert) + .foregroundColor(themeManager.theme.colors.alert) .padding(.top, 12) .accessibilityIdentifier("delete_account_button") } @@ -184,9 +185,9 @@ public struct ManageAccountView: View { } ) }, - color: Theme.Colors.background, - textColor: Theme.Colors.accentColor, - borderColor: Theme.Colors.accentColor + color: themeManager.theme.colors.background, + textColor: themeManager.theme.colors.accentColor, + borderColor: themeManager.theme.colors.accentColor ).padding(.horizontal, 24) } .frame( diff --git a/Profile/Profile/Presentation/Settings/SettingsView.swift b/Profile/Profile/Presentation/Settings/SettingsView.swift index e58533f4d..11e7c15b2 100644 --- a/Profile/Profile/Presentation/Settings/SettingsView.swift +++ b/Profile/Profile/Presentation/Settings/SettingsView.swift @@ -17,6 +17,7 @@ public struct SettingsView: View { private var viewModel: SettingsViewModel @Environment(\.isHorizontal) private var isHorizontal + @EnvironmentObject var themeManager: ThemeManager public init(viewModel: SettingsViewModel) { self.viewModel = viewModel @@ -38,12 +39,12 @@ public struct SettingsView: View { ZStack { HStack { Text(ProfileLocalization.settings) - .titleSettings(color: Theme.Colors.loginNavigationText) + .titleSettings(color: themeManager.theme.colors.loginNavigationText) .accessibilityIdentifier("register_text") } VStack { BackNavigationButton( - color: Theme.Colors.loginNavigationText, + color: themeManager.theme.colors.loginNavigationText, action: { viewModel.router.back() } @@ -70,6 +71,7 @@ public struct SettingsView: View { settings datesAndCalendar ProfileSupportInfoView(viewModel: viewModel) + learningCenter logOutButton } } @@ -82,7 +84,7 @@ public struct SettingsView: View { .padding(.top, 24) .padding(.horizontal, isHorizontal ? 24 : 0) } - .roundedBackground(Theme.Colors.background) + .roundedBackground(themeManager.theme.colors.background) } .navigationBarHidden(true) .navigationBarBackButtonHidden(true) @@ -104,7 +106,7 @@ public struct SettingsView: View { } } .background( - Theme.Colors.background + themeManager.theme.colors.background .ignoresSafeArea() ) .ignoresSafeArea(.all, edges: .horizontal) @@ -133,7 +135,7 @@ public struct SettingsView: View { .accessibilityElement(children: .ignore) .accessibilityLabel(ProfileLocalization.datesAndCalendar) .cardStyle( - bgColor: Theme.Colors.textInputUnfocusedBackground, + bgColor: themeManager.theme.colors.textInputUnfocusedBackground, strokeColor: .clear ) } @@ -159,7 +161,7 @@ public struct SettingsView: View { .accessibilityElement(children: .ignore) .accessibilityLabel(ProfileLocalization.manageAccount) .cardStyle( - bgColor: Theme.Colors.textInputUnfocusedBackground, + bgColor: themeManager.theme.colors.textInputUnfocusedBackground, strokeColor: .clear ) } @@ -171,7 +173,7 @@ public struct SettingsView: View { Text(ProfileLocalization.settings) .padding(.horizontal, 24) .font(Theme.Fonts.labelLarge) - .foregroundColor(Theme.Colors.textSecondary) + .foregroundColor(themeManager.theme.colors.textSecondary) .accessibilityIdentifier("settings_text") .padding(.top, 12) @@ -194,11 +196,60 @@ public struct SettingsView: View { .accessibilityElement(children: .ignore) .accessibilityLabel(ProfileLocalization.settingsVideo) .cardStyle( - bgColor: Theme.Colors.textInputUnfocusedBackground, + bgColor: themeManager.theme.colors.textInputUnfocusedBackground, strokeColor: .clear ) } + // MARK: - Learning Center + @ViewBuilder + private var learningCenter: some View { + Text(ProfileLocalization.learningCenter) + .padding(.horizontal, 24) + .font(Theme.Fonts.labelLarge) + .foregroundColor(themeManager.theme.colors.textSecondary) + .accessibilityIdentifier("settings_text") + .padding(.top, 12) + VStack(alignment: .leading, spacing: 27) { + Button(action: { + viewModel.trackProfileVideoSettingsClicked() + viewModel.router.showLearningCenter() + }, label: { + HStack { + getLogo(name: themeManager.theme.name) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxWidth: 40, maxHeight: 40) + .accessibilityIdentifier("logo_image") + + Text(themeManager.theme.name) + .font(Theme.Fonts.titleMedium) + Spacer() + Image(systemName: "chevron.right") + .flipsForRightToLeftLayoutDirection(true) + } + }) + .accessibilityIdentifier("video_settings_button") + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(ProfileLocalization.settingsVideo) + .cardStyle( + bgColor: themeManager.theme.colors.textInputUnfocusedBackground, + strokeColor: .clear + ) + } + + func getLogo(name: String) -> Image { + switch name.lowercased() { + case "tenantA": + return ThemeAssets.appLogo.swiftUIImage + case "tenantB": + return ThemeAssets.appLogo.swiftUIImage + default: + return ThemeAssets.appLogo.swiftUIImage + } + } + // MARK: - Log out private var logOutButton: some View { @@ -236,8 +287,8 @@ public struct SettingsView: View { .accessibilityLabel(ProfileLocalization.logout) .accessibilityIdentifier("logout_button") } - .foregroundColor(Theme.Colors.alert) - .cardStyle(bgColor: Theme.Colors.textInputUnfocusedBackground, strokeColor: .clear) + .foregroundColor(themeManager.theme.colors.alert) + .cardStyle(bgColor: themeManager.theme.colors.textInputUnfocusedBackground, strokeColor: .clear) .padding(.top, 24) .padding(.bottom, 60) } @@ -266,6 +317,7 @@ public struct SettingsCell: View { private var title: String private var description: String? + @EnvironmentObject var themeManager: ThemeManager public init(title: String, description: String?) { self.title = title @@ -280,10 +332,10 @@ public struct SettingsCell: View { if let description { Text(description) .font(Theme.Fonts.bodySmall) - .foregroundColor(Theme.Colors.textSecondary) + .foregroundColor(themeManager.theme.colors.textSecondary) .accessibilityIdentifier("video_settings_sub_text") } - }.foregroundColor(Theme.Colors.textPrimary) + }.foregroundColor(themeManager.theme.colors.textPrimary) .frame(maxWidth: .infinity, alignment: .leading) } } diff --git a/Profile/Profile/Presentation/Settings/SettingsViewModel.swift b/Profile/Profile/Presentation/Settings/SettingsViewModel.swift index 3b4a2c7f9..9f57814e2 100644 --- a/Profile/Profile/Presentation/Settings/SettingsViewModel.swift +++ b/Profile/Profile/Presentation/Settings/SettingsViewModel.swift @@ -76,6 +76,7 @@ public final class SettingsViewModel: ObservableObject { let corePersistence: CorePersistenceProtocol let connectivity: ConnectivityProtocol private var coreStorage: CoreStorage + private let tenantProvider: @Sendable () -> any TenantProvider public init( interactor: ProfileInteractorProtocol, @@ -86,7 +87,8 @@ public final class SettingsViewModel: ObservableObject { config: ConfigProtocol, corePersistence: CorePersistenceProtocol, connectivity: ConnectivityProtocol, - coreStorage: CoreStorage + coreStorage: CoreStorage, + tenantProvider: @escaping @Sendable () -> any TenantProvider ) { self.interactor = interactor self.downloadManager = downloadManager @@ -97,7 +99,7 @@ public final class SettingsViewModel: ObservableObject { self.corePersistence = corePersistence self.connectivity = connectivity self.coreStorage = coreStorage - + self.tenantProvider = tenantProvider let userSettings = interactor.getSettings() self.userSettings = userSettings self.wifiOnly = userSettings.wifiOnly @@ -146,7 +148,7 @@ public final class SettingsViewModel: ObservableObject { let deviceModel = UIDevice.current.model let feedbackDetails = "OS version: \(osVersion)\nApp version: \(appVersion)\nDevice model: \(deviceModel)" - let recipientAddress = config.feedbackEmail + let recipientAddress = tenantProvider().feedbackEmail let emailSubject = "Feedback" let emailBody = "\n\n\(feedbackDetails)\n".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! let emailURL = URL(string: "mailto:\(recipientAddress)?subject=\(emailSubject)&body=\(emailBody)") diff --git a/Profile/Profile/Presentation/Settings/VideoQualityView.swift b/Profile/Profile/Presentation/Settings/VideoQualityView.swift index d06c1ea9f..9312723fd 100644 --- a/Profile/Profile/Presentation/Settings/VideoQualityView.swift +++ b/Profile/Profile/Presentation/Settings/VideoQualityView.swift @@ -16,6 +16,7 @@ public struct VideoQualityView: View { @ObservedObject private var viewModel: SettingsViewModel @Environment(\.isHorizontal) private var isHorizontal + @EnvironmentObject var themeManager: ThemeManager public init(viewModel: SettingsViewModel) { self.viewModel = viewModel @@ -37,12 +38,12 @@ public struct VideoQualityView: View { ZStack { HStack { Text(ProfileLocalization.Settings.videoQualityTitle) - .titleSettings(color: Theme.Colors.loginNavigationText) + .titleSettings(color: themeManager.theme.colors.loginNavigationText) .accessibilityIdentifier("manage_account_text") } VStack { BackNavigationButton( - color: Theme.Colors.loginNavigationText, + color: themeManager.theme.colors.loginNavigationText, action: { viewModel.router.back() } @@ -82,9 +83,9 @@ public struct VideoQualityView: View { Spacer() CoreAssets.checkmark.swiftUIImage .renderingMode(.template) - .foregroundColor(Theme.Colors.accentXColor) + .foregroundColor(themeManager.theme.colors.accentXColor) .opacity(quality == viewModel.selectedQuality ? 1 : 0) - }.foregroundColor(Theme.Colors.textPrimary) + }.foregroundColor(themeManager.theme.colors.textPrimary) }) .accessibilityIdentifier("select_quality_button") Divider() @@ -94,7 +95,7 @@ public struct VideoQualityView: View { .padding(.horizontal, 24) .padding(.top, 24) } - .roundedBackground(Theme.Colors.background) + .roundedBackground(themeManager.theme.colors.background) // MARK: - Error Alert if viewModel.showError { @@ -117,7 +118,7 @@ public struct VideoQualityView: View { .navigationTitle(ProfileLocalization.Settings.videoQualityTitle) .ignoresSafeArea(.all, edges: .horizontal) .background( - Theme.Colors.background + themeManager.theme.colors.background .ignoresSafeArea() ) } diff --git a/Profile/Profile/Presentation/Settings/VideoSettingsView.swift b/Profile/Profile/Presentation/Settings/VideoSettingsView.swift index 3e4fd4b4c..c785112af 100644 --- a/Profile/Profile/Presentation/Settings/VideoSettingsView.swift +++ b/Profile/Profile/Presentation/Settings/VideoSettingsView.swift @@ -14,6 +14,7 @@ public struct VideoSettingsView: View { @ObservedObject private var viewModel: SettingsViewModel @Environment(\.isHorizontal) private var isHorizontal + @EnvironmentObject var themeManager: ThemeManager public init(viewModel: SettingsViewModel) { self.viewModel = viewModel @@ -35,12 +36,12 @@ public struct VideoSettingsView: View { ZStack { HStack { Text(ProfileLocalization.Settings.videoSettingsTitle) - .titleSettings(color: Theme.Colors.loginNavigationText) + .titleSettings(color: themeManager.theme.colors.loginNavigationText) .accessibilityIdentifier("manage_account_text") } VStack { BackNavigationButton( - color: Theme.Colors.loginNavigationText, + color: themeManager.theme.colors.loginNavigationText, action: { viewModel.router.back() } @@ -63,10 +64,10 @@ public struct VideoSettingsView: View { description: ProfileLocalization.Settings.wifiDescription ) Toggle(isOn: $viewModel.wifiOnly, label: {}) - .toggleStyle(SwitchToggleStyle(tint: Theme.Colors.toggleSwitchColor)) + .toggleStyle(SwitchToggleStyle(tint: themeManager.theme.colors.toggleSwitchColor)) .frame(width: 50) .accessibilityIdentifier("download_agreement_switch") - }.foregroundColor(Theme.Colors.textPrimary) + }.foregroundColor(themeManager.theme.colors.textPrimary) Divider() // MARK: Streaming Quality @@ -115,7 +116,7 @@ public struct VideoSettingsView: View { .padding(.horizontal, 24) .padding(.top, 24) } - .roundedBackground(Theme.Colors.background) + .roundedBackground(themeManager.theme.colors.background) } } } @@ -124,7 +125,7 @@ public struct VideoSettingsView: View { .navigationTitle(ProfileLocalization.Settings.videoSettingsTitle) .ignoresSafeArea(.all, edges: .horizontal) .background( - Theme.Colors.background + themeManager.theme.colors.background .ignoresSafeArea() ) } diff --git a/Profile/Profile/SwiftGen/Strings.swift b/Profile/Profile/SwiftGen/Strings.swift index 3401ceb79..3c911e6e1 100644 --- a/Profile/Profile/SwiftGen/Strings.swift +++ b/Profile/Profile/SwiftGen/Strings.swift @@ -30,6 +30,8 @@ public enum ProfileLocalization { public static let fullProfile = ProfileLocalization.tr("Localizable", "FULL_PROFILE", fallback: "full profile") /// Profile info public static let info = ProfileLocalization.tr("Localizable", "INFO", fallback: "Profile info") + /// Current Learning Center + public static let learningCenter = ProfileLocalization.tr("Localizable", "LEARNING_CENTER", fallback: "Current Learning Center") /// limited profile public static let limitedProfile = ProfileLocalization.tr("Localizable", "LIMITED_PROFILE", fallback: "limited profile") /// Log out diff --git a/Profile/Profile/en.lproj/Localizable.strings b/Profile/Profile/en.lproj/Localizable.strings index 8a91753ee..131bb4519 100644 --- a/Profile/Profile/en.lproj/Localizable.strings +++ b/Profile/Profile/en.lproj/Localizable.strings @@ -23,6 +23,7 @@ "DO_NOT_SELL_INFORMATION" = "Do not sell my personal information"; "FAQ_TITLE" = "View FAQ"; "MANAGE_ACCOUNT" = "Manage Account"; +"LEARNING_CENTER" = "Current Learning Center"; "LOGOUT" = "Log out"; "SWITCH_TO" = "Switch to"; diff --git a/Theme/Theme.xcodeproj/project.pbxproj b/Theme/Theme.xcodeproj/project.pbxproj index 1fc77b799..d3929bfad 100644 --- a/Theme/Theme.xcodeproj/project.pbxproj +++ b/Theme/Theme.xcodeproj/project.pbxproj @@ -12,6 +12,12 @@ 0770DE5428D0B00C006D8A5D /* swiftgen.yml in Resources */ = {isa = PBXBuildFile; fileRef = 0770DE5328D0B00C006D8A5D /* swiftgen.yml */; }; 0770DE7B28D0C78C006D8A5D /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0770DE7A28D0C78C006D8A5D /* Theme.swift */; }; 4875747BC644481E79603124 /* Pods_App_Theme.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51EFD5ECB23A4898127124B9 /* Pods_App_Theme.framework */; }; + 9972D1752E5F15070020CFBD /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D1712E5F15070020CFBD /* ThemeManager.swift */; }; + 9972D1762E5F15070020CFBD /* ThemeDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D1722E5F15070020CFBD /* ThemeDefinition.swift */; }; + 9972D1772E5F15070020CFBD /* ThemeFontSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D1742E5F15070020CFBD /* ThemeFontSet.swift */; }; + 9972D1782E5F15070020CFBD /* ThemeColorSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9972D1732E5F15070020CFBD /* ThemeColorSet.swift */; }; + 99AEC6202E60478500F2D309 /* Pods_App_Theme.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 99AEC61F2E60478500F2D309 /* Pods_App_Theme.framework */; }; + 99AEC6212E60478500F2D309 /* Pods_App_Theme.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 99AEC61F2E60478500F2D309 /* Pods_App_Theme.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E04A731A2B171D2B00E31764 /* FontParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E09179F82B0EF981002AB695 /* FontParserTests.swift */; }; E0C716A72B0B05BA00858BAB /* fonts.json in Resources */ = {isa = PBXBuildFile; fileRef = E0C716A62B0B05BA00858BAB /* fonts.json */; }; E0C716A92B0B065600858BAB /* FontParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C716A82B0B065600858BAB /* FontParser.swift */; }; @@ -31,6 +37,20 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 99AEC6222E60478600F2D309 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 99AEC6212E60478500F2D309 /* Pods_App_Theme.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 0295B1DA297FF0E9003B0C65 /* fonts_file.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = fonts_file.ttf; sourceTree = ""; }; 0754BB7841E3C0F8D6464951 /* Pods-App-Core.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.releasestage.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.releasestage.xcconfig"; sourceTree = ""; }; @@ -55,12 +75,19 @@ 5D02E092DEDAF8A9DE9D34E7 /* Pods-App-Theme.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Theme/Pods-App-Theme.debugprod.xcconfig"; sourceTree = ""; }; 60153262DBC2F9E660D7E11B /* Pods-App-Core.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.release.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.release.xcconfig"; sourceTree = ""; }; 72B5AEE033EE8E4086910FAA /* Pods-App-Theme-ThemeTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme-ThemeTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Theme-ThemeTests/Pods-App-Theme-ThemeTests.releaseprod.xcconfig"; sourceTree = ""; }; + 783E878FA97E45035D5EFA62 /* Pods-App-Theme-ThemeTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme-ThemeTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Theme-ThemeTests/Pods-App-Theme-ThemeTests.debugprodtenants.xcconfig"; sourceTree = ""; }; 7AFDB8C1E97070E426F05ABC /* Pods-App-Theme.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme.release.xcconfig"; path = "Target Support Files/Pods-App-Theme/Pods-App-Theme.release.xcconfig"; sourceTree = ""; }; 8975BD5CEEDBF3A35A67D289 /* Pods-App-Theme.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme.debug.xcconfig"; path = "Target Support Files/Pods-App-Theme/Pods-App-Theme.debug.xcconfig"; sourceTree = ""; }; 960BB69958C7376CD354D74F /* Pods-App-Theme.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Theme/Pods-App-Theme.debugdev.xcconfig"; sourceTree = ""; }; + 9972D1712E5F15070020CFBD /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = ""; }; + 9972D1722E5F15070020CFBD /* ThemeDefinition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeDefinition.swift; sourceTree = ""; }; + 9972D1732E5F15070020CFBD /* ThemeColorSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeColorSet.swift; sourceTree = ""; }; + 9972D1742E5F15070020CFBD /* ThemeFontSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeFontSet.swift; sourceTree = ""; }; + 99AEC61F2E60478500F2D309 /* Pods_App_Theme.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_App_Theme.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9D5B06CAA99EA5CD49CBE2BB /* Pods-App-Core.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.debugdev.xcconfig"; sourceTree = ""; }; A8316465C7A08B99CB3108AA /* Pods-App-Theme-ThemeTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme-ThemeTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-Theme-ThemeTests/Pods-App-Theme-ThemeTests.releasedev.xcconfig"; sourceTree = ""; }; C7E5BCE79CE297B20777B27A /* Pods-App-Core.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.debugprod.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.debugprod.xcconfig"; sourceTree = ""; }; + CD3469AED485689B4B2600D5 /* Pods-App-Theme.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Theme/Pods-App-Theme.openedxmultitenants.xcconfig"; sourceTree = ""; }; E001ADD92B1767C000DE3A03 /* Theme.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = Theme.xctestplan; path = ../Theme.xctestplan; sourceTree = ""; }; E09179F82B0EF981002AB695 /* FontParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontParserTests.swift; sourceTree = ""; }; E0C716A62B0B05BA00858BAB /* fonts.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = fonts.json; sourceTree = ""; }; @@ -70,6 +97,8 @@ E0D6E6A62B16DD4E0089F9C9 /* RoundedCorners.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoundedCorners.swift; sourceTree = ""; }; E0D6E6AE2B16EA380089F9C9 /* ThemeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ThemeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; F6E09DC289758CE811EF93D8 /* Pods-App-Theme-ThemeTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme-ThemeTests.release.xcconfig"; path = "Target Support Files/Pods-App-Theme-ThemeTests/Pods-App-Theme-ThemeTests.release.xcconfig"; sourceTree = ""; }; + F7F7AA539780A80DA5D4E9A0 /* Pods-App-Theme.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-Theme/Pods-App-Theme.debugprodtenants.xcconfig"; sourceTree = ""; }; + F8AE51FC69C5968DE72BD196 /* Pods-App-Theme-ThemeTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Theme-ThemeTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-Theme-ThemeTests/Pods-App-Theme-ThemeTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -77,6 +106,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 99AEC6202E60478500F2D309 /* Pods_App_Theme.framework in Frameworks */, 4875747BC644481E79603124 /* Pods_App_Theme.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -132,6 +162,10 @@ 0295B1DB297FF0E9003B0C65 /* Fonts */, 0770DE5528D0B142006D8A5D /* SwiftGen */, 0770DE7A28D0C78C006D8A5D /* Theme.swift */, + 9972D1712E5F15070020CFBD /* ThemeManager.swift */, + 9972D1722E5F15070020CFBD /* ThemeDefinition.swift */, + 9972D1732E5F15070020CFBD /* ThemeColorSet.swift */, + 9972D1742E5F15070020CFBD /* ThemeFontSet.swift */, E0C716AA2B0B0B8E00858BAB /* Assets.xcassets */, ); path = Theme; @@ -172,6 +206,10 @@ 72B5AEE033EE8E4086910FAA /* Pods-App-Theme-ThemeTests.releaseprod.xcconfig */, 185C3037FC537A93E532FB5B /* Pods-App-Theme-ThemeTests.releasestage.xcconfig */, A8316465C7A08B99CB3108AA /* Pods-App-Theme-ThemeTests.releasedev.xcconfig */, + CD3469AED485689B4B2600D5 /* Pods-App-Theme.openedxmultitenants.xcconfig */, + F8AE51FC69C5968DE72BD196 /* Pods-App-Theme-ThemeTests.openedxmultitenants.xcconfig */, + F7F7AA539780A80DA5D4E9A0 /* Pods-App-Theme.debugprodtenants.xcconfig */, + 783E878FA97E45035D5EFA62 /* Pods-App-Theme-ThemeTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -196,6 +234,7 @@ F1620A3A2C8B0699EAA61B57 /* Frameworks */ = { isa = PBXGroup; children = ( + 99AEC61F2E60478500F2D309 /* Pods_App_Theme.framework */, 51EFD5ECB23A4898127124B9 /* Pods_App_Theme.framework */, 52EBBA416BC61CD2B78879B7 /* Pods_App_Theme_ThemeTests.framework */, ); @@ -225,6 +264,7 @@ 0770DE0428D07831006D8A5D /* Sources */, 0770DE0528D07831006D8A5D /* Frameworks */, 0770DE0628D07831006D8A5D /* Resources */, + 99AEC6222E60478600F2D309 /* Embed Frameworks */, ); buildRules = ( ); @@ -407,6 +447,10 @@ E0C716A92B0B065600858BAB /* FontParser.swift in Sources */, 0770DE7B28D0C78C006D8A5D /* Theme.swift in Sources */, E0D6E69F2B161BD70089F9C9 /* ThemeAssets.swift in Sources */, + 9972D1752E5F15070020CFBD /* ThemeManager.swift in Sources */, + 9972D1762E5F15070020CFBD /* ThemeDefinition.swift in Sources */, + 9972D1772E5F15070020CFBD /* ThemeFontSet.swift in Sources */, + 9972D1782E5F15070020CFBD /* ThemeColorSet.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1194,6 +1238,240 @@ }; name = Release; }; + 995886C42E6448E40065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886C52E6448E40065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F7F7AA539780A80DA5D4E9A0 /* Pods-App-Theme.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Theme; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886C62E6448E40065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 783E878FA97E45035D5EFA62 /* Pods-App-Theme-ThemeTests.debugprodtenants.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.ThemeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1F22E60378C0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1F32E60378C0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CD3469AED485689B4B2600D5 /* Pods-App-Theme.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.Theme; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1F42E60378C0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F8AE51FC69C5968DE72BD196 /* Pods-App-Theme-ThemeTests.openedxmultitenants.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.ThemeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; E0D6E6B62B16EA380089F9C9 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 487962E20A82E0E0A3240D2D /* Pods-App-Theme-ThemeTests.debug.xcconfig */; @@ -1373,11 +1651,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0770DE0D28D07831006D8A5D /* Debug */, + 9972D1F22E60378C0020CFBD /* OpenEdXMultiTenants */, 0727876028D23277002E9142 /* DebugProd */, 02DD1C9929E80CE400F35DCE /* DebugStage */, 0727875C28D2326B002E9142 /* DebugDev */, 0770DE0E28D07831006D8A5D /* Release */, 0727876228D2327C002E9142 /* ReleaseProd */, + 995886C42E6448E40065D132 /* DebugProdTenants */, 02DD1C9C29E80CED00F35DCE /* ReleaseStage */, 0727875E28D23272002E9142 /* ReleaseDev */, ); @@ -1388,11 +1668,13 @@ isa = XCConfigurationList; buildConfigurations = ( 0770DE1028D07831006D8A5D /* Debug */, + 9972D1F32E60378C0020CFBD /* OpenEdXMultiTenants */, 0727876128D23277002E9142 /* DebugProd */, 02DD1C9A29E80CE400F35DCE /* DebugStage */, 0727875D28D2326B002E9142 /* DebugDev */, 0770DE1128D07831006D8A5D /* Release */, 0727876328D2327C002E9142 /* ReleaseProd */, + 995886C52E6448E40065D132 /* DebugProdTenants */, 02DD1C9D29E80CED00F35DCE /* ReleaseStage */, 0727875F28D23272002E9142 /* ReleaseDev */, ); @@ -1403,11 +1685,13 @@ isa = XCConfigurationList; buildConfigurations = ( E0D6E6B62B16EA380089F9C9 /* Debug */, + 9972D1F42E60378C0020CFBD /* OpenEdXMultiTenants */, E0D6E6B72B16EA380089F9C9 /* DebugProd */, E0D6E6B82B16EA380089F9C9 /* DebugStage */, E0D6E6B92B16EA380089F9C9 /* DebugDev */, E0D6E6BA2B16EA380089F9C9 /* Release */, E0D6E6BB2B16EA380089F9C9 /* ReleaseProd */, + 995886C62E6448E40065D132 /* DebugProdTenants */, E0D6E6BC2B16EA380089F9C9 /* ReleaseStage */, E0D6E6BD2B16EA380089F9C9 /* ReleaseDev */, ); diff --git a/Theme/Theme/Assets.xcassets/Colors/TabBarColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/TabBarColor.colorset/Contents.json new file mode 100644 index 000000000..bf1a96417 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/TabBarColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF8", + "green" : "0x78", + "red" : "0x53" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/Colors/navigationBarColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/navigationBarColor.colorset/Contents.json new file mode 100644 index 000000000..06ab94dff --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/navigationBarColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0x68", + "red" : "0x3B" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.976", + "green" : "0.471", + "red" : "0.329" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/Colors/navigationBarColorDark.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/navigationBarColorDark.colorset/Contents.json new file mode 100644 index 000000000..06ab94dff --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/navigationBarColorDark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0x68", + "red" : "0x3B" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.976", + "green" : "0.471", + "red" : "0.329" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/Colors/tabbarTintColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/tabbarTintColor.colorset/Contents.json new file mode 100644 index 000000000..bf1a96417 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/tabbarTintColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF8", + "green" : "0x78", + "red" : "0x53" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentButtonColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentButtonColor.colorset/Contents.json new file mode 100644 index 000000000..49ac54867 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentButtonColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xCA", + "red" : "0x31" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.369", + "green" : "0.208", + "red" : "0.191" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentColor.colorset/Contents.json new file mode 100644 index 000000000..13c34a739 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x8C", + "green" : "0x57", + "red" : "0x3E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentXColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentXColor.colorset/Contents.json new file mode 100644 index 000000000..edab54b39 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAccentXColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xCA", + "red" : "0x31" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAlert.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAlert.colorset/Contents.json new file mode 100644 index 000000000..14e0c379b --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAlert.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAvatarStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAvatarStroke.colorset/Contents.json new file mode 100644 index 000000000..1e6df63e7 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAAvatarStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.392", + "green" : "0.286", + "red" : "0.239" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantABackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantABackground.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantABackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantABackgroundStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantABackgroundStroke.colorset/Contents.json new file mode 100644 index 000000000..723fc70a4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantABackgroundStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/TenantACardViewBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/TenantACardViewBackground.colorset/Contents.json new file mode 100644 index 000000000..44092279d --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/TenantACardViewBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/TenantACardViewStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/TenantACardViewStroke.colorset/Contents.json new file mode 100644 index 000000000..d31f2bcff --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACardView/TenantACardViewStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDF", + "green" : "0xD3", + "red" : "0xCC" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.435", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACertificateForeground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACertificateForeground.colorset/Contents.json new file mode 100644 index 000000000..779262042 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACertificateForeground.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.850", + "blue" : "0.396", + "green" : "0.722", + "red" : "0.180" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACommentCellBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACommentCellBackground.colorset/Contents.json new file mode 100644 index 000000000..e9a7a3504 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACommentCellBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF5", + "green" : "0xF5", + "red" : "0xF5" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseCardBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseCardBackground.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseCardBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseCardShadow.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseCardShadow.colorset/Contents.json new file mode 100644 index 000000000..e7c5c162d --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseCardShadow.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.150", + "blue" : "0x2F", + "green" : "0x21", + "red" : "0x19" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.400", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantADatesSectionBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantADatesSectionBackground.colorset/Contents.json new file mode 100644 index 000000000..b73d804ea --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantADatesSectionBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.984", + "green" : "0.980", + "red" : "0.976" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantADatesSectionStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantADatesSectionStroke.colorset/Contents.json new file mode 100644 index 000000000..432fab345 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantADatesSectionStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.878", + "green" : "0.831", + "red" : "0.800" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantANextWeekTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantANextWeekTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..5cd29db93 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantANextWeekTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantAThisWeekTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantAThisWeekTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..abd91436e --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantAThisWeekTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.392", + "green" : "0.286", + "red" : "0.239" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.624", + "green" : "0.533", + "red" : "0.475" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantATodayTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantATodayTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..3e35599d4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantATodayTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.667", + "red" : "0.259" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.584", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantAUpcomingTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantAUpcomingTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..2af3cc3c3 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantAUpcomingTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.878", + "green" : "0.831", + "red" : "0.800" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantApastDueTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantApastDueTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..a72efa461 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseDates/TenantApastDueTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.302", + "green" : "0.788", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/TenantAprimaryHeaderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/TenantAprimaryHeaderColor.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/TenantAprimaryHeaderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/TenantAsecondaryHeaderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/TenantAsecondaryHeaderColor.colorset/Contents.json new file mode 100644 index 000000000..58170e4e6 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantACourseHeader/TenantAsecondaryHeaderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xBA", + "green" : "0xBA", + "red" : "0xBA" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x99", + "green" : "0x99", + "red" : "0x99" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAInfoColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAInfoColor.colorset/Contents.json new file mode 100644 index 000000000..13c34a739 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAInfoColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x8C", + "green" : "0x57", + "red" : "0x3E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAIrreversibleAlert.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAIrreversibleAlert.colorset/Contents.json new file mode 100644 index 000000000..14e0c379b --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAIrreversibleAlert.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantALoginBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantALoginBackground.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantALoginBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantALoginNavigationText.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantALoginNavigationText.colorset/Contents.json new file mode 100644 index 000000000..cce43b047 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantALoginNavigationText.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.651", + "green" : "0.401", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.651", + "green" : "0.401", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryButtonTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryButtonTextColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryButtonTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardCautionBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardCautionBG.colorset/Contents.json new file mode 100644 index 000000000..bfc59a1b2 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardCautionBG.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardCourseUpgradeBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardCourseUpgradeBG.colorset/Contents.json new file mode 100644 index 000000000..bfc59a1b2 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardCourseUpgradeBG.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardProgressBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardProgressBG.colorset/Contents.json new file mode 100644 index 000000000..d31f2bcff --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAPrimaryCard/TenantAPrimaryCardProgressBG.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDF", + "green" : "0xD3", + "red" : "0xCC" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.435", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAOnProgress.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAOnProgress.colorset/Contents.json new file mode 100644 index 000000000..3c81fe0e7 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAOnProgress.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0xCC", + "red" : "0xF0" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0xCC", + "red" : "0xF0" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAProgressDone.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAProgressDone.colorset/Contents.json new file mode 100644 index 000000000..8e2a9063e --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAProgressDone.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xD7", + "green" : "0xE6", + "red" : "0xBB" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x71", + "green" : "0xA1", + "red" : "0x30" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAProgressSkip.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAProgressSkip.colorset/Contents.json new file mode 100644 index 000000000..4cfea1bac --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantAProgressSkip.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDA", + "green" : "0xD9", + "red" : "0xDD" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDA", + "green" : "0xD9", + "red" : "0xDD" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantASelectedAndDone.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantASelectedAndDone.colorset/Contents.json new file mode 100644 index 000000000..65b3786f0 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAProgressLine/TenantASelectedAndDone.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x71", + "green" : "0xA1", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4D", + "green" : "0x7D", + "red" : "0x0D" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonBGColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonBGColor.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonBGColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonBorderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonBorderColor.colorset/Contents.json new file mode 100644 index 000000000..13c34a739 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonBorderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x8C", + "green" : "0x57", + "red" : "0x3E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonTextColor.colorset/Contents.json new file mode 100644 index 000000000..00d59cb46 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASecondaryButton/TenantASecondaryButtonTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.976", + "green" : "0.471", + "red" : "0.329" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAShadowColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAShadowColor.colorset/Contents.json new file mode 100644 index 000000000..615930dd7 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAShadowColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.060", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.060", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingSelectedTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingSelectedTextColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingSelectedTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingStrokeColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingStrokeColor.colorset/Contents.json new file mode 100644 index 000000000..9151445b8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingStrokeColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFE" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingTextColor.colorset/Contents.json new file mode 100644 index 000000000..93c1c4d85 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASlidingTabBar/TenantASlidingTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFE" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarErrorColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarErrorColor.colorset/Contents.json new file mode 100644 index 000000000..13570c6d4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarErrorColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.310", + "green" : "0.310", + "red" : "0.922" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.310", + "green" : "0.310", + "red" : "0.922" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarInfoColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarInfoColor.colorset/Contents.json new file mode 100644 index 000000000..3e35599d4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarInfoColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.667", + "red" : "0.259" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.584", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarTextColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarWarningColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarWarningColor.colorset/Contents.json new file mode 100644 index 000000000..db6a639f5 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASnackbar/TenantASnackbarWarningColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAStyledButton/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAStyledButton/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAStyledButton/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAStyledButton/TenantAStyledButtonText.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAStyledButton/TenantAStyledButtonText.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAStyledButton/TenantAStyledButtonText.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantASuccess.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASuccess.colorset/Contents.json new file mode 100644 index 000000000..65b3786f0 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantASuccess.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x71", + "green" : "0xA1", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4D", + "green" : "0x7D", + "red" : "0x0D" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATabBarTintColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATabBarTintColor.colorset/Contents.json new file mode 100644 index 000000000..9b3db3386 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATabBarTintColor.colorset/Contents.json @@ -0,0 +1,47 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATabbarColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATabbarColor.colorset/Contents.json new file mode 100644 index 000000000..cd87ac6c6 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATabbarColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "extended-srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4A", + "green" : "0x41", + "red" : "0x2C" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextPrimary.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextPrimary.colorset/Contents.json new file mode 100644 index 000000000..cc0044cca --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextPrimary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2E", + "green" : "0x20", + "red" : "0x18" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextSecondary.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextSecondary.colorset/Contents.json new file mode 100644 index 000000000..e6f1bfdc1 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextSecondary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xCA", + "red" : "0x31" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x9F", + "green" : "0x87", + "red" : "0x79" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextSecondaryLight.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextSecondaryLight.colorset/Contents.json new file mode 100644 index 000000000..93691d3e8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextColor/TenantATextSecondaryLight.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.624", + "green" : "0.533", + "red" : "0.475" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputBackground.colorset/Contents.json new file mode 100644 index 000000000..164b36790 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputPlaceholderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputPlaceholderColor.colorset/Contents.json new file mode 100644 index 000000000..93691d3e8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputPlaceholderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.624", + "green" : "0.533", + "red" : "0.475" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputStroke.colorset/Contents.json new file mode 100644 index 000000000..5cd29db93 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputTextColor.colorset/Contents.json new file mode 100644 index 000000000..a3f0c654a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputUnfocusedBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputUnfocusedBackground.colorset/Contents.json new file mode 100644 index 000000000..2d9b9cd70 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputUnfocusedBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.984", + "green" : "0.980", + "red" : "0.976" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputUnfocusedStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputUnfocusedStroke.colorset/Contents.json new file mode 100644 index 000000000..432fab345 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantATextInput/TenantATextInputUnfocusedStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.878", + "green" : "0.831", + "red" : "0.800" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAToggleSwitchColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAToggleSwitchColor.colorset/Contents.json new file mode 100644 index 000000000..13c34a739 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAToggleSwitchColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x8C", + "green" : "0x57", + "red" : "0x3E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWarning.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWarning.colorset/Contents.json new file mode 100644 index 000000000..db6a639f5 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWarning.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWarningText.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWarningText.colorset/Contents.json new file mode 100644 index 000000000..be9d677bb --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWarningText.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWhite.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWhite.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAWhite.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarColor.colorset/Contents.json new file mode 100644 index 000000000..9b3db3386 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarColor.colorset/Contents.json @@ -0,0 +1,47 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarColorDark.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarColorDark.colorset/Contents.json new file mode 100644 index 000000000..6cbc923e9 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarColorDark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2F", + "green" : "0x21", + "red" : "0x19" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2F", + "green" : "0x21", + "red" : "0x19" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarTintColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarTintColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantAColors/TenantAnavigationBarTintColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentButtonColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentButtonColor.colorset/Contents.json new file mode 100644 index 000000000..49ac54867 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentButtonColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xCA", + "red" : "0x31" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.369", + "green" : "0.208", + "red" : "0.191" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentColor.colorset/Contents.json new file mode 100644 index 000000000..d0010f58e --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentColor.colorset/Contents.json @@ -0,0 +1,33 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "universal", + "reference" : "systemIndigoColor" + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentXColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentXColor.colorset/Contents.json new file mode 100644 index 000000000..e26cf0941 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAccentXColor.colorset/Contents.json @@ -0,0 +1,33 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "universal", + "reference" : "systemIndigoColor" + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xCA", + "red" : "0x31" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAlert.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAlert.colorset/Contents.json new file mode 100644 index 000000000..14e0c379b --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAlert.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAvatarStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAvatarStroke.colorset/Contents.json new file mode 100644 index 000000000..1e6df63e7 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBAvatarStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.392", + "green" : "0.286", + "red" : "0.239" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBBackground.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBBackgroundStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBBackgroundStroke.colorset/Contents.json new file mode 100644 index 000000000..723fc70a4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBBackgroundStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/TenantBCardViewBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/TenantBCardViewBackground.colorset/Contents.json new file mode 100644 index 000000000..44092279d --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/TenantBCardViewBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/TenantBCardViewStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/TenantBCardViewStroke.colorset/Contents.json new file mode 100644 index 000000000..d31f2bcff --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCardView/TenantBCardViewStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDF", + "green" : "0xD3", + "red" : "0xCC" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.435", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCertificateForeground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCertificateForeground.colorset/Contents.json new file mode 100644 index 000000000..779262042 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCertificateForeground.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.850", + "blue" : "0.396", + "green" : "0.722", + "red" : "0.180" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCommentCellBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCommentCellBackground.colorset/Contents.json new file mode 100644 index 000000000..e9a7a3504 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCommentCellBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF5", + "green" : "0xF5", + "red" : "0xF5" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseCardBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseCardBackground.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseCardBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseCardShadow.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseCardShadow.colorset/Contents.json new file mode 100644 index 000000000..e7c5c162d --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseCardShadow.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.150", + "blue" : "0x2F", + "green" : "0x21", + "red" : "0x19" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.400", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBDatesSectionBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBDatesSectionBackground.colorset/Contents.json new file mode 100644 index 000000000..b73d804ea --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBDatesSectionBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.984", + "green" : "0.980", + "red" : "0.976" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBDatesSectionStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBDatesSectionStroke.colorset/Contents.json new file mode 100644 index 000000000..432fab345 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBDatesSectionStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.878", + "green" : "0.831", + "red" : "0.800" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBNextWeekTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBNextWeekTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..5cd29db93 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBNextWeekTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBThisWeekTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBThisWeekTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..161faf8ba --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBThisWeekTimelineColor.colorset/Contents.json @@ -0,0 +1,33 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "universal", + "reference" : "systemIndigoColor" + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.624", + "green" : "0.533", + "red" : "0.475" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBTodayTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBTodayTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..3e35599d4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBTodayTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.667", + "red" : "0.259" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.584", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBUpcomingTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBUpcomingTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..2af3cc3c3 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBUpcomingTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.878", + "green" : "0.831", + "red" : "0.800" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBpastDueTimelineColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBpastDueTimelineColor.colorset/Contents.json new file mode 100644 index 000000000..a72efa461 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseDates/TenantBpastDueTimelineColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.302", + "green" : "0.788", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/TenantBprimaryHeaderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/TenantBprimaryHeaderColor.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/TenantBprimaryHeaderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/TenantBsecondaryHeaderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/TenantBsecondaryHeaderColor.colorset/Contents.json new file mode 100644 index 000000000..58170e4e6 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBCourseHeader/TenantBsecondaryHeaderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xBA", + "green" : "0xBA", + "red" : "0xBA" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x99", + "green" : "0x99", + "red" : "0x99" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBInfoColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBInfoColor.colorset/Contents.json new file mode 100644 index 000000000..d0010f58e --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBInfoColor.colorset/Contents.json @@ -0,0 +1,33 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "universal", + "reference" : "systemIndigoColor" + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBIrreversibleAlert.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBIrreversibleAlert.colorset/Contents.json new file mode 100644 index 000000000..14e0c379b --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBIrreversibleAlert.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.443", + "green" : "0.239", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBLoginBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBLoginBackground.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBLoginBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBLoginNavigationText.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBLoginNavigationText.colorset/Contents.json new file mode 100644 index 000000000..cce43b047 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBLoginNavigationText.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.651", + "green" : "0.401", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.651", + "green" : "0.401", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryButtonTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryButtonTextColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryButtonTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardCautionBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardCautionBG.colorset/Contents.json new file mode 100644 index 000000000..bfc59a1b2 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardCautionBG.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardCourseUpgradeBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardCourseUpgradeBG.colorset/Contents.json new file mode 100644 index 000000000..bfc59a1b2 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardCourseUpgradeBG.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardProgressBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardProgressBG.colorset/Contents.json new file mode 100644 index 000000000..d31f2bcff --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBPrimaryCard/TenantBPrimaryCardProgressBG.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDF", + "green" : "0xD3", + "red" : "0xCC" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.435", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBOnProgress.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBOnProgress.colorset/Contents.json new file mode 100644 index 000000000..3c81fe0e7 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBOnProgress.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0xCC", + "red" : "0xF0" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0xCC", + "red" : "0xF0" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBProgressDone.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBProgressDone.colorset/Contents.json new file mode 100644 index 000000000..8e2a9063e --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBProgressDone.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xD7", + "green" : "0xE6", + "red" : "0xBB" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x71", + "green" : "0xA1", + "red" : "0x30" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBProgressSkip.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBProgressSkip.colorset/Contents.json new file mode 100644 index 000000000..4cfea1bac --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBProgressSkip.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDA", + "green" : "0xD9", + "red" : "0xDD" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xDA", + "green" : "0xD9", + "red" : "0xDD" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBSelectedAndDone.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBSelectedAndDone.colorset/Contents.json new file mode 100644 index 000000000..65b3786f0 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBProgressLine/TenantBSelectedAndDone.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x71", + "green" : "0xA1", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4D", + "green" : "0x7D", + "red" : "0x0D" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonBGColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonBGColor.colorset/Contents.json new file mode 100644 index 000000000..8fef18d07 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonBGColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonBorderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonBorderColor.colorset/Contents.json new file mode 100644 index 000000000..13c34a739 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonBorderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x8C", + "green" : "0x57", + "red" : "0x3E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonTextColor.colorset/Contents.json new file mode 100644 index 000000000..00d59cb46 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSecondaryButton/TenantBSecondaryButtonTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.976", + "green" : "0.471", + "red" : "0.329" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBShadowColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBShadowColor.colorset/Contents.json new file mode 100644 index 000000000..615930dd7 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBShadowColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.060", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.060", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingSelectedTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingSelectedTextColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingSelectedTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingStrokeColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingStrokeColor.colorset/Contents.json new file mode 100644 index 000000000..9151445b8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingStrokeColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFE" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingTextColor.colorset/Contents.json new file mode 100644 index 000000000..93c1c4d85 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSlidingTabBar/TenantBSlidingTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.408", + "red" : "0.235" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFE" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarErrorColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarErrorColor.colorset/Contents.json new file mode 100644 index 000000000..13570c6d4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarErrorColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.310", + "green" : "0.310", + "red" : "0.922" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.310", + "green" : "0.310", + "red" : "0.922" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarInfoColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarInfoColor.colorset/Contents.json new file mode 100644 index 000000000..3e35599d4 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarInfoColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.667", + "red" : "0.259" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.584", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarTextColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarWarningColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarWarningColor.colorset/Contents.json new file mode 100644 index 000000000..db6a639f5 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSnackbar/TenantBSnackbarWarningColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBStyledButton/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBStyledButton/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBStyledButton/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBStyledButton/TenantBStyledButtonText.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBStyledButton/TenantBStyledButtonText.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBStyledButton/TenantBStyledButtonText.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSuccess.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSuccess.colorset/Contents.json new file mode 100644 index 000000000..65b3786f0 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBSuccess.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x71", + "green" : "0xA1", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4D", + "green" : "0x7D", + "red" : "0x0D" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTabBarTintColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTabBarTintColor.colorset/Contents.json new file mode 100644 index 000000000..9b3db3386 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTabBarTintColor.colorset/Contents.json @@ -0,0 +1,47 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTabbarColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTabbarColor.colorset/Contents.json new file mode 100644 index 000000000..cd87ac6c6 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTabbarColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "extended-srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4A", + "green" : "0x41", + "red" : "0x2C" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextPrimary.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextPrimary.colorset/Contents.json new file mode 100644 index 000000000..cc0044cca --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextPrimary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2E", + "green" : "0x20", + "red" : "0x18" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextSecondary.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextSecondary.colorset/Contents.json new file mode 100644 index 000000000..e6f1bfdc1 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextSecondary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xCA", + "red" : "0x31" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x9F", + "green" : "0x87", + "red" : "0x79" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextSecondaryLight.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextSecondaryLight.colorset/Contents.json new file mode 100644 index 000000000..93691d3e8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextColor/TenantBTextSecondaryLight.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.624", + "green" : "0.533", + "red" : "0.475" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputBackground.colorset/Contents.json new file mode 100644 index 000000000..164b36790 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputPlaceholderColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputPlaceholderColor.colorset/Contents.json new file mode 100644 index 000000000..93691d3e8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputPlaceholderColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.624", + "green" : "0.533", + "red" : "0.475" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputStroke.colorset/Contents.json new file mode 100644 index 000000000..5cd29db93 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputTextColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputTextColor.colorset/Contents.json new file mode 100644 index 000000000..a3f0c654a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.129", + "red" : "0.098" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputUnfocusedBackground.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputUnfocusedBackground.colorset/Contents.json new file mode 100644 index 000000000..2d9b9cd70 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputUnfocusedBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.984", + "green" : "0.980", + "red" : "0.976" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.275", + "green" : "0.200", + "red" : "0.153" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputUnfocusedStroke.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputUnfocusedStroke.colorset/Contents.json new file mode 100644 index 000000000..432fab345 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBTextInput/TenantBTextInputUnfocusedStroke.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.878", + "green" : "0.831", + "red" : "0.800" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.439", + "green" : "0.353", + "red" : "0.306" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBToggleSwitchColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBToggleSwitchColor.colorset/Contents.json new file mode 100644 index 000000000..13c34a739 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBToggleSwitchColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x8C", + "green" : "0x57", + "red" : "0x3E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5E", + "green" : "0x35", + "red" : "0x1C" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWarning.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWarning.colorset/Contents.json new file mode 100644 index 000000000..db6a639f5 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWarning.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.282", + "green" : "0.761", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWarningText.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWarningText.colorset/Contents.json new file mode 100644 index 000000000..be9d677bb --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWarningText.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWhite.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWhite.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBWhite.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarColor.colorset/Contents.json new file mode 100644 index 000000000..9b3db3386 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarColor.colorset/Contents.json @@ -0,0 +1,47 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xB4", + "green" : "0xC9", + "red" : "0x30" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarColorDark.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarColorDark.colorset/Contents.json new file mode 100644 index 000000000..6cbc923e9 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarColorDark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2F", + "green" : "0x21", + "red" : "0x19" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2F", + "green" : "0x21", + "red" : "0x19" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarTintColor.colorset/Contents.json b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarTintColor.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/TenantBColors/TenantBnavigationBarTintColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/SwiftGen/ThemeAssets.swift b/Theme/Theme/SwiftGen/ThemeAssets.swift index ae82d6f03..a9365a036 100644 --- a/Theme/Theme/SwiftGen/ThemeAssets.swift +++ b/Theme/Theme/SwiftGen/ThemeAssets.swift @@ -81,6 +81,8 @@ public enum ThemeAssets { public static let tabbarActiveColor = ColorAsset(name: "TabbarActiveColor") public static let tabbarBGColor = ColorAsset(name: "TabbarBGColor") public static let tabbarInactiveColor = ColorAsset(name: "TabbarInactiveColor") + public static let tabbarColor = ColorAsset(name: "TabbarColor") + public static let tabbarTintColor = ColorAsset(name: "TabbarTintColor") public static let textPrimary = ColorAsset(name: "TextPrimary") public static let textSecondary = ColorAsset(name: "TextSecondary") public static let textSecondaryLight = ColorAsset(name: "TextSecondaryLight") @@ -92,6 +94,8 @@ public enum ThemeAssets { public static let textInputUnfocusedStroke = ColorAsset(name: "TextInputUnfocusedStroke") public static let toggleSwitchColor = ColorAsset(name: "ToggleSwitchColor") public static let circleProgressBG = ColorAsset(name: "circleProgressBG") + public static let navigationBarColor = ColorAsset(name: "navigationBarColor") + public static let navigationBarColorDark = ColorAsset(name: "navigationBarColorDark") public static let navigationBarTintColor = ColorAsset(name: "navigationBarTintColor") public static let progressLineBG = ColorAsset(name: "progressLineBG") public static let progressPercentage = ColorAsset(name: "progressPercentage") @@ -99,6 +103,136 @@ public enum ThemeAssets { public static let warning = ColorAsset(name: "warning") public static let warningText = ColorAsset(name: "warningText") public static let white = ColorAsset(name: "white") + public static let tenantAAccentButtonColor = ColorAsset(name: "TenantAAccentButtonColor") + public static let tenantAAccentColor = ColorAsset(name: "TenantAAccentColor") + public static let tenantAAccentXColor = ColorAsset(name: "TenantAAccentXColor") + public static let tenantAAlert = ColorAsset(name: "TenantAAlert") + public static let tenantAAvatarStroke = ColorAsset(name: "TenantAAvatarStroke") + public static let tenantABackground = ColorAsset(name: "TenantABackground") + public static let tenantABackgroundStroke = ColorAsset(name: "TenantABackgroundStroke") + public static let tenantACardViewBackground = ColorAsset(name: "TenantACardViewBackground") + public static let tenantACardViewStroke = ColorAsset(name: "TenantACardViewStroke") + public static let tenantACertificateForeground = ColorAsset(name: "TenantACertificateForeground") + public static let tenantACommentCellBackground = ColorAsset(name: "TenantACommentCellBackground") + public static let tenantACourseCardBackground = ColorAsset(name: "TenantACourseCardBackground") + public static let tenantACourseCardShadow = ColorAsset(name: "TenantACourseCardShadow") + public static let tenantADatesSectionBackground = ColorAsset(name: "TenantADatesSectionBackground") + public static let tenantADatesSectionStroke = ColorAsset(name: "TenantADatesSectionStroke") + public static let tenantANextWeekTimelineColor = ColorAsset(name: "TenantANextWeekTimelineColor") + public static let tenantAThisWeekTimelineColor = ColorAsset(name: "TenantAThisWeekTimelineColor") + public static let tenantATodayTimelineColor = ColorAsset(name: "TenantATodayTimelineColor") + public static let tenantAUpcomingTimelineColor = ColorAsset(name: "TenantAUpcomingTimelineColor") + public static let tenantApastDueTimelineColor = ColorAsset(name: "TenantApastDueTimelineColor") + public static let tenantAprimaryHeaderColor = ColorAsset(name: "TenantAprimaryHeaderColor") + public static let tenantAsecondaryHeaderColor = ColorAsset(name: "TenantAsecondaryHeaderColor") + public static let tenantAInfoColor = ColorAsset(name: "TenantAInfoColor") + public static let tenantAIrreversibleAlert = ColorAsset(name: "TenantAIrreversibleAlert") + public static let tenantALoginBackground = ColorAsset(name: "TenantALoginBackground") + public static let tenantALoginNavigationText = ColorAsset(name: "TenantALoginNavigationText") + public static let tenantAPrimaryButtonTextColor = ColorAsset(name: "TenantAPrimaryButtonTextColor") + public static let tenantAPrimaryCardCautionBG = ColorAsset(name: "TenantAPrimaryCardCautionBG") + public static let tenantAPrimaryCardCourseUpgradeBG = ColorAsset(name: "TenantAPrimaryCardCourseUpgradeBG") + public static let tenantAPrimaryCardProgressBG = ColorAsset(name: "TenantAPrimaryCardProgressBG") + public static let tenantAOnProgress = ColorAsset(name: "TenantAOnProgress") + public static let tenantAProgressDone = ColorAsset(name: "TenantAProgressDone") + public static let tenantAProgressSkip = ColorAsset(name: "TenantAProgressSkip") + public static let tenantASelectedAndDone = ColorAsset(name: "TenantASelectedAndDone") + public static let tenantASecondaryButtonBGColor = ColorAsset(name: "TenantASecondaryButtonBGColor") + public static let tenantASecondaryButtonBorderColor = ColorAsset(name: "TenantASecondaryButtonBorderColor") + public static let tenantASecondaryButtonTextColor = ColorAsset(name: "TenantASecondaryButtonTextColor") + public static let tenantAShadowColor = ColorAsset(name: "TenantAShadowColor") + public static let tenantASlidingSelectedTextColor = ColorAsset(name: "TenantASlidingSelectedTextColor") + public static let tenantASlidingStrokeColor = ColorAsset(name: "TenantASlidingStrokeColor") + public static let tenantASlidingTextColor = ColorAsset(name: "TenantASlidingTextColor") + public static let tenantASnackbarErrorColor = ColorAsset(name: "TenantASnackbarErrorColor") + public static let tenantASnackbarInfoColor = ColorAsset(name: "TenantASnackbarInfoColor") + public static let tenantASnackbarTextColor = ColorAsset(name: "TenantASnackbarTextColor") + public static let tenantASnackbarWarningColor = ColorAsset(name: "TenantASnackbarWarningColor") + public static let tenantAStyledButtonText = ColorAsset(name: "TenantAStyledButtonText") + public static let tenantASuccess = ColorAsset(name: "TenantASuccess") + public static let tenantATabBarTintColor = ColorAsset(name: "TenantATabBarTintColor") + public static let tenantATabbarColor = ColorAsset(name: "TenantATabbarColor") + public static let tenantATextPrimary = ColorAsset(name: "TenantATextPrimary") + public static let tenantATextSecondary = ColorAsset(name: "TenantATextSecondary") + public static let tenantATextSecondaryLight = ColorAsset(name: "TenantATextSecondaryLight") + public static let tenantATextInputBackground = ColorAsset(name: "TenantATextInputBackground") + public static let tenantATextInputPlaceholderColor = ColorAsset(name: "TenantATextInputPlaceholderColor") + public static let tenantATextInputStroke = ColorAsset(name: "TenantATextInputStroke") + public static let tenantATextInputTextColor = ColorAsset(name: "TenantATextInputTextColor") + public static let tenantATextInputUnfocusedBackground = ColorAsset(name: "TenantATextInputUnfocusedBackground") + public static let tenantATextInputUnfocusedStroke = ColorAsset(name: "TenantATextInputUnfocusedStroke") + public static let tenantAToggleSwitchColor = ColorAsset(name: "TenantAToggleSwitchColor") + public static let tenantAWarning = ColorAsset(name: "TenantAWarning") + public static let tenantAWarningText = ColorAsset(name: "TenantAWarningText") + public static let tenantAWhite = ColorAsset(name: "TenantAWhite") + public static let tenantAnavigationBarColor = ColorAsset(name: "TenantAnavigationBarColor") + public static let tenantAnavigationBarColorDark = ColorAsset(name: "TenantAnavigationBarColorDark") + public static let tenantAnavigationBarTintColor = ColorAsset(name: "TenantAnavigationBarTintColor") + public static let tenantBAccentButtonColor = ColorAsset(name: "TenantBAccentButtonColor") + public static let tenantBAccentColor = ColorAsset(name: "TenantBAccentColor") + public static let tenantBAccentXColor = ColorAsset(name: "TenantBAccentXColor") + public static let tenantBAlert = ColorAsset(name: "TenantBAlert") + public static let tenantBAvatarStroke = ColorAsset(name: "TenantBAvatarStroke") + public static let tenantBBackground = ColorAsset(name: "TenantBBackground") + public static let tenantBBackgroundStroke = ColorAsset(name: "TenantBBackgroundStroke") + public static let tenantBCardViewBackground = ColorAsset(name: "TenantBCardViewBackground") + public static let tenantBCardViewStroke = ColorAsset(name: "TenantBCardViewStroke") + public static let tenantBCertificateForeground = ColorAsset(name: "TenantBCertificateForeground") + public static let tenantBCommentCellBackground = ColorAsset(name: "TenantBCommentCellBackground") + public static let tenantBCourseCardBackground = ColorAsset(name: "TenantBCourseCardBackground") + public static let tenantBCourseCardShadow = ColorAsset(name: "TenantBCourseCardShadow") + public static let tenantBDatesSectionBackground = ColorAsset(name: "TenantBDatesSectionBackground") + public static let tenantBDatesSectionStroke = ColorAsset(name: "TenantBDatesSectionStroke") + public static let tenantBNextWeekTimelineColor = ColorAsset(name: "TenantBNextWeekTimelineColor") + public static let tenantBThisWeekTimelineColor = ColorAsset(name: "TenantBThisWeekTimelineColor") + public static let tenantBTodayTimelineColor = ColorAsset(name: "TenantBTodayTimelineColor") + public static let tenantBUpcomingTimelineColor = ColorAsset(name: "TenantBUpcomingTimelineColor") + public static let tenantBpastDueTimelineColor = ColorAsset(name: "TenantBpastDueTimelineColor") + public static let tenantBprimaryHeaderColor = ColorAsset(name: "TenantBprimaryHeaderColor") + public static let tenantBsecondaryHeaderColor = ColorAsset(name: "TenantBsecondaryHeaderColor") + public static let tenantBInfoColor = ColorAsset(name: "TenantBInfoColor") + public static let tenantBIrreversibleAlert = ColorAsset(name: "TenantBIrreversibleAlert") + public static let tenantBLoginBackground = ColorAsset(name: "TenantBLoginBackground") + public static let tenantBLoginNavigationText = ColorAsset(name: "TenantBLoginNavigationText") + public static let tenantBPrimaryButtonTextColor = ColorAsset(name: "TenantBPrimaryButtonTextColor") + public static let tenantBPrimaryCardCautionBG = ColorAsset(name: "TenantBPrimaryCardCautionBG") + public static let tenantBPrimaryCardCourseUpgradeBG = ColorAsset(name: "TenantBPrimaryCardCourseUpgradeBG") + public static let tenantBPrimaryCardProgressBG = ColorAsset(name: "TenantBPrimaryCardProgressBG") + public static let tenantBOnProgress = ColorAsset(name: "TenantBOnProgress") + public static let tenantBProgressDone = ColorAsset(name: "TenantBProgressDone") + public static let tenantBProgressSkip = ColorAsset(name: "TenantBProgressSkip") + public static let tenantBSelectedAndDone = ColorAsset(name: "TenantBSelectedAndDone") + public static let tenantBSecondaryButtonBGColor = ColorAsset(name: "TenantBSecondaryButtonBGColor") + public static let tenantBSecondaryButtonBorderColor = ColorAsset(name: "TenantBSecondaryButtonBorderColor") + public static let tenantBSecondaryButtonTextColor = ColorAsset(name: "TenantBSecondaryButtonTextColor") + public static let tenantBShadowColor = ColorAsset(name: "TenantBShadowColor") + public static let tenantBSlidingSelectedTextColor = ColorAsset(name: "TenantBSlidingSelectedTextColor") + public static let tenantBSlidingStrokeColor = ColorAsset(name: "TenantBSlidingStrokeColor") + public static let tenantBSlidingTextColor = ColorAsset(name: "TenantBSlidingTextColor") + public static let tenantBSnackbarErrorColor = ColorAsset(name: "TenantBSnackbarErrorColor") + public static let tenantBSnackbarInfoColor = ColorAsset(name: "TenantBSnackbarInfoColor") + public static let tenantBSnackbarTextColor = ColorAsset(name: "TenantBSnackbarTextColor") + public static let tenantBSnackbarWarningColor = ColorAsset(name: "TenantBSnackbarWarningColor") + public static let tenantBStyledButtonText = ColorAsset(name: "TenantBStyledButtonText") + public static let tenantBSuccess = ColorAsset(name: "TenantBSuccess") + public static let tenantBTabBarTintColor = ColorAsset(name: "TenantBTabBarTintColor") + public static let tenantBTabbarColor = ColorAsset(name: "TenantBTabbarColor") + public static let tenantBTextPrimary = ColorAsset(name: "TenantBTextPrimary") + public static let tenantBTextSecondary = ColorAsset(name: "TenantBTextSecondary") + public static let tenantBTextSecondaryLight = ColorAsset(name: "TenantBTextSecondaryLight") + public static let tenantBTextInputBackground = ColorAsset(name: "TenantBTextInputBackground") + public static let tenantBTextInputPlaceholderColor = ColorAsset(name: "TenantBTextInputPlaceholderColor") + public static let tenantBTextInputStroke = ColorAsset(name: "TenantBTextInputStroke") + public static let tenantBTextInputTextColor = ColorAsset(name: "TenantBTextInputTextColor") + public static let tenantBTextInputUnfocusedBackground = ColorAsset(name: "TenantBTextInputUnfocusedBackground") + public static let tenantBTextInputUnfocusedStroke = ColorAsset(name: "TenantBTextInputUnfocusedStroke") + public static let tenantBToggleSwitchColor = ColorAsset(name: "TenantBToggleSwitchColor") + public static let tenantBWarning = ColorAsset(name: "TenantBWarning") + public static let tenantBWarningText = ColorAsset(name: "TenantBWarningText") + public static let tenantBWhite = ColorAsset(name: "TenantBWhite") + public static let tenantBnavigationBarColor = ColorAsset(name: "TenantBnavigationBarColor") + public static let tenantBnavigationBarColorDark = ColorAsset(name: "TenantBnavigationBarColorDark") + public static let tenantBnavigationBarTintColor = ColorAsset(name: "TenantBnavigationBarTintColor") public static let appLogo = ImageAsset(name: "appLogo") public static let assignmentStroke = ColorAsset(name: "assignmentStroke") public static let headerBackground = ImageAsset(name: "headerBackground") diff --git a/Theme/Theme/Theme.swift b/Theme/Theme/Theme.swift index 3baf42d83..c513c1401 100644 --- a/Theme/Theme/Theme.swift +++ b/Theme/Theme/Theme.swift @@ -12,6 +12,22 @@ private let fontsParser = FontParser() public struct Theme: Sendable { + public struct ThemeConfig: Sendable { + public var name: String + public var appLogo: Image + public var bgColor: Image + + public init( + name: String = "Default", + appLogo: Image = Image(systemName: "app.fill"), + bgColor: Image = Image(systemName: "photo") + ) { + self.name = name + self.appLogo = appLogo + self.bgColor = bgColor + } + } + // swiftlint:disable line_length public struct Colors: Sendable { nonisolated(unsafe) public private(set) static var accentColor = ThemeAssets.accentColor.swiftUIColor @@ -57,10 +73,14 @@ public struct Theme: Sendable { nonisolated(unsafe) public private(set) static var datesSectionBackground = ThemeAssets.datesSectionBackground.swiftUIColor nonisolated(unsafe) public private(set) static var datesSectionStroke = ThemeAssets.datesSectionStroke.swiftUIColor nonisolated(unsafe) public private(set) static var navigationBarTintColor = ThemeAssets.navigationBarTintColor.swiftUIColor + nonisolated(unsafe) public private(set) static var navigationBarColor = ThemeAssets.navigationBarColor.swiftUIColor + nonisolated(unsafe) public private(set) static var navigationBarColorDark = ThemeAssets.navigationBarColorDark.swiftUIColor nonisolated(unsafe) public private(set) static var secondaryButtonBorderColor = ThemeAssets.secondaryButtonBorderColor.swiftUIColor nonisolated(unsafe) public private(set) static var secondaryButtonTextColor = ThemeAssets.secondaryButtonTextColor.swiftUIColor nonisolated(unsafe) public private(set) static var secondaryButtonBGColor = ThemeAssets.secondaryButtonBGColor.swiftUIColor nonisolated(unsafe) public private(set) static var success = ThemeAssets.success.swiftUIColor + nonisolated(unsafe) public private(set) static var tabbarColor = ThemeAssets.tabbarColor.swiftUIColor + nonisolated(unsafe) public private(set) static var tabbarTintColor = ThemeAssets.tabbarTintColor.swiftUIColor nonisolated(unsafe) public private(set) static var primaryButtonTextColor = ThemeAssets.primaryButtonTextColor.swiftUIColor nonisolated(unsafe) public private(set) static var toggleSwitchColor = ThemeAssets.toggleSwitchColor.swiftUIColor nonisolated(unsafe) public private(set) static var textInputTextColor = ThemeAssets.textInputTextColor.swiftUIColor @@ -91,6 +111,7 @@ public struct Theme: Sendable { public static func update( accentColor: Color = ThemeAssets.accentColor.swiftUIColor, accentXColor: Color = ThemeAssets.accentXColor.swiftUIColor, + accentButtonColor: Color = ThemeAssets.accentButtonColor.swiftUIColor, alert: Color = ThemeAssets.alert.swiftUIColor, avatarStroke: Color = ThemeAssets.avatarStroke.swiftUIColor, background: Color = ThemeAssets.background.swiftUIColor, @@ -124,18 +145,28 @@ public struct Theme: Sendable { datesSectionBackground: Color = ThemeAssets.datesSectionBackground.swiftUIColor, datesSectionStroke: Color = ThemeAssets.datesSectionStroke.swiftUIColor, navigationBarTintColor: Color = ThemeAssets.navigationBarTintColor.swiftUIColor, + navigationBarColor: Color = ThemeAssets.navigationBarColor.swiftUIColor, + navigationBarColorDark: Color = ThemeAssets.navigationBarColorDark.swiftUIColor, + loginNavigationText: Color = ThemeAssets.loginNavigationText.swiftUIColor, secondaryButtonBorderColor: Color = ThemeAssets.secondaryButtonBorderColor.swiftUIColor, secondaryButtonTextColor: Color = ThemeAssets.secondaryButtonTextColor.swiftUIColor, success: Color = ThemeAssets.success.swiftUIColor, + tabbarColor: Color = ThemeAssets.tabbarColor.swiftUIColor, + tabbarTintColor: Color = ThemeAssets.tabbarTintColor.swiftUIColor, primaryButtonTextColor: Color = ThemeAssets.primaryButtonTextColor.swiftUIColor, toggleSwitchColor: Color = ThemeAssets.toggleSwitchColor.swiftUIColor, textInputTextColor: Color = ThemeAssets.textInputTextColor.swiftUIColor, textInputPlaceholderColor: Color = ThemeAssets.textInputPlaceholderColor.swiftUIColor, infoColor: Color = ThemeAssets.infoColor.swiftUIColor, - irreversibleAlert: Color = ThemeAssets.irreversibleAlert.swiftUIColor + irreversibleAlert: Color = ThemeAssets.irreversibleAlert.swiftUIColor, + resumeButtonBG: Color = ThemeAssets.resumeButtonBG.swiftUIColor, + resumeButtonText: Color = ThemeAssets.resumeButtonText.swiftUIColor, + primaryCardCautionBG: Color = ThemeAssets.primaryCardCautionBG.swiftUIColor, + primaryCardProgressBG: Color = ThemeAssets.primaryCardProgressBG.swiftUIColor ) { self.accentColor = accentColor self.accentXColor = accentXColor + self.accentButtonColor = accentButtonColor self.alert = alert self.avatarStroke = avatarStroke self.background = background @@ -169,15 +200,24 @@ public struct Theme: Sendable { self.datesSectionBackground = datesSectionBackground self.datesSectionStroke = datesSectionStroke self.navigationBarTintColor = navigationBarTintColor + self.navigationBarColor = navigationBarColor + self.navigationBarColorDark = navigationBarColorDark + self.loginNavigationText = loginNavigationText self.secondaryButtonBorderColor = secondaryButtonBorderColor self.secondaryButtonTextColor = secondaryButtonTextColor self.success = success + self.tabbarColor = tabbarColor + self.tabbarTintColor = tabbarTintColor self.primaryButtonTextColor = primaryButtonTextColor self.toggleSwitchColor = toggleSwitchColor self.textInputTextColor = textInputTextColor self.textInputPlaceholderColor = textInputPlaceholderColor self.infoColor = infoColor self.irreversibleAlert = irreversibleAlert + self.resumeButtonBG = resumeButtonBG + self.resumeButtonText = resumeButtonText + self.primaryCardCautionBG = primaryCardCautionBG + self.primaryCardProgressBG = primaryCardProgressBG } } // swiftlint:enable line_length @@ -187,8 +227,12 @@ public struct Theme: Sendable { nonisolated(unsafe) public private(set) static var textPrimary = ThemeAssets.textPrimary.color nonisolated(unsafe) public private(set) static var accentColor = ThemeAssets.accentColor.color nonisolated(unsafe) public private(set) static var accentXColor = ThemeAssets.accentXColor.color + nonisolated(unsafe) public private(set) static var loginNavigationText = ThemeAssets.loginNavigationText.color nonisolated(unsafe) public private(set) static var navigationBarTintColor = ThemeAssets.navigationBarTintColor.color + nonisolated(unsafe) public private(set) static var navigationBarColor = ThemeAssets.navigationBarColor.color + nonisolated(unsafe) public private(set) static var navigationBarColorDark = + ThemeAssets.navigationBarColorDark.color nonisolated(unsafe) public private(set) static var tabbarActiveColor = ThemeAssets.tabbarActiveColor.color nonisolated(unsafe) public private(set) static var tabbarBGColor = ThemeAssets.tabbarBGColor.color nonisolated(unsafe) public private(set) static var tabbarInactiveColor = ThemeAssets.tabbarInactiveColor.color @@ -197,12 +241,18 @@ public struct Theme: Sendable { textPrimary: UIColor = ThemeAssets.textPrimary.color, accentColor: UIColor = ThemeAssets.accentColor.color, accentXColor: UIColor = ThemeAssets.accentXColor.color, - navigationBarTintColor: UIColor = ThemeAssets.navigationBarTintColor.color + navigationBarTintColor: UIColor = ThemeAssets.navigationBarTintColor.color, + navigationBarColor: UIColor = ThemeAssets.navigationBarColor.color, + navigationBarColorDark: UIColor = ThemeAssets.navigationBarColorDark.color, + loginNavigationText: UIColor = ThemeAssets.loginNavigationText.color ) { self.textPrimary = textPrimary self.accentColor = accentColor self.accentXColor = accentXColor self.navigationBarTintColor = navigationBarTintColor + self.navigationBarColor = navigationBarColor + self.navigationBarColorDark = navigationBarColorDark + self.loginNavigationText = loginNavigationText } } @@ -337,6 +387,15 @@ public extension Theme.Fonts { // swiftlint:enable type_name } +public extension Theme { + @MainActor + static var config: ThemeConfig = .init() + @MainActor + static func updateConfig(_ config: ThemeConfig) { + self.config = config + } +} + extension View { public func loadFonts() -> some View { Theme.Fonts.registerFonts() diff --git a/Theme/Theme/ThemeColorSet.swift b/Theme/Theme/ThemeColorSet.swift new file mode 100644 index 000000000..d07537e24 --- /dev/null +++ b/Theme/Theme/ThemeColorSet.swift @@ -0,0 +1,256 @@ +// +// ThemeColorSet.swift +// Theme +// +// Created by Rawan Matar on 12/05/2025. +// + +import SwiftUI + +public struct ThemeColorSet: Sendable { + public var accentColor = ThemeAssets.accentColor.swiftUIColor + public var accentXColor = ThemeAssets.accentXColor.swiftUIColor + public var accentButtonColor = ThemeAssets.accentButtonColor.swiftUIColor + public var alert = ThemeAssets.alert.swiftUIColor + public var avatarStroke = ThemeAssets.avatarStroke.swiftUIColor + public var background = ThemeAssets.background.swiftUIColor + public var loginBackground = ThemeAssets.loginBackground.swiftUIColor + public var backgroundStroke = ThemeAssets.backgroundStroke.swiftUIColor + public var cardViewBackground = ThemeAssets.cardViewBackground.swiftUIColor + public var cardViewStroke = ThemeAssets.cardViewStroke.swiftUIColor + public var certificateForeground = ThemeAssets.certificateForeground.swiftUIColor + public var commentCellBackground = ThemeAssets.commentCellBackground.swiftUIColor + public var nextWeekTimelineColor = ThemeAssets.nextWeekTimelineColor.swiftUIColor + public var pastDueTimelineColor = ThemeAssets.pastDueTimelineColor.swiftUIColor + public var thisWeekTimelineColor = ThemeAssets.thisWeekTimelineColor.swiftUIColor + public var todayTimelineColor = ThemeAssets.todayTimelineColor.swiftUIColor + public var upcomingTimelineColor = ThemeAssets.upcomingTimelineColor.swiftUIColor + public var shadowColor = ThemeAssets.shadowColor.swiftUIColor + public var snackbarErrorColor = ThemeAssets.snackbarErrorColor.swiftUIColor + public var snackbarWarningColor = ThemeAssets.snackbarWarningColor.swiftUIColor + public var snackbarInfoColor = ThemeAssets.snackbarInfoColor.swiftUIColor + public var snackbarTextColor = ThemeAssets.snackbarTextColor.swiftUIColor + public var styledButtonText = ThemeAssets.styledButtonText.swiftUIColor + public var textPrimary = ThemeAssets.textPrimary.swiftUIColor + public var textSecondary = ThemeAssets.textSecondary.swiftUIColor + public var textSecondaryLight = ThemeAssets.textSecondaryLight.swiftUIColor + public var textInputBackground = ThemeAssets.textInputBackground.swiftUIColor + public var textInputStroke = ThemeAssets.textInputStroke.swiftUIColor + public var textInputUnfocusedBackground = ThemeAssets.textInputUnfocusedBackground.swiftUIColor + public var textInputUnfocusedStroke = ThemeAssets.textInputUnfocusedStroke.swiftUIColor + public var warning = ThemeAssets.warning.swiftUIColor + public var warningText = ThemeAssets.warningText.swiftUIColor + public var white = ThemeAssets.white.swiftUIColor + public var onProgress = ThemeAssets.onProgress.swiftUIColor + public var progressDone = ThemeAssets.progressDone.swiftUIColor + public var progressSkip = ThemeAssets.progressSkip.swiftUIColor + public var progressSelectedAndDone = ThemeAssets.selectedAndDone.swiftUIColor + public var loginNavigationText = ThemeAssets.loginNavigationText.swiftUIColor + public var datesSectionBackground = ThemeAssets.datesSectionBackground.swiftUIColor + public var datesSectionStroke = ThemeAssets.datesSectionStroke.swiftUIColor + public var navigationBarTintColor = ThemeAssets.navigationBarTintColor.swiftUIColor + public var navigationBarColor = ThemeAssets.navigationBarColor.swiftUIColor + public var navigationBarColorDark = ThemeAssets.navigationBarColorDark.swiftUIColor + public var secondaryButtonBorderColor = ThemeAssets.secondaryButtonBorderColor.swiftUIColor + public var secondaryButtonTextColor = ThemeAssets.secondaryButtonTextColor.swiftUIColor + public var secondaryButtonBGColor = ThemeAssets.secondaryButtonBGColor.swiftUIColor + public var success = ThemeAssets.success.swiftUIColor + public var tabbarColor = ThemeAssets.tabbarColor.swiftUIColor + public var tabbarTintColor = ThemeAssets.tabbarTintColor.swiftUIColor + public var primaryButtonTextColor = ThemeAssets.primaryButtonTextColor.swiftUIColor + public var toggleSwitchColor = ThemeAssets.toggleSwitchColor.swiftUIColor + public var textInputTextColor = ThemeAssets.textInputTextColor.swiftUIColor + public var textInputPlaceholderColor = ThemeAssets.textInputPlaceholderColor.swiftUIColor + public var infoColor = ThemeAssets.infoColor.swiftUIColor + public var irreversibleAlert = ThemeAssets.irreversibleAlert.swiftUIColor + public var slidingTextColor = ThemeAssets.slidingTextColor.swiftUIColor + public var slidingSelectedTextColor = ThemeAssets.slidingSelectedTextColor.swiftUIColor + public var slidingStrokeColor = ThemeAssets.slidingStrokeColor.swiftUIColor + public var primaryHeaderColor = ThemeAssets.primaryHeaderColor.swiftUIColor + public var secondaryHeaderColor = ThemeAssets.secondaryHeaderColor.swiftUIColor + public var courseCardShadow = ThemeAssets.courseCardShadow.swiftUIColor + public var courseCardBackground = ThemeAssets.courseCardBackground.swiftUIColor + public var resumeButtonBG = ThemeAssets.resumeButtonBG.swiftUIColor + public var resumeButtonText = ThemeAssets.resumeButtonText.swiftUIColor + public var primaryCardCautionBG = ThemeAssets.primaryCardCautionBG.swiftUIColor + public var primaryCardProgressBG = ThemeAssets.primaryCardProgressBG.swiftUIColor + public var courseProgressBG = ThemeAssets.courseProgressBG.swiftUIColor + public var deleteAccountBG = ThemeAssets.deleteAccountBG.swiftUIColor + + public static let `default` = ThemeColorSet( + accentColor: ThemeAssets.accentColor.swiftUIColor, + accentXColor: ThemeAssets.accentXColor.swiftUIColor, + accentButtonColor: ThemeAssets.accentButtonColor.swiftUIColor, + alert: ThemeAssets.alert.swiftUIColor, + avatarStroke: ThemeAssets.avatarStroke.swiftUIColor, + background: ThemeAssets.background.swiftUIColor, + backgroundStroke: ThemeAssets.backgroundStroke.swiftUIColor, + cardViewBackground: ThemeAssets.cardViewStroke.swiftUIColor, + cardViewStroke: ThemeAssets.cardViewStroke.swiftUIColor, + certificateForeground: ThemeAssets.certificateForeground.swiftUIColor, + commentCellBackground: ThemeAssets.commentCellBackground.swiftUIColor, + nextWeekTimelineColor: ThemeAssets.nextWeekTimelineColor.swiftUIColor, + pastDueTimelineColor: ThemeAssets.pastDueTimelineColor.swiftUIColor, + thisWeekTimelineColor: ThemeAssets.thisWeekTimelineColor.swiftUIColor, + todayTimelineColor: ThemeAssets.todayTimelineColor.swiftUIColor, + upcomingTimelineColor: ThemeAssets.upcomingTimelineColor.swiftUIColor, + shadowColor: ThemeAssets.shadowColor.swiftUIColor, + snackbarErrorColor: ThemeAssets.snackbarErrorColor.swiftUIColor, + snackbarInfoColor: ThemeAssets.snackbarInfoColor.swiftUIColor, + snackbarTextColor: ThemeAssets.snackbarTextColor.swiftUIColor, + styledButtonText: ThemeAssets.styledButtonText.swiftUIColor, + textPrimary: ThemeAssets.textPrimary.swiftUIColor, + textSecondary: ThemeAssets.textSecondary.swiftUIColor, + textSecondaryLight: ThemeAssets.textSecondaryLight.swiftUIColor, + textInputBackground: ThemeAssets.textInputBackground.swiftUIColor, + textInputStroke: ThemeAssets.textInputStroke.swiftUIColor, + textInputUnfocusedBackground: ThemeAssets.textInputUnfocusedBackground.swiftUIColor, + textInputUnfocusedStroke: ThemeAssets.textInputUnfocusedStroke.swiftUIColor, + warning: ThemeAssets.warning.swiftUIColor, + white: ThemeAssets.white.swiftUIColor, + onProgress: ThemeAssets.onProgress.swiftUIColor, + progressDone: ThemeAssets.progressDone.swiftUIColor, + progressSkip: ThemeAssets.progressSkip.swiftUIColor, + datesSectionBackground: ThemeAssets.datesSectionBackground.swiftUIColor, + datesSectionStroke: ThemeAssets.datesSectionStroke.swiftUIColor, + navigationBarTintColor: ThemeAssets.navigationBarTintColor.swiftUIColor, + navigationBarColor: ThemeAssets.navigationBarColor.swiftUIColor, + navigationBarColorDark: ThemeAssets.navigationBarColorDark.swiftUIColor, + + secondaryButtonBorderColor: ThemeAssets.secondaryButtonBorderColor.swiftUIColor, + secondaryButtonTextColor: ThemeAssets.secondaryButtonTextColor.swiftUIColor, + success: ThemeAssets.success.swiftUIColor, + tabbarColor: ThemeAssets.tabbarColor.swiftUIColor, + tabbarTintColor: ThemeAssets.tenantATabBarTintColor.swiftUIColor, + primaryButtonTextColor: ThemeAssets.primaryButtonTextColor.swiftUIColor, + toggleSwitchColor: ThemeAssets.toggleSwitchColor.swiftUIColor, + textInputTextColor: ThemeAssets.textInputTextColor.swiftUIColor, + textInputPlaceholderColor: ThemeAssets.textInputPlaceholderColor.swiftUIColor, + infoColor: ThemeAssets.infoColor.swiftUIColor, + irreversibleAlert: ThemeAssets.irreversibleAlert.swiftUIColor, + resumeButtonBG: ThemeAssets.resumeButtonBG.swiftUIColor, + resumeButtonText: ThemeAssets.resumeButtonText.swiftUIColor, + primaryCardCautionBG: ThemeAssets.primaryCardCautionBG.swiftUIColor, + primaryCardProgressBG: ThemeAssets.primaryCardProgressBG.swiftUIColor, + courseProgressBG: ThemeAssets.courseProgressBG.swiftUIColor, + deleteAccountBG: ThemeAssets.deleteAccountBG.swiftUIColor + ) + + public static let tenantA = ThemeColorSet( + accentColor: ThemeAssets.tenantAAccentColor.swiftUIColor, + accentXColor: ThemeAssets.tenantAAccentXColor.swiftUIColor, + accentButtonColor: ThemeAssets.tenantAAccentButtonColor.swiftUIColor, + alert: ThemeAssets.tenantAAlert.swiftUIColor, + avatarStroke: ThemeAssets.tenantAAvatarStroke.swiftUIColor, + background: ThemeAssets.tenantABackground.swiftUIColor, + backgroundStroke: ThemeAssets.tenantABackgroundStroke.swiftUIColor, + cardViewBackground: ThemeAssets.tenantACardViewStroke.swiftUIColor, + cardViewStroke: ThemeAssets.tenantACardViewStroke.swiftUIColor, + certificateForeground: ThemeAssets.tenantACertificateForeground.swiftUIColor, + commentCellBackground: ThemeAssets.tenantACommentCellBackground.swiftUIColor, + nextWeekTimelineColor: ThemeAssets.tenantANextWeekTimelineColor.swiftUIColor, + pastDueTimelineColor: ThemeAssets.tenantApastDueTimelineColor.swiftUIColor, + thisWeekTimelineColor: ThemeAssets.tenantAThisWeekTimelineColor.swiftUIColor, + todayTimelineColor: ThemeAssets.tenantATodayTimelineColor.swiftUIColor, + upcomingTimelineColor: ThemeAssets.tenantAUpcomingTimelineColor.swiftUIColor, + shadowColor: ThemeAssets.tenantAShadowColor.swiftUIColor, + snackbarErrorColor: ThemeAssets.tenantASnackbarErrorColor.swiftUIColor, + snackbarInfoColor: ThemeAssets.tenantASnackbarInfoColor.swiftUIColor, + snackbarTextColor: ThemeAssets.tenantASnackbarTextColor.swiftUIColor, + styledButtonText: ThemeAssets.tenantAStyledButtonText.swiftUIColor, + textPrimary: ThemeAssets.tenantATextPrimary.swiftUIColor, + textSecondary: ThemeAssets.tenantATextSecondary.swiftUIColor, + textSecondaryLight: ThemeAssets.tenantATextSecondaryLight.swiftUIColor, + textInputBackground: ThemeAssets.tenantATextInputBackground.swiftUIColor, + textInputStroke: ThemeAssets.tenantATextInputStroke.swiftUIColor, + textInputUnfocusedBackground: ThemeAssets.tenantATextInputUnfocusedBackground.swiftUIColor, + textInputUnfocusedStroke: ThemeAssets.tenantATextInputUnfocusedStroke.swiftUIColor, + warning: ThemeAssets.tenantAWarning.swiftUIColor, + white: ThemeAssets.tenantAWhite.swiftUIColor, + onProgress: ThemeAssets.tenantAOnProgress.swiftUIColor, + progressDone: ThemeAssets.tenantAProgressDone.swiftUIColor, + progressSkip: ThemeAssets.tenantAProgressSkip.swiftUIColor, + loginNavigationText: ThemeAssets.tenantALoginNavigationText.swiftUIColor, + datesSectionBackground: ThemeAssets.tenantADatesSectionBackground.swiftUIColor, + datesSectionStroke: ThemeAssets.tenantADatesSectionStroke.swiftUIColor, + navigationBarTintColor: ThemeAssets.tenantAnavigationBarTintColor.swiftUIColor, + navigationBarColor: ThemeAssets.tenantAnavigationBarColor.swiftUIColor, + navigationBarColorDark: ThemeAssets.tenantAnavigationBarColorDark.swiftUIColor, + secondaryButtonBorderColor: ThemeAssets.tenantASecondaryButtonBorderColor.swiftUIColor, + secondaryButtonTextColor: ThemeAssets.tenantASecondaryButtonTextColor.swiftUIColor, + success: ThemeAssets.tenantASuccess.swiftUIColor, + tabbarColor: ThemeAssets.tenantATabbarColor.swiftUIColor, + tabbarTintColor: ThemeAssets.tenantATabBarTintColor.swiftUIColor, + primaryButtonTextColor: ThemeAssets.tenantAPrimaryButtonTextColor.swiftUIColor, + toggleSwitchColor: ThemeAssets.tenantAToggleSwitchColor.swiftUIColor, + textInputTextColor: ThemeAssets.tenantATextInputTextColor.swiftUIColor, + textInputPlaceholderColor: ThemeAssets.tenantATextInputPlaceholderColor.swiftUIColor, + infoColor: ThemeAssets.tenantAInfoColor.swiftUIColor, + irreversibleAlert: ThemeAssets.tenantAIrreversibleAlert.swiftUIColor, + resumeButtonBG: ThemeAssets.resumeButtonBG.swiftUIColor, + resumeButtonText: ThemeAssets.resumeButtonText.swiftUIColor, + primaryCardCautionBG: ThemeAssets.tenantAPrimaryCardCautionBG.swiftUIColor, + primaryCardProgressBG: ThemeAssets.primaryCardProgressBG.swiftUIColor, + courseProgressBG: ThemeAssets.courseProgressBG.swiftUIColor, + deleteAccountBG: ThemeAssets.deleteAccountBG.swiftUIColor + ) + + public static let tenantB = ThemeColorSet( + accentColor: ThemeAssets.tenantBAccentColor.swiftUIColor, + accentXColor: ThemeAssets.tenantBAccentXColor.swiftUIColor, + accentButtonColor: ThemeAssets.tenantBAccentButtonColor.swiftUIColor, + alert: ThemeAssets.tenantBAlert.swiftUIColor, + avatarStroke: ThemeAssets.tenantBAvatarStroke.swiftUIColor, + background: ThemeAssets.tenantBBackground.swiftUIColor, + backgroundStroke: ThemeAssets.tenantBBackgroundStroke.swiftUIColor, + cardViewBackground: ThemeAssets.tenantBCardViewStroke.swiftUIColor, + cardViewStroke: ThemeAssets.tenantBCardViewStroke.swiftUIColor, + certificateForeground: ThemeAssets.tenantBCertificateForeground.swiftUIColor, + commentCellBackground: ThemeAssets.tenantBCommentCellBackground.swiftUIColor, + nextWeekTimelineColor: ThemeAssets.tenantBNextWeekTimelineColor.swiftUIColor, + pastDueTimelineColor: ThemeAssets.tenantBpastDueTimelineColor.swiftUIColor, + thisWeekTimelineColor: ThemeAssets.tenantBThisWeekTimelineColor.swiftUIColor, + todayTimelineColor: ThemeAssets.tenantBTodayTimelineColor.swiftUIColor, + upcomingTimelineColor: ThemeAssets.tenantBUpcomingTimelineColor.swiftUIColor, + shadowColor: ThemeAssets.tenantBShadowColor.swiftUIColor, + snackbarErrorColor: ThemeAssets.tenantBSnackbarErrorColor.swiftUIColor, + snackbarInfoColor: ThemeAssets.tenantBSnackbarInfoColor.swiftUIColor, + snackbarTextColor: ThemeAssets.tenantBSnackbarTextColor.swiftUIColor, + styledButtonText: ThemeAssets.tenantBStyledButtonText.swiftUIColor, + textPrimary: ThemeAssets.tenantBTextPrimary.swiftUIColor, + textSecondary: ThemeAssets.tenantBTextSecondary.swiftUIColor, + textSecondaryLight: ThemeAssets.tenantBTextSecondaryLight.swiftUIColor, + textInputBackground: ThemeAssets.tenantBTextInputBackground.swiftUIColor, + textInputStroke: ThemeAssets.tenantBTextInputStroke.swiftUIColor, + textInputUnfocusedBackground: ThemeAssets.tenantBTextInputUnfocusedBackground.swiftUIColor, + textInputUnfocusedStroke: ThemeAssets.tenantBTextInputUnfocusedStroke.swiftUIColor, + warning: ThemeAssets.tenantBWarning.swiftUIColor, + white: ThemeAssets.tenantBWhite.swiftUIColor, + onProgress: ThemeAssets.tenantBOnProgress.swiftUIColor, + progressDone: ThemeAssets.tenantBProgressDone.swiftUIColor, + progressSkip: ThemeAssets.tenantBProgressSkip.swiftUIColor, + loginNavigationText: ThemeAssets.tenantBLoginNavigationText.swiftUIColor, + datesSectionBackground: ThemeAssets.tenantBDatesSectionBackground.swiftUIColor, + datesSectionStroke: ThemeAssets.tenantBDatesSectionStroke.swiftUIColor, + navigationBarTintColor: ThemeAssets.tenantBnavigationBarTintColor.swiftUIColor, + navigationBarColor: ThemeAssets.tenantBnavigationBarColor.swiftUIColor, + navigationBarColorDark: ThemeAssets.tenantBnavigationBarColorDark.swiftUIColor, + secondaryButtonBorderColor: ThemeAssets.tenantBSecondaryButtonBorderColor.swiftUIColor, + secondaryButtonTextColor: ThemeAssets.tenantBSecondaryButtonTextColor.swiftUIColor, + success: ThemeAssets.tenantBSuccess.swiftUIColor, + tabbarColor: ThemeAssets.tenantBTabbarColor.swiftUIColor, + tabbarTintColor: ThemeAssets.tenantBTabBarTintColor.swiftUIColor, + primaryButtonTextColor: ThemeAssets.tenantBPrimaryButtonTextColor.swiftUIColor, + toggleSwitchColor: ThemeAssets.tenantBToggleSwitchColor.swiftUIColor, + textInputTextColor: ThemeAssets.tenantBTextInputTextColor.swiftUIColor, + textInputPlaceholderColor: ThemeAssets.tenantBTextInputPlaceholderColor.swiftUIColor, + infoColor: ThemeAssets.tenantBInfoColor.swiftUIColor, + irreversibleAlert: ThemeAssets.tenantBIrreversibleAlert.swiftUIColor, + resumeButtonBG: ThemeAssets.resumeButtonBG.swiftUIColor, + resumeButtonText: ThemeAssets.resumeButtonText.swiftUIColor, + primaryCardCautionBG: ThemeAssets.tenantBPrimaryCardCautionBG.swiftUIColor, + primaryCardProgressBG: ThemeAssets.primaryCardProgressBG.swiftUIColor, + courseProgressBG: ThemeAssets.courseProgressBG.swiftUIColor, + deleteAccountBG: ThemeAssets.deleteAccountBG.swiftUIColor + ) +} diff --git a/Theme/Theme/ThemeDefinition.swift b/Theme/Theme/ThemeDefinition.swift new file mode 100644 index 000000000..0c4eae8e0 --- /dev/null +++ b/Theme/Theme/ThemeDefinition.swift @@ -0,0 +1,48 @@ +// +// ThemeDefinition.swift +// Theme +// +// Created by Rawan Matar on 12/05/2025. +// + +import SwiftUI + +public struct ThemeDefinition: Sendable { + public var name: String + public var appLogo: Image + public var bgColor: Image + public var colors: ThemeColorSet + public var fonts: ThemeFontSet + + public init(colors: ThemeColorSet, fonts: ThemeFontSet, appLogo: Image, bgColor: Image, name: String) { + self.colors = colors + self.fonts = fonts + self.appLogo = appLogo + self.bgColor = bgColor + self.name = name + } + + public static let `default` = ThemeDefinition( + colors: .default, + fonts: .default, + appLogo: ThemeAssets.appLogo.swiftUIImage, + bgColor: ThemeAssets.headerBackground.swiftUIImage, + name: "default" + ) + + public static let tenantA = ThemeDefinition( + colors: .tenantA, + fonts: .tenantA, + appLogo: ThemeAssets.appLogo.swiftUIImage, + bgColor: ThemeAssets.headerBackground.swiftUIImage, + name: "TenantA" + ) + + public static let tenantB = ThemeDefinition( + colors: .tenantB, + fonts: .tenantB, + appLogo: ThemeAssets.appLogo.swiftUIImage, + bgColor: ThemeAssets.headerBackground.swiftUIImage, + name: "TenantB" + ) +} diff --git a/Theme/Theme/ThemeFontSet.swift b/Theme/Theme/ThemeFontSet.swift new file mode 100644 index 000000000..2bbc2789e --- /dev/null +++ b/Theme/Theme/ThemeFontSet.swift @@ -0,0 +1,33 @@ +// +// ThemeFontSet.swift +// Theme +// +// Created by Rawan Matar on 12/05/2025. +// + +import SwiftUI + +public struct ThemeFontSet: Sendable { + public var titleMedium: Font + public var bodyLarge: Font + public var labelSmall: Font + // Add more font variants as needed + + public static let `default` = ThemeFontSet( + titleMedium: Theme.Fonts.titleMedium, + bodyLarge: Theme.Fonts.bodyLarge, + labelSmall: Theme.Fonts.labelSmall + ) + + public static let tenantA = ThemeFontSet( + titleMedium: .custom("Georgia-Bold", size: 18), + bodyLarge: .custom("Georgia", size: 16), + labelSmall: .custom("Georgia-Italic", size: 10) + ) + + public static let tenantB = ThemeFontSet( + titleMedium: .custom("Georgia-Bold", size: 18), + bodyLarge: .custom("Georgia", size: 16), + labelSmall: .custom("Georgia-Italic", size: 10) + ) +} diff --git a/Theme/Theme/ThemeManager.swift b/Theme/Theme/ThemeManager.swift new file mode 100644 index 000000000..860117a05 --- /dev/null +++ b/Theme/Theme/ThemeManager.swift @@ -0,0 +1,107 @@ +// +// ThemeManager.swift +// Theme +// +// Created by Rawan Matar on 12/05/2025. +// +import Foundation +import Combine +import SwiftUI + +@MainActor +public final class ThemeManager: ObservableObject { + public static let shared = ThemeManager() + + @Published public private(set) var theme: ThemeDefinition + + private init() { + self.theme = .default // Initial theme + } + + public func applyTheme(for tenantName: String, localizedName: String) { + let selectedTheme: ThemeDefinition + switch tenantName.lowercased() { + case "tenanta": + selectedTheme = .tenantA + case "tenantb": + selectedTheme = .tenantB + default: + selectedTheme = .default + } + + DispatchQueue.main.async { [self] in + Theme.updateConfig(.init( + name: localizedName, + appLogo: Image("tenantA_logo"), + bgColor: Image("tenantA_background") + )) + self.theme = selectedTheme + self.theme.name = localizedName + // Optional: update static Theme values here + Theme.Colors.update( + accentColor: selectedTheme.colors.accentColor, + accentXColor: selectedTheme.colors.accentXColor, + accentButtonColor: selectedTheme.colors.accentButtonColor, + alert: selectedTheme.colors.alert, + avatarStroke: selectedTheme.colors.avatarStroke, + background: selectedTheme.colors.background, + backgroundStroke: selectedTheme.colors.backgroundStroke, + cardViewBackground: selectedTheme.colors.cardViewBackground, + cardViewStroke: selectedTheme.colors.cardViewStroke, + certificateForeground: selectedTheme.colors.certificateForeground, + commentCellBackground: selectedTheme.colors.commentCellBackground, + nextWeekTimelineColor: selectedTheme.colors.nextWeekTimelineColor, + pastDueTimelineColor: selectedTheme.colors.pastDueTimelineColor, + thisWeekTimelineColor: selectedTheme.colors.thisWeekTimelineColor, + todayTimelineColor: selectedTheme.colors.todayTimelineColor, + upcomingTimelineColor: selectedTheme.colors.upcomingTimelineColor, + shadowColor: selectedTheme.colors.shadowColor, + snackbarErrorColor: selectedTheme.colors.snackbarErrorColor, + snackbarInfoColor: selectedTheme.colors.snackbarInfoColor, + snackbarTextColor: selectedTheme.colors.snackbarTextColor, + styledButtonText: selectedTheme.colors.styledButtonText, + textPrimary: selectedTheme.colors.textPrimary, + textSecondary: selectedTheme.colors.textSecondary, + textSecondaryLight: selectedTheme.colors.textSecondaryLight, + textInputBackground: selectedTheme.colors.textInputBackground, + textInputStroke: selectedTheme.colors.textInputStroke, + textInputUnfocusedBackground: selectedTheme.colors.textInputUnfocusedBackground, + textInputUnfocusedStroke: selectedTheme.colors.textInputUnfocusedStroke, + warning: selectedTheme.colors.warning, + white: selectedTheme.colors.white, + onProgress: selectedTheme.colors.onProgress, + progressDone: selectedTheme.colors.progressDone, + progressSkip: selectedTheme.colors.progressSkip, + datesSectionBackground: selectedTheme.colors.datesSectionBackground, + datesSectionStroke: selectedTheme.colors.datesSectionStroke, + navigationBarTintColor: selectedTheme.colors.navigationBarTintColor, + navigationBarColor: selectedTheme.colors.navigationBarColor, + navigationBarColorDark: selectedTheme.colors.navigationBarColorDark, + loginNavigationText: selectedTheme.colors.loginNavigationText, + secondaryButtonBorderColor: selectedTheme.colors.secondaryButtonBorderColor, + secondaryButtonTextColor: selectedTheme.colors.secondaryButtonTextColor, + success: selectedTheme.colors.success, + tabbarColor: selectedTheme.colors.tabbarColor, + tabbarTintColor: selectedTheme.colors.tabbarTintColor, + primaryButtonTextColor: selectedTheme.colors.primaryButtonTextColor, + toggleSwitchColor: selectedTheme.colors.toggleSwitchColor, + textInputTextColor: selectedTheme.colors.textInputTextColor, + textInputPlaceholderColor: selectedTheme.colors.textInputPlaceholderColor, + infoColor: selectedTheme.colors.infoColor, + irreversibleAlert: selectedTheme.colors.irreversibleAlert, + resumeButtonBG: selectedTheme.colors.resumeButtonBG, + resumeButtonText: selectedTheme.colors.resumeButtonText + ) + + Theme.UIColors.update( + textPrimary: UIColor(selectedTheme.colors.textPrimary), + accentColor: UIColor(selectedTheme.colors.accentColor), + accentXColor: UIColor(selectedTheme.colors.accentXColor), + navigationBarTintColor: UIColor(selectedTheme.colors.navigationBarTintColor), + navigationBarColor: UIColor(selectedTheme.colors.navigationBarColor), + navigationBarColorDark: UIColor(selectedTheme.colors.navigationBarColorDark), + loginNavigationText: UIColor(selectedTheme.colors.loginNavigationText), + ) + } + } +} diff --git a/WhatsNew/WhatsNew.xcodeproj/project.pbxproj b/WhatsNew/WhatsNew.xcodeproj/project.pbxproj index d1456fe36..52b04c995 100644 --- a/WhatsNew/WhatsNew.xcodeproj/project.pbxproj +++ b/WhatsNew/WhatsNew.xcodeproj/project.pbxproj @@ -80,9 +80,11 @@ 1E3F4487E7D3A48F5FD12DDA /* Pods-App-WhatsNew-WhatsNewTests.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.releasestage.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.releasestage.xcconfig"; sourceTree = ""; }; 34C1F2BEAF7F0DCB8E630F33 /* Pods-App-WhatsNew.releasestage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.releasestage.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.releasestage.xcconfig"; sourceTree = ""; }; 365FD817D70DFBCBDE2EAE5F /* Pods-App-WhatsNew-WhatsNewTests.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.releaseprod.xcconfig"; sourceTree = ""; }; + 36C9BD94FF0649CD8947A60F /* Pods-App-WhatsNew.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.debugprodtenants.xcconfig"; sourceTree = ""; }; 4CB92C9DBA730A1B06B076BA /* Pods-App-WhatsNew.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.release.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.release.xcconfig"; sourceTree = ""; }; 58DF8140E3B3436F58C4C8B9 /* Pods-App-WhatsNew-WhatsNewTests.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.releasedev.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.releasedev.xcconfig"; sourceTree = ""; }; 6F50A409FBCCC7C08712A25E /* Pods-App-WhatsNew.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.debugdev.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.debugdev.xcconfig"; sourceTree = ""; }; + 88A20F75D477B3BD8737F0A7 /* Pods-App-WhatsNew-WhatsNewTests.debugprodtenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.debugprodtenants.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.debugprodtenants.xcconfig"; sourceTree = ""; }; 9176CDC000731B73D2F10372 /* Pods-App-WhatsNew.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.debugstage.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.debugstage.xcconfig"; sourceTree = ""; }; 9844714991FA40ECDC228CC9 /* Pods-App-WhatsNew.releasedev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.releasedev.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.releasedev.xcconfig"; sourceTree = ""; }; A2CABA11F5E7F89EFD9A05AC /* Pods-App-WhatsNew-WhatsNewTests.debugstage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.debugstage.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.debugstage.xcconfig"; sourceTree = ""; }; @@ -90,9 +92,11 @@ A76975E21FF282D59CEC4452 /* Pods-App-WhatsNew.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.debugprod.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.debugprod.xcconfig"; sourceTree = ""; }; AB8156676C9C771D691ADE07 /* Pods-App-WhatsNew.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.releaseprod.xcconfig"; sourceTree = ""; }; B7EAC5E8F0ED2F1F81050C30 /* Pods-App-WhatsNew-WhatsNewTests.debugprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.debugprod.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.debugprod.xcconfig"; sourceTree = ""; }; + D289C457C6EA440E5D4151BE /* Pods-App-WhatsNew.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew/Pods-App-WhatsNew.openedxmultitenants.xcconfig"; sourceTree = ""; }; E905D28DCAA1940E08C96896 /* Pods-App-WhatsNew-WhatsNewTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.debug.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.debug.xcconfig"; sourceTree = ""; }; F71207762CEF1763A08C7151 /* Pods-App-WhatsNew-WhatsNewTests.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.debugdev.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.debugdev.xcconfig"; sourceTree = ""; }; F8D1A5DF016EC4630637336C /* Pods_App_WhatsNew_WhatsNewTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_WhatsNew_WhatsNewTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F919FF4E89EBAECBB722FF10 /* Pods-App-WhatsNew-WhatsNewTests.openedxmultitenants.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-WhatsNew-WhatsNewTests.openedxmultitenants.xcconfig"; path = "Target Support Files/Pods-App-WhatsNew-WhatsNewTests/Pods-App-WhatsNew-WhatsNewTests.openedxmultitenants.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -247,6 +251,10 @@ 1E3F4487E7D3A48F5FD12DDA /* Pods-App-WhatsNew-WhatsNewTests.releasestage.xcconfig */, 365FD817D70DFBCBDE2EAE5F /* Pods-App-WhatsNew-WhatsNewTests.releaseprod.xcconfig */, 58DF8140E3B3436F58C4C8B9 /* Pods-App-WhatsNew-WhatsNewTests.releasedev.xcconfig */, + D289C457C6EA440E5D4151BE /* Pods-App-WhatsNew.openedxmultitenants.xcconfig */, + F919FF4E89EBAECBB722FF10 /* Pods-App-WhatsNew-WhatsNewTests.openedxmultitenants.xcconfig */, + 36C9BD94FF0649CD8947A60F /* Pods-App-WhatsNew.debugprodtenants.xcconfig */, + 88A20F75D477B3BD8737F0A7 /* Pods-App-WhatsNew-WhatsNewTests.debugprodtenants.xcconfig */, ); name = Pods; path = ../Pods; @@ -542,7 +550,6 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -608,7 +615,6 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -642,7 +648,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -681,7 +686,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -786,7 +790,6 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -827,7 +830,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -912,7 +914,6 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -953,7 +954,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -1038,7 +1038,6 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -1079,7 +1078,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -1164,7 +1162,6 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1198,7 +1195,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -1282,7 +1278,6 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1316,7 +1311,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -1400,7 +1394,6 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1434,7 +1427,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WhatsNew/Info.plist; INFOPLIST_KEY_NSHumanReadableCopyright = ""; @@ -1480,6 +1472,246 @@ }; name = ReleaseStage; }; + 995886A62E6447490065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = DebugProdTenants; + }; + 995886A72E6447490065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 36C9BD94FF0649CD8947A60F /* Pods-App-WhatsNew.debugprodtenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = WhatsNew/Info.plist; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.WhatsNew; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 995886A82E6447490065D132 /* DebugProdTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 88A20F75D477B3BD8737F0A7 /* Pods-App-WhatsNew-WhatsNewTests.debugprodtenants.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.WhatsNewTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = DebugProdTenants; + }; + 9972D1DD2E60375D0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = OpenEdXMultiTenants; + }; + 9972D1DE2E60375D0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D289C457C6EA440E5D4151BE /* Pods-App-WhatsNew.openedxmultitenants.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = WhatsNew/Info.plist; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.WhatsNew; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; + 9972D1DF2E60375D0020CFBD /* OpenEdXMultiTenants */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F919FF4E89EBAECBB722FF10 /* Pods-App-WhatsNew-WhatsNewTests.openedxmultitenants.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = L8PG7LC3Y3; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.openedx.app.WhatsNewTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = OpenEdXMultiTenants; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1487,12 +1719,14 @@ isa = XCConfigurationList; buildConfigurations = ( 028A372D2ADFF3F8008CA604 /* Debug */, + 9972D1DD2E60375D0020CFBD /* OpenEdXMultiTenants */, 02E640642ADFF4EA0079AEDA /* DebugStage */, 02E640612ADFF4E50079AEDA /* DebugProd */, 02E6405E2ADFF4DE0079AEDA /* DebugDev */, 028A372E2ADFF3F8008CA604 /* Release */, 02E6406D2ADFF4FD0079AEDA /* ReleaseStage */, 02E6406A2ADFF4F70079AEDA /* ReleaseProd */, + 995886A62E6447490065D132 /* DebugProdTenants */, 02E640672ADFF4F10079AEDA /* ReleaseDev */, ); defaultConfigurationIsVisible = 0; @@ -1502,12 +1736,14 @@ isa = XCConfigurationList; buildConfigurations = ( 028A37302ADFF3F8008CA604 /* Debug */, + 9972D1DE2E60375D0020CFBD /* OpenEdXMultiTenants */, 02E640652ADFF4EA0079AEDA /* DebugStage */, 02E640622ADFF4E50079AEDA /* DebugProd */, 02E6405F2ADFF4DE0079AEDA /* DebugDev */, 028A37312ADFF3F8008CA604 /* Release */, 02E6406E2ADFF4FD0079AEDA /* ReleaseStage */, 02E6406B2ADFF4F70079AEDA /* ReleaseProd */, + 995886A72E6447490065D132 /* DebugProdTenants */, 02E640682ADFF4F10079AEDA /* ReleaseDev */, ); defaultConfigurationIsVisible = 0; @@ -1517,12 +1753,14 @@ isa = XCConfigurationList; buildConfigurations = ( 028A37332ADFF3F8008CA604 /* Debug */, + 9972D1DF2E60375D0020CFBD /* OpenEdXMultiTenants */, 02E640662ADFF4EA0079AEDA /* DebugStage */, 02E640632ADFF4E50079AEDA /* DebugProd */, 02E640602ADFF4DE0079AEDA /* DebugDev */, 028A37342ADFF3F8008CA604 /* Release */, 02E6406F2ADFF4FD0079AEDA /* ReleaseStage */, 02E6406C2ADFF4F70079AEDA /* ReleaseProd */, + 995886A82E6447490065D132 /* DebugProdTenants */, 02E640692ADFF4F10079AEDA /* ReleaseDev */, ); defaultConfigurationIsVisible = 0; diff --git a/WhatsNew/WhatsNew/Presentation/Elements/PageControl.swift b/WhatsNew/WhatsNew/Presentation/Elements/PageControl.swift index 8bdef4535..afac6dc11 100644 --- a/WhatsNew/WhatsNew/Presentation/Elements/PageControl.swift +++ b/WhatsNew/WhatsNew/Presentation/Elements/PageControl.swift @@ -12,13 +12,16 @@ import Theme struct PageControl: View { let numberOfPages: Int var currentPage: Int - + @EnvironmentObject var themeManager: ThemeManager + private var dots: some View { HStack(spacing: 8) { ForEach(0 ..< numberOfPages) { page in RoundedRectangle(cornerRadius: 4) .frame(width: page == currentPage ? 24 : 8, height: 8) - .foregroundColor(page == currentPage ? Theme.Colors.accentXColor : Theme.Colors.textSecondaryLight) + .foregroundColor(page == currentPage ? + themeManager.theme.colors.accentXColor + : themeManager.theme.colors.textSecondaryLight) } } } diff --git a/WhatsNew/WhatsNew/Presentation/Elements/WhatsNewNavigationButton.swift b/WhatsNew/WhatsNew/Presentation/Elements/WhatsNewNavigationButton.swift index d439058ba..7c9e5f8fb 100644 --- a/WhatsNew/WhatsNew/Presentation/Elements/WhatsNewNavigationButton.swift +++ b/WhatsNew/WhatsNew/Presentation/Elements/WhatsNewNavigationButton.swift @@ -12,6 +12,7 @@ import Theme struct WhatsNewNavigationButton: View { let type: ButtonType let action: () -> Void + @EnvironmentObject var themeManager: ThemeManager enum ButtonType { case previous, next, done @@ -23,25 +24,27 @@ struct WhatsNewNavigationButton: View { if type == .previous { CoreAssets.arrowLeft.swiftUIImage .renderingMode(.template) - .foregroundColor(Theme.Colors.secondaryButtonTextColor) + .foregroundColor(themeManager.theme.colors.secondaryButtonTextColor) } Text(type == .previous ? WhatsNewLocalization.buttonPrevious : (type == .next ? WhatsNewLocalization.buttonNext : WhatsNewLocalization.buttonDone )) - .foregroundColor(type == .previous ? Theme.Colors.secondaryButtonTextColor : Theme.Colors.white) + .foregroundColor(type == .previous ? + themeManager.theme.colors.secondaryButtonTextColor + : themeManager.theme.colors.white) .font(Theme.Fonts.labelLarge) if type == .next { CoreAssets.arrowLeft.swiftUIImage .renderingMode(.template) .rotationEffect(Angle(degrees: 180)) - .foregroundColor(Theme.Colors.white) + .foregroundColor(themeManager.theme.colors.white) } if type == .done { CoreAssets.checkmark.swiftUIImage .renderingMode(.template) - .foregroundColor(Theme.Colors.white) + .foregroundColor(themeManager.theme.colors.white) } }.padding(.horizontal, 20) .padding(.vertical, 9) @@ -50,8 +53,8 @@ struct WhatsNewNavigationButton: View { Theme.Shapes.buttonShape .fill( type == .previous - ? Theme.Colors.secondaryButtonBGColor - : Theme.Colors.accentButtonColor + ? themeManager.theme.colors.secondaryButtonBGColor + : themeManager.theme.colors.accentButtonColor ) ) .accessibilityElement(children: .ignore) @@ -60,8 +63,8 @@ struct WhatsNewNavigationButton: View { .overlay( Theme.Shapes.buttonShape .stroke(type == .previous - ? Theme.Colors.secondaryButtonBorderColor - : Theme.Colors.background, lineWidth: 1) + ? themeManager.theme.colors.secondaryButtonBorderColor + : themeManager.theme.colors.background, lineWidth: 1) ) .onTapGesture { action() } } diff --git a/WhatsNew/WhatsNew/Presentation/WhatsNewView.swift b/WhatsNew/WhatsNew/Presentation/WhatsNewView.swift index feb9e9877..2d341d9a4 100644 --- a/WhatsNew/WhatsNew/Presentation/WhatsNewView.swift +++ b/WhatsNew/WhatsNew/Presentation/WhatsNewView.swift @@ -20,6 +20,7 @@ public struct WhatsNewView: View { private var isHorizontal @State var index = 0 + @EnvironmentObject var themeManager: ThemeManager public init(router: WhatsNewRouter, viewModel: WhatsNewViewModel) { self.router = router @@ -29,7 +30,7 @@ public struct WhatsNewView: View { public var body: some View { GeometryReader { reader in ZStack(alignment: isHorizontal ? .center : .bottom) { - Theme.Colors.background + themeManager.theme.colors.background .ignoresSafeArea() adaptiveStack(isHorizontal: isHorizontal) { TabView(selection: $index) { @@ -53,7 +54,7 @@ public struct WhatsNewView: View { Spacer() Rectangle() - .foregroundColor(Theme.Colors.background) + .foregroundColor(themeManager.theme.colors.background) .frame(width: reader.size.width / 1.9) .ignoresSafeArea() .mask( @@ -160,7 +161,7 @@ public struct WhatsNewView: View { }, label: { Image(systemName: "xmark") - .foregroundColor(Theme.Colors.accentXColor) + .foregroundColor(themeManager.theme.colors.accentXColor) }) .accessibilityIdentifier("close_button") }) diff --git a/default_config/config_settings.yaml b/default_config/config_settings.yaml index 249e93fc3..9184f708e 100644 --- a/default_config/config_settings.yaml +++ b/default_config/config_settings.yaml @@ -3,3 +3,4 @@ config_mapping: prod: 'prod' stage: 'stage' dev: 'dev' + tenants: 'tenants' diff --git a/default_config/tenants/config.yaml b/default_config/tenants/config.yaml new file mode 100644 index 000000000..7c60920d2 --- /dev/null +++ b/default_config/tenants/config.yaml @@ -0,0 +1,52 @@ +TENANTS: + - + name: "TenantA" + TENANT_NAME: + ar: "المعهد ب" + en: "TenantA" + color: "green" + ENVIRONMENT_DISPLAY_NAME: "TenantA" + OAUTH_CLIENT_ID: '' + API_HOST_URL: 'http://localhost:8000' + API_HOST_URL_HIDDEN_LOGIN: 'http://localhost:8000' + SSO_URL: 'http://localhost:8000' + SSO_URL_SUCCESSFUL_LOGIN: 'http://localhost:8000' + SSO_BUTTON_TITLE: + ar: "تسجيل الدخول" + en: "Sign in" + IS_SWITCH_TENANT_LOGIN_ENABLED: true + + UI_COMPONENTS: + COURSE_BANNER_ENABLED: true + COURSE_TOP_TAB_BAR_ENABLED: false + COURSE_UNIT_PROGRESS_ENABLED: false + COURSE_NESTED_LIST_ENABLED: false + LOGIN_REGISTRATION_ENABLED: false + SAML_SSO_LOGIN_ENABLED: true + SAML_SSO_DEFAULT_LOGIN_BUTTON: true + - + name: "TenantB" + TENANT_NAME: + ar: "المعهد أ" + en: "TenantB" + color: "blue" + OAUTH_CLIENT_ID: '' + API_HOST_URL: 'http://localhost:8000' + API_HOST_URL_HIDDEN_LOGIN: 'http://localhost:8000' + ENVIRONMENT_DISPLAY_NAME: 'TenantB' + SSO_URL: 'http://localhost:8000' + SSO_URL_SUCCESSFUL_LOGIN: 'http://localhost:8000' + SSO_BUTTON_TITLE: + ar: "تسجيل الدخول" + en: "Sign in" + IS_SWITCH_TENANT_LOGIN_ENABLED: false + + UI_COMPONENTS: + COURSE_BANNER_ENABLED: true + COURSE_TOP_TAB_BAR_ENABLED: false + COURSE_UNIT_PROGRESS_ENABLED: false + COURSE_NESTED_LIST_ENABLED: false + LOGIN_REGISTRATION_ENABLED: true + SAML_SSO_LOGIN_ENABLED: false + SAML_SSO_DEFAULT_LOGIN_BUTTON: true + diff --git a/default_config/tenants/file_mappings.yaml b/default_config/tenants/file_mappings.yaml new file mode 100644 index 000000000..86d84fa91 --- /dev/null +++ b/default_config/tenants/file_mappings.yaml @@ -0,0 +1,3 @@ +ios: + files: + - config.yaml