From 255e2b77480bca225d868836f00c2bd216400d6d Mon Sep 17 00:00:00 2001 From: Volodymyr Chekyrta Date: Fri, 8 Nov 2024 12:51:09 +0200 Subject: [PATCH 1/3] build: update action versions (#541) --- .github/workflows/unit_tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 99a84f445..8d72de40f 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -21,7 +21,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: vendor/bundle key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} @@ -36,7 +36,7 @@ jobs: run: bundle exec fastlane unit_tests - name: Archive artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: test-output @@ -45,6 +45,6 @@ jobs: if-no-files-found: ignore - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: flags: unittests From f2092620df709ebc354c02f9a5892bb2780c7db1 Mon Sep 17 00:00:00 2001 From: Anton Yarmolenko Date: Mon, 18 Nov 2024 18:19:16 +0100 Subject: [PATCH 2/3] fix: Part 5 sync to upstream (#542) * Merge pull request #42 from edx/password-input-view-eye feat: eye icon for password field * chore: added SecureInputView to project * Merge pull request #44 from edx/clear-cookies-by-logout fix: clear cookies by logout * Merge pull request #47 from edx/reduce-grid-spacing style: reduce grid spacing * chore: Fix outdated course dates alert title truncation issue (#53) * Merge pull request #57 from edx/remaining-size-in-gb-or-mb chore: size in GB or MB * fix: Remove urls from headings of End User lisence agreements (#65) * fix: move padding to right place * chore: fixed double space --------- Co-authored-by: Anton Yarmolenko <37253+rnr@users.noreply.github.com> Co-authored-by: Shafqat Muneer --- .../Presentation/Base/FieldsView.swift | 2 +- .../Presentation/Login/SignInView.swift | 7 ++-- Core/Core.xcodeproj/project.pbxproj | 4 ++ Core/Core/View/Base/AlertView.swift | 1 + .../View/Base/RegistrationTextField.swift | 2 +- Core/Core/View/Base/SecureInputView.swift | 39 +++++++++++++++++++ .../CourseVideoDownloadBarView.swift | 2 +- .../CourseVideoDownloadBarViewModel.swift | 14 +++++-- .../Presentation/AllCoursesView.swift | 16 ++++---- OpenEdX/Data/AppStorage.swift | 6 +++ 10 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 Core/Core/View/Base/SecureInputView.swift diff --git a/Authorization/Authorization/Presentation/Base/FieldsView.swift b/Authorization/Authorization/Presentation/Base/FieldsView.swift index e69cce798..d876bba14 100644 --- a/Authorization/Authorization/Presentation/Base/FieldsView.swift +++ b/Authorization/Authorization/Presentation/Base/FieldsView.swift @@ -115,7 +115,7 @@ struct FieldsView: View { } private func handleURL(_ url: URL) -> OpenURLAction.Result { - router.showWebBrowser(title: url.host ?? "", url: url) + router.showWebBrowser(title: "", url: url) return .handled } } diff --git a/Authorization/Authorization/Presentation/Login/SignInView.swift b/Authorization/Authorization/Presentation/Login/SignInView.swift index 84d14adb0..e4bb7335b 100644 --- a/Authorization/Authorization/Presentation/Login/SignInView.swift +++ b/Authorization/Authorization/Presentation/Login/SignInView.swift @@ -104,9 +104,8 @@ public struct SignInView: View { .foregroundColor(Theme.Colors.textPrimary) .padding(.top, 18) .accessibilityIdentifier("password_text") - SecureField("", text: $password) + SecureInputView($password) .font(Theme.Fonts.bodyLarge) - .foregroundColor(Theme.Colors.textInputTextColor) .padding(.all, 14) .background( Theme.InputFieldBackground( @@ -280,7 +279,7 @@ public struct SignInView: View { .navigationBarHidden(true) .ignoresSafeArea(.all, edges: .horizontal) .background(Theme.Colors.background.ignoresSafeArea(.all)) - .onFirstAppear{ + .onFirstAppear { viewModel.trackScreenEvent() } } @@ -309,7 +308,7 @@ public struct SignInView: View { } private func handleURL(_ url: URL) -> OpenURLAction.Result { - viewModel.router.showWebBrowser(title: url.host ?? "", url: url) + viewModel.router.showWebBrowser(title: "", url: url) return .handled } } diff --git a/Core/Core.xcodeproj/project.pbxproj b/Core/Core.xcodeproj/project.pbxproj index d1a063a0e..e58070797 100644 --- a/Core/Core.xcodeproj/project.pbxproj +++ b/Core/Core.xcodeproj/project.pbxproj @@ -134,6 +134,7 @@ 9784D47E2BF7762800AFEFFF /* FullScreenErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9784D47D2BF7762800AFEFFF /* FullScreenErrorView.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 */; }; A5F4E7B52B61544A00ACD166 /* BrazeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F4E7B42B61544A00ACD166 /* BrazeConfig.swift */; }; BA4AFB422B5A7A0900A21367 /* VideoDownloadQualityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AFB412B5A7A0900A21367 /* VideoDownloadQualityView.swift */; }; BA4AFB442B6A5AF100A21367 /* CheckBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AFB432B6A5AF100A21367 /* CheckBoxView.swift */; }; @@ -340,6 +341,7 @@ 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 = ""; }; 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 = ""; }; @@ -735,6 +737,7 @@ 06DEA4A22BBD66A700110D20 /* BackNavigationButton.swift */, 06DEA4A42BBD66D700110D20 /* BackNavigationButtonViewModel.swift */, 0267F8502C3C256F0089D810 /* FileWebView.swift */, + A5D4B3DD2CDD0A9700688951 /* SecureInputView.swift */, ); path = Base; sourceTree = ""; @@ -1130,6 +1133,7 @@ 06619EAA2B8F2936001FAADE /* ReadabilityModifier.swift in Sources */, BAFB99902B14B377007D09F9 /* GoogleConfig.swift in Sources */, 029A132C2C2471F8005FB830 /* OfflineSyncEndpoint.swift in Sources */, + A5D4B3DE2CDD0A9700688951 /* SecureInputView.swift in Sources */, 02CF46C829546AA200A698EE /* NoCachedDataError.swift in Sources */, 0727877728D23847002E9142 /* DataLayer.swift in Sources */, 0241666B28F5A78B00082765 /* HTMLFormattedText.swift in Sources */, diff --git a/Core/Core/View/Base/AlertView.swift b/Core/Core/View/Base/AlertView.swift index 6b754e564..d3b5a7ae5 100644 --- a/Core/Core/View/Base/AlertView.swift +++ b/Core/Core/View/Base/AlertView.swift @@ -167,6 +167,7 @@ public struct AlertView: View { .font(Theme.Fonts.titleLarge) .foregroundColor(Theme.Colors.textPrimary) .padding(.horizontal, 40) + .fixedSize(horizontal: false, vertical: true) Text(alertMessage) .font(Theme.Fonts.bodyMedium) .foregroundColor(Theme.Colors.textPrimary) diff --git a/Core/Core/View/Base/RegistrationTextField.swift b/Core/Core/View/Base/RegistrationTextField.swift index 7cf4788d4..83cb3eb24 100644 --- a/Core/Core/View/Base/RegistrationTextField.swift +++ b/Core/Core/View/Base/RegistrationTextField.swift @@ -67,7 +67,7 @@ public struct RegistrationTextField: View { .accessibilityIdentifier("\(config.field.name)_textarea") } else { if textContentType == .password { - SecureField(placeholder, text: $config.text) + SecureInputView($config.text) .keyboardType(keyboardType) .textContentType(textContentType) .autocapitalization(.none) diff --git a/Core/Core/View/Base/SecureInputView.swift b/Core/Core/View/Base/SecureInputView.swift new file mode 100644 index 000000000..872c1f74c --- /dev/null +++ b/Core/Core/View/Base/SecureInputView.swift @@ -0,0 +1,39 @@ +// +// SecureInputView.swift +// Core +// +// Created by Anton Yarmolenka on 25/07/2024. +// + +import SwiftUI +import Theme + +public struct SecureInputView: View { + + @Binding private var text: String + @State private var isSecured: Bool = true + + public init(_ text: Binding) { + self._text = text + } + + public var body: some View { + ZStack(alignment: .trailing) { + Group { + if isSecured { + SecureField("", text: $text) + } else { + TextField("", text: $text) + } + }.padding(.trailing, 32) + + Button(action: { + isSecured.toggle() + }) { + Image(systemName: self.isSecured ? "eye.slash" : "eye") + .accentColor(Theme.Colors.textInputPlaceholderColor) + } + .frame(height: 23) + } + } +} diff --git a/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarView.swift b/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarView.swift index 50ca98bbb..8af9257e4 100644 --- a/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarView.swift +++ b/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarView.swift @@ -114,7 +114,7 @@ struct CourseVideoDownloadBarView: View { .accessibilityIdentifier("remaining_videos_text") } if let totalSize = viewModel.totalSize { - let text = ", \(totalSize)MB \(CourseLocalization.Download.total)" + let text = ", \(totalSize) \(CourseLocalization.Download.total)" Text(text) .accessibilityElement(children: .ignore) .accessibilityLabel(text) diff --git a/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarViewModel.swift b/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarViewModel.swift index 704a7ad64..41d80a109 100644 --- a/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarViewModel.swift +++ b/Course/Course/Presentation/Subviews/CourseVideoDownloadBarView/CourseVideoDownloadBarViewModel.swift @@ -88,9 +88,9 @@ final class CourseVideoDownloadBarViewModel: ObservableObject { if isOn { let size = mb - calculateSize(value: mb, percentage: progress * 100) if size == 0 { - return String(format: "%.2f", mb) + return sizeInMbOrGb(size: mb) } - return String(format: "%.2f", size) + return sizeInMbOrGb(size: size) } let size = blockToMB( @@ -101,7 +101,15 @@ final class CourseVideoDownloadBarViewModel: ObservableObject { downloadQuality: downloadQuality ) - return String(format: "%.2f", size) + return sizeInMbOrGb(size: size) + } + + private func sizeInMbOrGb(size: Double) -> String { + if size >= 1024.0 { + return String(format: "%.2fGB", size / 1024.0) + } else { + return String(format: "%.2fMB", size) + } } init( diff --git a/Dashboard/Dashboard/Presentation/AllCoursesView.swift b/Dashboard/Dashboard/Presentation/AllCoursesView.swift index f35299372..caf44c036 100644 --- a/Dashboard/Dashboard/Presentation/AllCoursesView.swift +++ b/Dashboard/Dashboard/Presentation/AllCoursesView.swift @@ -59,7 +59,7 @@ public struct AllCoursesView: View { .frameLimit(width: proxy.size.width) if let myEnrollments = viewModel.myEnrollments { let useRelativeDates = viewModel.storage.useRelativeDates - LazyVGrid(columns: columns(), spacing: 15) { + LazyVGrid(columns: columns(), spacing: 0) { ForEach( Array(myEnrollments.courses.enumerated()), id: \.offset @@ -101,9 +101,9 @@ public struct AllCoursesView: View { } } } - .padding(10) - .frameLimit(width: proxy.size.width) } + .padding(10) + .frameLimit(width: proxy.size.width) } // MARK: - ProgressBar if viewModel.nextPage <= viewModel.totalPages, !viewModel.refresh { @@ -173,13 +173,13 @@ public struct AllCoursesView: View { private func columns() -> [GridItem] { isHorizontal || idiom == .pad ? [ - GridItem(.flexible()), - GridItem(.flexible()), - GridItem(.flexible()) + GridItem(.flexible(), spacing: 0), + GridItem(.flexible(), spacing: 0), + GridItem(.flexible(), spacing: 0) ] : [ - GridItem(.flexible()), - GridItem(.flexible()) + GridItem(.flexible(), spacing: 0), + GridItem(.flexible(), spacing: 0) ] } diff --git a/OpenEdX/Data/AppStorage.swift b/OpenEdX/Data/AppStorage.swift index d064da7aa..2d595cd0d 100644 --- a/OpenEdX/Data/AppStorage.swift +++ b/OpenEdX/Data/AppStorage.swift @@ -346,6 +346,12 @@ public class AppStorage: CoreStorage, ProfileStorage, WhatsNewStorage, CourseSto cookiesDate = nil user = nil userProfile = nil + // delete all cookies + if let cookies = HTTPCookieStorage.shared.cookies { + for cookie in cookies { + HTTPCookieStorage.shared.deleteCookie(cookie) + } + } } private let KEY_ACCESS_TOKEN = "accessToken" From 331062c97b1fc29d6aee4f4a0fd5b12ebe864b02 Mon Sep 17 00:00:00 2001 From: Anton Yarmolenko Date: Tue, 19 Nov 2024 15:05:53 +0100 Subject: [PATCH 3/3] chore: delete wrong color (#543) Co-authored-by: Anton Yarmolenko <37253+rnr@users.noreply.github.com> --- Core/Core/View/Base/OfflineSnackBarView.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Core/Core/View/Base/OfflineSnackBarView.swift b/Core/Core/View/Base/OfflineSnackBarView.swift index af1c9e778..c26a577ee 100644 --- a/Core/Core/View/Base/OfflineSnackBarView.swift +++ b/Core/Core/View/Base/OfflineSnackBarView.swift @@ -29,7 +29,6 @@ public struct OfflineSnackBarView: View { HStack(spacing: 12) { Text(CoreLocalization.NoInternet.offline) .accessibilityIdentifier("no_internet_text") - .foregroundColor(Theme.Colors.snackbarTextColor) Spacer() Button(action: { withAnimation { @@ -37,7 +36,6 @@ public struct OfflineSnackBarView: View { } }, label: { Text(CoreLocalization.NoInternet.dismiss) - .foregroundColor(Theme.Colors.snackbarTextColor) }) .accessibilityIdentifier("no_internet_dismiss_button") Button(action: { @@ -49,7 +47,6 @@ public struct OfflineSnackBarView: View { } }, label: { Text(CoreLocalization.NoInternet.reload) - .foregroundColor(Theme.Colors.snackbarTextColor) } ) .accessibilityIdentifier("no_internet_reload_button")