diff --git a/Core/Core/Configuration/Config/ThemeConfig.swift b/Core/Core/Configuration/Config/ThemeConfig.swift index 239cd69fe..64508cd3a 100644 --- a/Core/Core/Configuration/Config/ThemeConfig.swift +++ b/Core/Core/Configuration/Config/ThemeConfig.swift @@ -6,16 +6,20 @@ // import Foundation +import OEXFoundation -private enum ThemeKeys: String { +private enum ThemeKeys: String, RawStringExtractable { case isRoundedCorners = "ROUNDED_CORNERS_STYLE" + case buttonCornersRadius = "BUTTON_CORNERS_RADIUS" } public final class ThemeConfig: NSObject { public var isRoundedCorners: Bool - + public var buttonCornersRadius: Double + init(dictionary: [String: AnyObject]) { - isRoundedCorners = dictionary[ThemeKeys.isRoundedCorners.rawValue] as? Bool != false + isRoundedCorners = dictionary[ThemeKeys.isRoundedCorners] as? Bool != false + buttonCornersRadius = dictionary[ThemeKeys.buttonCornersRadius] as? Double ?? 8.0 super.init() } } diff --git a/Core/Core/SwiftGen/Strings.swift b/Core/Core/SwiftGen/Strings.swift index efae8f823..a4e441d6c 100644 --- a/Core/Core/SwiftGen/Strings.swift +++ b/Core/Core/SwiftGen/Strings.swift @@ -29,16 +29,16 @@ public enum CoreLocalization { /// Yesterday public static let yesterday = CoreLocalization.tr("Localizable", "YESTERDAY", fallback: "Yesterday") public enum Alert { - /// ACCEPT - public static let accept = CoreLocalization.tr("Localizable", "ALERT.ACCEPT", fallback: "ACCEPT") + /// Accept + public static let accept = CoreLocalization.tr("Localizable", "ALERT.ACCEPT", fallback: "Accept") /// Add public static let add = CoreLocalization.tr("Localizable", "ALERT.ADD", fallback: "Add") /// Remove course calendar public static let calendarShiftPromptRemoveCourseCalendar = CoreLocalization.tr("Localizable", "ALERT.CALENDAR_SHIFT_PROMPT_REMOVE_COURSE_CALENDAR", fallback: "Remove course calendar") - /// CANCEL - public static let cancel = CoreLocalization.tr("Localizable", "ALERT.CANCEL", fallback: "CANCEL") - /// DELETE - public static let delete = CoreLocalization.tr("Localizable", "ALERT.DELETE", fallback: "DELETE") + /// Cancel + public static let cancel = CoreLocalization.tr("Localizable", "ALERT.CANCEL", fallback: "Cancel") + /// Delete + public static let delete = CoreLocalization.tr("Localizable", "ALERT.DELETE", fallback: "Delete") /// Keep editing public static let keepEditing = CoreLocalization.tr("Localizable", "ALERT.KEEP_EDITING", fallback: "Keep editing") /// Leave diff --git a/Core/Core/View/Base/AlertView.swift b/Core/Core/View/Base/AlertView.swift index d3b5a7ae5..bcda89a1b 100644 --- a/Core/Core/View/Base/AlertView.swift +++ b/Core/Core/View/Base/AlertView.swift @@ -290,7 +290,7 @@ public struct AlertView: View { .fill(Theme.Colors.warning) ) .overlay( - RoundedRectangle(cornerRadius: 8) + Theme.Shapes.buttonShape .stroke(style: .init( lineWidth: 1, lineCap: .round, @@ -319,7 +319,7 @@ public struct AlertView: View { .fill(Theme.Colors.accentColor) ) .overlay( - RoundedRectangle(cornerRadius: 8) + Theme.Shapes.buttonShape .stroke(style: .init( lineWidth: 1, lineCap: .round, @@ -344,17 +344,17 @@ public struct AlertView: View { }) .background( Theme.Shapes.buttonShape - .fill(.clear) + .fill(Theme.Colors.background) ) .overlay( - RoundedRectangle(cornerRadius: 8) + Theme.Shapes.buttonShape .stroke(style: .init( lineWidth: 1, lineCap: .round, lineJoin: .round, miterLimit: 1 )) - .foregroundColor(Theme.Colors.secondaryButtonBorderColor) + .foregroundColor(Theme.Colors.accentColor) ) .frame(maxWidth: 215) } @@ -411,7 +411,7 @@ public struct AlertView: View { } label: { ZStack { Text(primaryButtonTitle) - .foregroundColor(Theme.Colors.styledButtonText) + .foregroundColor(Theme.Colors.primaryButtonTextColor) .font(Theme.Fonts.labelLarge) .frame(maxWidth: .infinity) .padding(.horizontal, 16) @@ -420,10 +420,10 @@ public struct AlertView: View { } .background( Theme.Shapes.buttonShape - .fill(Theme.Colors.accentButtonColor) + .fill(Theme.Colors.accentColor) ) .overlay( - RoundedRectangle(cornerRadius: 8) + Theme.Shapes.buttonShape .stroke(style: .init( lineWidth: 1, lineCap: .round, @@ -439,7 +439,7 @@ public struct AlertView: View { }, label: { ZStack { Text(secondaryButtonTitle) - .foregroundColor(Theme.Colors.secondaryButtonTextColor) + .foregroundColor(Theme.Colors.accentColor) .font(Theme.Fonts.labelLarge) .frame(maxWidth: .infinity) .padding(.horizontal, 16) @@ -448,17 +448,17 @@ public struct AlertView: View { }) .background( Theme.Shapes.buttonShape - .fill(Theme.Colors.secondaryButtonBGColor) + .fill(Theme.Colors.background) ) .overlay( - RoundedRectangle(cornerRadius: 8) + Theme.Shapes.buttonShape .stroke(style: .init( lineWidth: 1, lineCap: .round, lineJoin: .round, miterLimit: 1 )) - .foregroundColor(Theme.Colors.secondaryButtonBorderColor) + .foregroundColor(Theme.Colors.accentColor) ) .frame(maxWidth: 215) } diff --git a/Core/Core/View/Base/DownloadView.swift b/Core/Core/View/Base/DownloadView.swift index 5b6165c08..3ad78062a 100644 --- a/Core/Core/View/Base/DownloadView.swift +++ b/Core/Core/View/Base/DownloadView.swift @@ -23,6 +23,7 @@ public struct DownloadAvailableView: View { CoreAssets.startDownloading.swiftUIImage.renderingMode(.template) .resizable() .scaledToFit() + .foregroundColor(Theme.Colors.textPrimary) .frame(width: 24, height: 24) } .frame(width: 30, height: 30) diff --git a/Core/Core/View/Base/LogistrationBottomView.swift b/Core/Core/View/Base/LogistrationBottomView.swift index d5da22ccc..c902a1b4c 100644 --- a/Core/Core/View/Base/LogistrationBottomView.swift +++ b/Core/Core/View/Base/LogistrationBottomView.swift @@ -15,6 +15,10 @@ public enum LogistrationSourceScreen: Equatable, Sendable { case discovery case courseDetail(String, String) case programDetails(String) + + public var value: String? { + return String(describing: self).components(separatedBy: "(").first + } } public enum LogistrationAction: Sendable { diff --git a/Core/Core/View/Base/UnitButtonView.swift b/Core/Core/View/Base/UnitButtonView.swift index 37c94eeb4..b89106145 100644 --- a/Core/Core/View/Base/UnitButtonView.swift +++ b/Core/Core/View/Base/UnitButtonView.swift @@ -145,13 +145,16 @@ public struct UnitButtonView: View { case .continueLesson, .nextSection: HStack { Text(type.stringValue()) - .foregroundColor(Theme.Colors.styledButtonText) + .foregroundColor( + type == .continueLesson ? Theme.Colors.resumeButtonText : + Theme.Colors.styledButtonText + ) .padding(.leading, 20) .font(Theme.Fonts.labelLarge) CoreAssets.arrowLeft.swiftUIImage.renderingMode(.template) .foregroundColor( type == .continueLesson - ? Theme.Colors.accentColor + ? Theme.Colors.resumeButtonText : Theme.Colors.styledButtonText ) .rotationEffect(Angle.degrees(180)) @@ -184,7 +187,10 @@ public struct UnitButtonView: View { case .continueLesson, .nextSection, .reload, .finish, .custom: Theme.Shapes.buttonShape - .fill(bgColor ?? Theme.Colors.accentButtonColor) + .fill( + type == .continueLesson ? Theme.Colors.resumeButtonBG : + bgColor ?? Theme.Colors.accentButtonColor + ) .shadow(color: (type == .first || type == .next diff --git a/Core/Core/en.lproj/Localizable.strings b/Core/Core/en.lproj/Localizable.strings index 612975633..3bf847155 100644 --- a/Core/Core/en.lproj/Localizable.strings +++ b/Core/Core/en.lproj/Localizable.strings @@ -61,12 +61,12 @@ "DATE.DUE_IN" = "Due in "; "DATE.DUE_IN_DAYS" = "Due in %@ Days"; -"ALERT.ACCEPT" = "ACCEPT"; -"ALERT.CANCEL" = "CANCEL"; +"ALERT.ACCEPT" = "Accept"; +"ALERT.CANCEL" = "Cancel"; "ALERT.LOGOUT" = "Log out"; "ALERT.LEAVE" = "Leave"; "ALERT.KEEP_EDITING" = "Keep editing"; -"ALERT.DELETE" = "DELETE"; +"ALERT.DELETE" = "Delete"; "ALERT.ADD" = "Add"; "ALERT.REMOVE" = "Remove"; "ALERT.CALENDAR_SHIFT_PROMPT_REMOVE_COURSE_CALENDAR"="Remove course calendar"; diff --git a/Course/Course/Presentation/Subviews/CourseProgressView.swift b/Course/Course/Presentation/Subviews/CourseProgressView.swift index 70ee1c2d8..1aaeaa7c1 100644 --- a/Course/Course/Presentation/Subviews/CourseProgressView.swift +++ b/Course/Course/Presentation/Subviews/CourseProgressView.swift @@ -21,7 +21,7 @@ public struct CourseProgressView: View { ZStack(alignment: .leading) { GeometryReader { geometry in RoundedRectangle(cornerRadius: 10) - .fill(Theme.Colors.textSecondary.opacity(0.5)) + .fill(Theme.Colors.courseProgressBG) .frame(width: geometry.size.width, height: 10) if let total = progress.totalAssignmentsCount, diff --git a/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift b/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift index 753696baa..f7132b16f 100644 --- a/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift +++ b/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift @@ -41,7 +41,8 @@ struct CustomDisclosureGroup: View { .rotationEffect(.degrees(expandedSections[chapter.id] ?? false ? -90 : 90)) .foregroundColor(Theme.Colors.textPrimary) if chapter.childs.allSatisfy({ $0.completion == 1 }) { - CoreAssets.finishedSequence.swiftUIImage + CoreAssets.finishedSequence.swiftUIImage.renderingMode(.template) + .foregroundColor(Theme.Colors.success) } Text(chapter.displayName) .font(Theme.Fonts.titleMedium) @@ -112,7 +113,9 @@ struct CustomDisclosureGroup: View { HStack { if sequential.completion == 1 { CoreAssets.finishedSequence.swiftUIImage + .renderingMode(.template) .resizable() + .foregroundColor(Theme.Colors.success) .frame(width: 20, height: 20) } else { sequential.type.image diff --git a/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift b/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift index be275e4ab..100a75e48 100644 --- a/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift +++ b/Dashboard/Dashboard/Presentation/Elements/PrimaryCardView.swift @@ -127,7 +127,7 @@ public struct PrimaryCardView: View { } private var assignments: some View { - VStack(alignment: .leading, spacing: 8) { + VStack(alignment: .leading, spacing: 0) { // pastAssignments if pastAssignments.count == 1, let pastAssignment = pastAssignments.first { courseButton( @@ -188,6 +188,7 @@ public struct PrimaryCardView: View { description: DashboardLocalization.Learn.PrimaryCard.resume, icon: CoreAssets.resumeCourse.swiftUIImage, selected: true, + bgColor: Theme.Colors.accentButtonColor, action: { resumeAction() } ) } else { @@ -196,6 +197,7 @@ public struct PrimaryCardView: View { description: nil, icon: CoreAssets.resumeCourse.swiftUIImage, selected: true, + bgColor: Theme.Colors.accentButtonColor, action: { resumeAction() } ) } @@ -207,6 +209,7 @@ public struct PrimaryCardView: View { description: String?, icon: Image, selected: Bool, + bgColor: Color = Theme.Colors.primaryCardCautionBG, action: @escaping () -> Void ) -> some View { Button(action: { @@ -242,6 +245,7 @@ public struct PrimaryCardView: View { .padding(.top, 2) } } + .padding(.bottom, 8) Spacer() CoreAssets.chevronRight.swiftUIImage .foregroundStyle(foregroundColor(selected)) @@ -249,7 +253,7 @@ public struct PrimaryCardView: View { } .padding(.top, 8) .padding(.bottom, selected ? 10 : 0) - }.background(selected ? Theme.Colors.accentButtonColor : .clear) + }.background(bgColor) }) } diff --git a/Dashboard/Dashboard/Presentation/Elements/ProgressLineView.swift b/Dashboard/Dashboard/Presentation/Elements/ProgressLineView.swift index 80ef325a1..8d426b77f 100644 --- a/Dashboard/Dashboard/Presentation/Elements/ProgressLineView.swift +++ b/Dashboard/Dashboard/Presentation/Elements/ProgressLineView.swift @@ -28,7 +28,7 @@ struct ProgressLineView: View { ZStack(alignment: .leading) { GeometryReader { geometry in Rectangle() - .foregroundStyle(Theme.Colors.cardViewStroke) + .foregroundStyle(Theme.Colors.primaryCardProgressBG) Rectangle() .foregroundStyle(Theme.Colors.accentButtonColor) .frame(width: geometry.size.width * progressValue) diff --git a/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebviewViewModel.swift b/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebviewViewModel.swift index aed09effd..1c70dcdfe 100644 --- a/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebviewViewModel.swift +++ b/Discovery/Discovery/Presentation/WebDiscovery/DiscoveryWebviewViewModel.swift @@ -138,14 +138,25 @@ extension DiscoveryWebviewViewModel: WebViewNavigationDelegate { } if let url = request.url, outsideLink || capturedLink || externalLink, UIApplication.shared.canOpenURL(url) { + analytics.externalLinkOpen(url: url.absoluteString, screen: sourceScreen.value ?? "") router.presentAlert( alertTitle: DiscoveryLocalization.Alert.leavingAppTitle, alertMessage: DiscoveryLocalization.Alert.leavingAppMessage, positiveAction: CoreLocalization.Webview.Alert.continue, onCloseTapped: { [weak self] in self?.router.dismiss(animated: true) - }, okTapped: { + self?.analytics.externalLinkOpenAction( + url: url.absoluteString, + screen: self?.sourceScreen.value ?? "", + action: "cancel" + ) + }, okTapped: { [weak self] in UIApplication.shared.open(url, options: [:]) + self?.analytics.externalLinkOpenAction( + url: url.absoluteString, + screen: self?.sourceScreen.value ?? "", + action: "continue" + ) }, type: .default(positiveAction: CoreLocalization.Webview.Alert.continue, image: nil) ) return true diff --git a/Discussion/Discussion/Presentation/Comments/Base/CommentCell.swift b/Discussion/Discussion/Presentation/Comments/Base/CommentCell.swift index d4970a894..b887f8534 100644 --- a/Discussion/Discussion/Presentation/Comments/Base/CommentCell.swift +++ b/Discussion/Discussion/Presentation/Comments/Base/CommentCell.swift @@ -57,6 +57,10 @@ public struct CommentCell: View { .resizable() .frame(width: 32, height: 32) .cornerRadius(16) + .overlay { + Circle() + .stroke(Theme.Colors.avatarStroke, lineWidth: 1) + } }) VStack(alignment: .leading) { @@ -70,16 +74,18 @@ public struct CommentCell: View { Button(action: { onReportTap() }, label: { - comment.abuseFlagged + let icon = comment.abuseFlagged ? CoreAssets.reported.swiftUIImage : CoreAssets.report.swiftUIImage + icon.renderingMode(.template) + Text(comment.abuseFlagged ? DiscussionLocalization.Comment.unreport : DiscussionLocalization.Comment.report) .font(Theme.Fonts.labelMedium) }).foregroundColor(comment.abuseFlagged - ? Theme.Colors.alert - : Theme.Colors.textSecondary) + ? Theme.Colors.irreversibleAlert + : Theme.Colors.textSecondaryLight) } Text(comment.postBodyHtml.hideHtmlTagsAndUrls()) .font(Theme.Fonts.bodyMedium) @@ -125,15 +131,16 @@ public struct CommentCell: View { : CoreAssets.vote.swiftUIImage.renderingMode(.template) Text("\(comment.votesCount)") Text(DiscussionLocalization.votesCount(comment.votesCount)) - .font(Theme.Fonts.labelLarge) }).foregroundColor(comment.voted - ? Theme.Colors.accentXColor - : Theme.Colors.textSecondary) + ? Theme.Colors.accentColor + : Theme.Colors.textSecondaryLight) + .font(Theme.Fonts.labelLarge) Spacer() if addCommentAvailable { HStack { Image(systemName: "message.fill") + .renderingMode(.template) Text("\(comment.responsesCount)") Text(DiscussionLocalization.commentsCount(comment.responsesCount)) } diff --git a/Discussion/Discussion/Presentation/Comments/Base/ParentCommentView.swift b/Discussion/Discussion/Presentation/Comments/Base/ParentCommentView.swift index 27c4f5229..1a14eadf2 100644 --- a/Discussion/Discussion/Presentation/Comments/Base/ParentCommentView.swift +++ b/Discussion/Discussion/Presentation/Comments/Base/ParentCommentView.swift @@ -49,9 +49,13 @@ public struct ParentCommentView: View { KFImage(URL(string: comments.authorAvatar)) .onFailureImage(KFCrossPlatformImage(systemName: "person")) .resizable() - .background(Color.gray) .frame(width: 48, height: 48) - .cornerRadius(isThread ? 8 : 24) + .cornerRadius(24) + .overlay { + Circle() + .stroke(Theme.Colors.avatarStroke, lineWidth: 1) + } + }) VStack(alignment: .leading) { Text(comments.authorName) @@ -68,6 +72,7 @@ public struct ParentCommentView: View { onFollowTap() }, label: { Image(systemName: comments.followed ? "star.fill" : "star") + .renderingMode(.template) Text(comments.followed ? DiscussionLocalization.Comment.unfollow : DiscussionLocalization.Comment.follow) @@ -111,29 +116,31 @@ public struct ParentCommentView: View { }, label: { comments.voted ? (CoreAssets.voted.swiftUIImage.renderingMode(.template)) - : (CoreAssets.vote.swiftUIImage.renderingMode(.template)) + : CoreAssets.vote.swiftUIImage.renderingMode(.template) + Text("\(comments.votesCount)") - .foregroundColor(Theme.Colors.textPrimary) Text(DiscussionLocalization.votesCount(comments.votesCount)) .font(Theme.Fonts.labelLarge) - .foregroundColor(Theme.Colors.textPrimary) + }).foregroundColor(comments.voted - ? Theme.Colors.accentXColor + ? Theme.Colors.accentColor : Theme.Colors.textSecondaryLight) Spacer() Button(action: { onReportTap() }, label: { - comments.abuseFlagged + let icon = comments.abuseFlagged ? CoreAssets.reported.swiftUIImage : CoreAssets.report.swiftUIImage + icon.renderingMode(.template) + Text(comments.abuseFlagged ? DiscussionLocalization.Comment.unreport : DiscussionLocalization.Comment.report) }) } .accentColor(comments.abuseFlagged - ? Theme.Colors.alert + ? Theme.Colors.irreversibleAlert : Theme.Colors.textSecondaryLight) .font(Theme.Fonts.labelLarge) } diff --git a/Documentation/Theming_implementation.md b/Documentation/Theming_implementation.md index e9d5b37dd..735ebef8e 100644 --- a/Documentation/Theming_implementation.md +++ b/Documentation/Theming_implementation.md @@ -72,6 +72,9 @@ assets: current_path: '' # optional: path to color inside colors_path light: '#FFFFFF' dark: '#ED5C13' + alpha_light: '0.4' # optional: alpha value for light color, from 0.0 to 1.0. Can be a number, not a string + alpha_dark: '0.2' # optional: alpha value for dark color, from 0.0 to 1.0. Can be a number, not a string + alpha: '0.5' # optional: alpha value for both light and dark colors, from 0.0 to 1.0. Can be a number, not a string icon: AppIcon: current_path: '' # optional: path to icon inside icon_path diff --git a/OpenEdX/AppDelegate.swift b/OpenEdX/AppDelegate.swift index e97f573d9..16cb8e7d1 100644 --- a/OpenEdX/AppDelegate.swift +++ b/OpenEdX/AppDelegate.swift @@ -45,6 +45,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { if let config = Container.shared.resolve(ConfigProtocol.self) { Theme.Shapes.isRoundedCorners = config.theme.isRoundedCorners + Theme.Shapes.buttonCornersRadius = config.theme.buttonCornersRadius if config.facebook.enabled { ApplicationDelegate.shared.application( diff --git a/Theme/Theme/Assets.xcassets/Colors/CourseProgressBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/CourseProgressBG.colorset/Contents.json new file mode 100644 index 000000000..0c6177c8c --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/CourseProgressBG.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.500", + "blue" : "0.733", + "green" : "0.647", + "red" : "0.592" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.500", + "blue" : "0.624", + "green" : "0.533", + "red" : "0.475" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/Contents.json b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/PrimaryCardCautionBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/PrimaryCardCautionBG.colorset/Contents.json new file mode 100644 index 000000000..bfc59a1b2 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/PrimaryCardCautionBG.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/Colors/PrimaryCard/PrimaryCardCourseUpgradeBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/PrimaryCardCourseUpgradeBG.colorset/Contents.json new file mode 100644 index 000000000..bfc59a1b2 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/PrimaryCardCourseUpgradeBG.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/Colors/PrimaryCard/PrimaryCardProgressBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/PrimaryCardProgressBG.colorset/Contents.json new file mode 100644 index 000000000..d31f2bcff --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/PrimaryCard/PrimaryCardProgressBG.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/Colors/ResumeButton/Contents.json b/Theme/Theme/Assets.xcassets/Colors/ResumeButton/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/ResumeButton/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Theme/Theme/Assets.xcassets/Colors/ResumeButton/ResumeButtonBG.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/ResumeButton/ResumeButtonBG.colorset/Contents.json new file mode 100644 index 000000000..bf1a96417 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/ResumeButton/ResumeButtonBG.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/ResumeButton/ResumeButtonText.colorset/Contents.json b/Theme/Theme/Assets.xcassets/Colors/ResumeButton/ResumeButtonText.colorset/Contents.json new file mode 100644 index 000000000..22c4bb0a8 --- /dev/null +++ b/Theme/Theme/Assets.xcassets/Colors/ResumeButton/ResumeButtonText.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 bee684564..1b0d20ef6 100644 --- a/Theme/Theme/SwiftGen/ThemeAssets.swift +++ b/Theme/Theme/SwiftGen/ThemeAssets.swift @@ -46,16 +46,22 @@ public enum ThemeAssets { public static let pastDueTimelineColor = ColorAsset(name: "pastDueTimelineColor") public static let primaryHeaderColor = ColorAsset(name: "primaryHeaderColor") public static let secondaryHeaderColor = ColorAsset(name: "secondaryHeaderColor") + public static let courseProgressBG = ColorAsset(name: "CourseProgressBG") public static let deleteAccountBG = ColorAsset(name: "DeleteAccountBG") public static let infoColor = ColorAsset(name: "InfoColor") public static let irreversibleAlert = ColorAsset(name: "IrreversibleAlert") public static let loginBackground = ColorAsset(name: "LoginBackground") public static let loginNavigationText = ColorAsset(name: "LoginNavigationText") public static let primaryButtonTextColor = ColorAsset(name: "PrimaryButtonTextColor") + public static let primaryCardCautionBG = ColorAsset(name: "PrimaryCardCautionBG") + public static let primaryCardCourseUpgradeBG = ColorAsset(name: "PrimaryCardCourseUpgradeBG") + public static let primaryCardProgressBG = ColorAsset(name: "PrimaryCardProgressBG") public static let onProgress = ColorAsset(name: "OnProgress") public static let progressDone = ColorAsset(name: "ProgressDone") public static let progressSkip = ColorAsset(name: "ProgressSkip") public static let selectedAndDone = ColorAsset(name: "SelectedAndDone") + public static let resumeButtonBG = ColorAsset(name: "ResumeButtonBG") + public static let resumeButtonText = ColorAsset(name: "ResumeButtonText") public static let secondaryButtonBGColor = ColorAsset(name: "SecondaryButtonBGColor") public static let secondaryButtonBorderColor = ColorAsset(name: "SecondaryButtonBorderColor") public static let secondaryButtonTextColor = ColorAsset(name: "SecondaryButtonTextColor") diff --git a/Theme/Theme/Theme.swift b/Theme/Theme/Theme.swift index 884e918b8..359e2c8ef 100644 --- a/Theme/Theme/Theme.swift +++ b/Theme/Theme/Theme.swift @@ -76,6 +76,12 @@ public struct Theme: Sendable { nonisolated(unsafe) public private(set) static var shade = ThemeAssets.shade.swiftUIColor nonisolated(unsafe) public private(set) static var courseCardBackground = ThemeAssets.courseCardBackground.swiftUIColor nonisolated(unsafe) public private(set) static var deleteAccountBG = ThemeAssets.deleteAccountBG.swiftUIColor + nonisolated(unsafe) public private(set) static var primaryCardCautionBG = ThemeAssets.primaryCardCautionBG.swiftUIColor + nonisolated(unsafe) public private(set) static var primaryCardUpgradeBG = ThemeAssets.primaryCardCourseUpgradeBG.swiftUIColor + nonisolated(unsafe) public private(set) static var primaryCardProgressBG = ThemeAssets.primaryCardProgressBG.swiftUIColor + nonisolated(unsafe) public private(set) static var courseProgressBG = ThemeAssets.courseProgressBG.swiftUIColor + nonisolated(unsafe) public private(set) static var resumeButtonBG = ThemeAssets.resumeButtonBG.swiftUIColor + nonisolated(unsafe) public private(set) static var resumeButtonText = ThemeAssets.resumeButtonText.swiftUIColor public static func update( accentColor: Color = ThemeAssets.accentColor.swiftUIColor, @@ -250,6 +256,7 @@ public struct Theme: Sendable { public struct Shapes: Sendable { nonisolated(unsafe) public static var isRoundedCorners: Bool = true + nonisolated(unsafe) public static var buttonCornersRadius: Double = 8.0 public static let screenBackgroundRadius = 24.0 public static let cardImageRadius = 10.0 public static let textInputShape = { @@ -257,7 +264,7 @@ public struct Theme: Sendable { return RoundedRectangle(cornerRadius: radius) }() public static let buttonShape = { - let radius: CGFloat = isRoundedCorners ? 8 : 0 + let radius: CGFloat = isRoundedCorners ? buttonCornersRadius : 0 return RoundedCorners(tl: radius, tr: radius, bl: radius, br: radius) }() public static let unitButtonShape = RoundedCorners(tl: 21, tr: 21, bl: 21, br: 21) diff --git a/config_script/whitelabel.py b/config_script/whitelabel.py index d09eb53dd..82709ec22 100644 --- a/config_script/whitelabel.py +++ b/config_script/whitelabel.py @@ -33,6 +33,9 @@ class WhitelabelApp: current_path: '' # optional: path to color inside colors_path light: '#FFFFFF' dark: '#ED5C13' + alpha_light: '0.4' # optional: alpha value for light color, from 0.0 to 1.0. Can be a number, not a string + alpha_dark: '0.2' # optional: alpha value for dark color, from 0.0 to 1.0. Can be a number, not a string + alpha: '0.5' # optional: alpha value for both light and dark colors, from 0.0 to 1.0. Can be a number, not a string icon: AppIcon: current_path: '' # optional: path to icon inside icon_path @@ -187,6 +190,9 @@ def replace_colors(self, asset_data): path_to_colorset = os.path.join(colors_path, current_path, name+'.colorset') light_color = color["light"] dark_color = color["dark"] + alpha = str(color["alpha"]) if "alpha" in color else None + alpha_light = str(color["alpha_light"]) if "alpha_light" in color else alpha + alpha_dark = str(color["alpha_dark"]) if "alpha_dark" in color else alpha # Change Contents.json content_json_path = os.path.join(path_to_colorset, 'Contents.json') if os.path.exists(content_json_path): @@ -195,11 +201,11 @@ def replace_colors(self, asset_data): for key in range(len(json_object["colors"])): if "appearances" in json_object["colors"][key]: # dark - changed_components = self.change_color_components(json_object["colors"][key]["color"]["components"], dark_color, name) + changed_components = self.change_color_components(json_object["colors"][key]["color"]["components"], dark_color, name, alpha_dark) json_object["colors"][key]["color"]["components"] = changed_components else: # light - changed_components = self.change_color_components(json_object["colors"][key]["color"]["components"], light_color, name) + changed_components = self.change_color_components(json_object["colors"][key]["color"]["components"], light_color, name, alpha_light) json_object["colors"][key]["color"]["components"] = changed_components new_json = json.dumps(json_object) with open(content_json_path, 'w') as openfile: @@ -208,7 +214,7 @@ def replace_colors(self, asset_data): else: logging.error(asset_name+"->colors->"+name+": " + content_json_path + " doesn't exist") - def change_color_components(self, components, color, name): + def change_color_components(self, components, color, name, alpha): color = color.replace("#", "") if len(color) != 6: print('Config for color "'+name+'" is incorrect') @@ -216,6 +222,8 @@ def change_color_components(self, components, color, name): components["red"] = "0x"+color[0]+color[1] components["green"] = "0x"+color[2]+color[3] components["blue"] = "0x"+color[4]+color[5] + if alpha is not None: + components["alpha"] = alpha return components def replace_app_icon(self, asset_data):