diff --git a/Core/Core/Extensions/UIApplicationExtension.swift b/Core/Core/Extensions/UIApplicationExtension.swift index 9c6f88c6f..68e63665d 100644 --- a/Core/Core/Extensions/UIApplicationExtension.swift +++ b/Core/Core/Extensions/UIApplicationExtension.swift @@ -45,7 +45,7 @@ extension UINavigationController { let image = CoreAssets.arrowLeft.image navigationBar.backIndicatorImage = image.withTintColor(CoreAssets.accentColor.color) - navigationBar.tintColor = .clear + navigationBar.backItem?.backButtonTitle = " " navigationBar.backIndicatorTransitionMaskImage = image.withTintColor(CoreAssets.accentColor.color) navigationBar.titleTextAttributes = [.foregroundColor: CoreAssets.textPrimary.color] } diff --git a/Core/Core/Extensions/UINavigationController+Animation.swift b/Core/Core/Extensions/UINavigationController+Animation.swift index 21671ea44..4f720f78c 100644 --- a/Core/Core/Extensions/UINavigationController+Animation.swift +++ b/Core/Core/Extensions/UINavigationController+Animation.swift @@ -24,7 +24,7 @@ public extension UINavigationController { duration: CFTimeInterval = 0.3 ) { addTransition(transitionType: type, duration: duration) - pushViewController(vc, animated: false) + pushViewController(vc, animated: UIAccessibility.isVoiceOverRunning) } private func addTransition( diff --git a/Core/Core/Extensions/ViewExtension.swift b/Core/Core/Extensions/ViewExtension.swift index 91a66ed92..8ccc2ae6b 100644 --- a/Core/Core/Extensions/ViewExtension.swift +++ b/Core/Core/Extensions/ViewExtension.swift @@ -263,7 +263,7 @@ public extension Image { .scaledToFit() .frame(height: 24) .padding(.horizontal, 8) - .padding(.top, topPadding) + .offset(y: topPadding) .foregroundColor(color) } } diff --git a/Core/Core/View/Base/CourseCellView.swift b/Core/Core/View/Base/CourseCellView.swift index ae21b2e7f..7c6fd419a 100644 --- a/Core/Core/View/Base/CourseCellView.swift +++ b/Core/Core/View/Base/CourseCellView.swift @@ -48,6 +48,7 @@ public struct CourseCellView: View { .cornerRadius(8) .clipShape(RoundedRectangle(cornerRadius: Theme.Shapes.cardImageRadius)) .padding(.leading, 3) + .accessibilityElement(children: .ignore) VStack(alignment: .leading) { Text(courseOrg) @@ -90,6 +91,8 @@ public struct CourseCellView: View { .background(Theme.Colors.background) .opacity(showView ? 1 : 0) .offset(y: showView ? 0 : 20) + .accessibilityElement(children: .ignore) + .accessibilityLabel(courseName + " " + (type == .dashboard ? (courseEnd == "" ? courseStart : courseEnd) : "")) .onAppear { DispatchQueue.main.asyncAfter(deadline: .now()) { withAnimation(.easeInOut(duration: (index <= 5 ? 0.3 : 0.1)) @@ -98,6 +101,7 @@ public struct CourseCellView: View { } } } + VStack { if Int(index) != cellsCount { Divider() diff --git a/Core/Core/View/Base/NavigationBar.swift b/Core/Core/View/Base/NavigationBar.swift index 2af6581f9..bcfd9837b 100644 --- a/Core/Core/View/Base/NavigationBar.swift +++ b/Core/Core/View/Base/NavigationBar.swift @@ -55,12 +55,14 @@ public struct NavigationBar: View { }, label: { CoreAssets.arrowLeft.swiftUIImage .backButtonStyle(color: leftButtonColor) + .padding(8) }) .foregroundColor(Theme.Colors.styledButtonText) }.frame(minWidth: 0, maxWidth: .infinity, alignment: .topLeading) + } if rightButtonType != nil { VStack { diff --git a/Core/Core/View/Base/StyledButton.swift b/Core/Core/View/Base/StyledButton.swift index b16f61a1a..fdad6a1d1 100644 --- a/Core/Core/View/Base/StyledButton.swift +++ b/Core/Core/View/Base/StyledButton.swift @@ -55,6 +55,8 @@ public struct StyledButton: View { .stroke(style: .init(lineWidth: 1, lineCap: .round, lineJoin: .round, miterLimit: 1)) .foregroundColor(isTransparent ? .white : .clear) ) + .accessibilityElement(children: .ignore) + .accessibilityLabel(title) } } diff --git a/Course/Course/Presentation/Container/CourseContainerView.swift b/Course/Course/Presentation/Container/CourseContainerView.swift index 726cdaeb3..4cfe2f2ce 100644 --- a/Course/Course/Presentation/Container/CourseContainerView.swift +++ b/Course/Course/Presentation/Container/CourseContainerView.swift @@ -56,7 +56,7 @@ public struct CourseContainerView: View { title: title, courseID: courseID, isVideo: false - ) + ).accessibilityAction {} .tabItem { CoreAssets.bookCircle.swiftUIImage.renderingMode(.template) Text(CourseLocalization.CourseContainer.course) @@ -68,7 +68,7 @@ public struct CourseContainerView: View { title: title, courseID: courseID, isVideo: true - ) + ).accessibilityAction {} .tabItem { CoreAssets.videoCircle.swiftUIImage.renderingMode(.template) Text(CourseLocalization.CourseContainer.videos) diff --git a/Course/Course/Presentation/Outline/CourseOutlineView.swift b/Course/Course/Presentation/Outline/CourseOutlineView.swift index 19a6fa413..03a5f623f 100644 --- a/Course/Course/Presentation/Outline/CourseOutlineView.swift +++ b/Course/Course/Presentation/Outline/CourseOutlineView.swift @@ -137,11 +137,13 @@ public struct CourseOutlineView: View { } Spacer(minLength: 84) } - }.frameLimit() + } + .frameLimit() .onRightSwipeGesture { viewModel.router.back() } }.padding(.top, 8) + .accessibilityAction {} // MARK: - Offline mode SnackBar OfflineSnackBarView( @@ -208,81 +210,91 @@ struct CourseStructureView: View { ForEach(chapter.childs, id: \.id) { child in let sequentialIndex = chapter.childs.firstIndex(where: { $0.id == child.id }) VStack(alignment: .leading) { - Button( - action: { - if let chapterIndex, let sequentialIndex { - viewModel.trackSequentialClicked(child) - viewModel.router.showCourseVerticalView( - courseID: viewModel.courseStructure?.id ?? "", - courseName: viewModel.courseStructure?.displayName ?? "", - title: child.displayName, - chapters: chapters, - chapterIndex: chapterIndex, - sequentialIndex: sequentialIndex - ) - } - }, - label: { - Group { - if child.completion == 1 { - CoreAssets.finished.swiftUIImage - .renderingMode(.template) - .foregroundColor(.accentColor) - } else { - child.type.image - } - Text(child.displayName) - .font(Theme.Fonts.titleMedium) - .multilineTextAlignment(.leading) - .lineLimit(1) - .frame( - maxWidth: idiom == .pad - ? proxy.size.width * 0.5 - : proxy.size.width * 0.6, - alignment: .leading + HStack { + Button( + action: { + if let chapterIndex, let sequentialIndex { + viewModel.trackSequentialClicked(child) + viewModel.router.showCourseVerticalView( + courseID: viewModel.courseStructure?.id ?? "", + courseName: viewModel.courseStructure?.displayName ?? "", + title: child.displayName, + chapters: chapters, + chapterIndex: chapterIndex, + sequentialIndex: sequentialIndex ) - }.foregroundColor(Theme.Colors.textPrimary) - Spacer() - if let state = viewModel.downloadState[child.id] { - switch state { - case .available: - DownloadAvailableView() - .onTapGesture { - viewModel.onDownloadViewTap( - chapter: chapter, - blockId: child.id, - state: state - ) - } - .onForeground { - viewModel.onForeground() - } - case .downloading: - DownloadProgressView() - .onTapGesture { - viewModel.onDownloadViewTap( - chapter: chapter, - blockId: child.id, - state: state - ) - } - .onBackground { - viewModel.onBackground() - } - case .finished: - DownloadFinishedView() - .onTapGesture { - viewModel.onDownloadViewTap( - chapter: chapter, - blockId: child.id, - state: state - ) - } } + }, + label: { + Group { + if child.completion == 1 { + CoreAssets.finished.swiftUIImage + .renderingMode(.template) + .foregroundColor(.accentColor) + } else { + child.type.image + } + Text(child.displayName) + .font(Theme.Fonts.titleMedium) + .multilineTextAlignment(.leading) + .lineLimit(1) + .frame( + maxWidth: idiom == .pad + ? proxy.size.width * 0.5 + : proxy.size.width * 0.6, + alignment: .leading + ) + }.foregroundColor(Theme.Colors.textPrimary) + }) .accessibilityElement(children: .ignore) + .accessibilityLabel(child.displayName) + Spacer() + if let state = viewModel.downloadState[child.id] { + switch state { + case .available: + DownloadAvailableView() + .accessibilityElement(children: .ignore) + .accessibilityLabel(CourseLocalization.Accessibility.download) + .onTapGesture { + viewModel.onDownloadViewTap( + chapter: chapter, + blockId: child.id, + state: state + ) + } + .onForeground { + viewModel.onForeground() + } + case .downloading: + DownloadProgressView() + .accessibilityElement(children: .ignore) + .accessibilityLabel(CourseLocalization.Accessibility.cancelDownload) + .onTapGesture { + viewModel.onDownloadViewTap( + chapter: chapter, + blockId: child.id, + state: state + ) + } + .onBackground { + viewModel.onBackground() + } + case .finished: + DownloadFinishedView() + .accessibilityElement(children: .ignore) + .accessibilityLabel(CourseLocalization.Accessibility.deleteDownload) + .onTapGesture { + viewModel.onDownloadViewTap( + chapter: chapter, + blockId: child.id, + state: state + ) + } } - Image(systemName: "chevron.right") - .foregroundColor(Theme.Colors.accentColor) - }).padding(.horizontal, 36) + } + Image(systemName: "chevron.right") + .foregroundColor(Theme.Colors.accentColor) + } + .padding(.horizontal, 36) .padding(.vertical, 20) if chapterIndex != chapters.count - 1 { Divider() diff --git a/Course/Course/Presentation/Outline/CourseVerticalView.swift b/Course/Course/Presentation/Outline/CourseVerticalView.swift index 20b1bc56f..b85677818 100644 --- a/Course/Course/Presentation/Outline/CourseVerticalView.swift +++ b/Course/Course/Presentation/Outline/CourseVerticalView.swift @@ -54,6 +54,7 @@ public struct CourseVerticalView: View { // MARK: - Lessons list ForEach(viewModel.verticals, id: \.id) { vertical in if let index = viewModel.verticals.firstIndex(where: {$0.id == vertical.id}) { + HStack { Button(action: { let vertical = viewModel.verticals[index] if let block = vertical.childs.first { @@ -74,7 +75,6 @@ public struct CourseVerticalView: View { ) } }, label: { - HStack { Group { if vertical.completion == 1 { CoreAssets.finished.swiftUIImage @@ -93,11 +93,15 @@ public struct CourseVerticalView: View { .multilineTextAlignment(.leading) .frame(maxWidth: .infinity, alignment: .leading) }.foregroundColor(Theme.Colors.textPrimary) + }).accessibilityElement(children: .ignore) + .accessibilityLabel(vertical.displayName) Spacer() if let state = viewModel.downloadState[vertical.id] { switch state { case .available: DownloadAvailableView() + .accessibilityElement(children: .ignore) + .accessibilityLabel(CourseLocalization.Accessibility.download) .onTapGesture { viewModel.onDownloadViewTap( blockId: vertical.id, @@ -109,6 +113,8 @@ public struct CourseVerticalView: View { } case .downloading: DownloadProgressView() + .accessibilityElement(children: .ignore) + .accessibilityLabel(CourseLocalization.Accessibility.cancelDownload) .onTapGesture { viewModel.onDownloadViewTap( blockId: vertical.id, @@ -120,6 +126,8 @@ public struct CourseVerticalView: View { } case .finished: DownloadFinishedView() + .accessibilityElement(children: .ignore) + .accessibilityLabel(CourseLocalization.Accessibility.deleteDownload) .onTapGesture { viewModel.onDownloadViewTap( blockId: vertical.id, @@ -131,7 +139,7 @@ public struct CourseVerticalView: View { Image(systemName: "chevron.right") .padding(.vertical, 8) } - }).padding(.horizontal, 36) + .padding(.horizontal, 36) .padding(.vertical, 14) if index != viewModel.verticals.count - 1 { Divider() @@ -143,7 +151,8 @@ public struct CourseVerticalView: View { } } Spacer(minLength: 84) - }.frameLimit() + }.accessibilityAction {} + .frameLimit() .onRightSwipeGesture { viewModel.router.back() } diff --git a/Course/Course/SwiftGen/Strings.swift b/Course/Course/SwiftGen/Strings.swift index 9ec7b8b36..2eaafb3bf 100644 --- a/Course/Course/SwiftGen/Strings.swift +++ b/Course/Course/SwiftGen/Strings.swift @@ -10,6 +10,14 @@ import Foundation // swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces public enum CourseLocalization { + public enum Accessibility { + /// Cancel download + public static let cancelDownload = CourseLocalization.tr("Localizable", "ACCESSIBILITY.CANCEL_DOWNLOAD", fallback: "Cancel download") + /// Delete download + public static let deleteDownload = CourseLocalization.tr("Localizable", "ACCESSIBILITY.DELETE_DOWNLOAD", fallback: "Delete download") + /// Download + public static let download = CourseLocalization.tr("Localizable", "ACCESSIBILITY.DOWNLOAD", fallback: "Download") + } public enum Alert { /// Rotate your device to view this video in full screen. public static let rotateDevice = CourseLocalization.tr("Localizable", "ALERT.ROTATE_DEVICE", fallback: "Rotate your device to view this video in full screen.") diff --git a/Course/Course/en.lproj/Localizable.strings b/Course/Course/en.lproj/Localizable.strings index a37d426c0..3152f86c7 100644 --- a/Course/Course/en.lproj/Localizable.strings +++ b/Course/Course/en.lproj/Localizable.strings @@ -52,3 +52,7 @@ "NOT_AVALIABLE.BUTTON" = "Open in browser"; "SUBTITLES.TITLE" = "Subtitles"; + +"ACCESSIBILITY.DOWNLOAD" = "Download"; +"ACCESSIBILITY.CANCEL_DOWNLOAD" = "Cancel download"; +"ACCESSIBILITY.DELETE_DOWNLOAD" = "Delete download"; diff --git a/Course/Course/uk.lproj/Localizable.strings b/Course/Course/uk.lproj/Localizable.strings index 4f7ff5f87..302297084 100644 --- a/Course/Course/uk.lproj/Localizable.strings +++ b/Course/Course/uk.lproj/Localizable.strings @@ -51,3 +51,7 @@ "NOT_AVALIABLE.BUTTON" = "Відкрити в браузері"; "SUBTITLES.TITLE" = "Субтитри"; + +"ACCESSIBILITY.DOWNLOAD" = "Скачати"; +"ACCESSIBILITY.CANCEL_DOWNLOAD" = "Скасувати завантаження"; +"ACCESSIBILITY.DELETE_DOWNLOAD" = "Видалити файл"; diff --git a/Dashboard/Dashboard/Presentation/DashboardView.swift b/Dashboard/Dashboard/Presentation/DashboardView.swift index 4be6e62e7..80edb3ee5 100644 --- a/Dashboard/Dashboard/Presentation/DashboardView.swift +++ b/Dashboard/Dashboard/Presentation/DashboardView.swift @@ -18,6 +18,8 @@ public struct DashboardView: View { .foregroundColor(Theme.Colors.textPrimary) }.listRowBackground(Color.clear) .padding(.top, 24) + .accessibilityElement(children: .ignore) + .accessibilityLabel(DashboardLocalization.Header.courses + DashboardLocalization.Header.welcomeBack) @StateObject private var viewModel: DashboardViewModel @@ -91,7 +93,8 @@ public struct DashboardView: View { } } } - }.frameLimit() + }.accessibilityAction {} + .frameLimit() }.padding(.top, 8) // MARK: - Offline mode SnackBar diff --git a/Discovery/Discovery/Presentation/DiscoveryView.swift b/Discovery/Discovery/Presentation/DiscoveryView.swift index 2abf4dd78..a90b41a9b 100644 --- a/Discovery/Discovery/Presentation/DiscoveryView.swift +++ b/Discovery/Discovery/Presentation/DiscoveryView.swift @@ -22,6 +22,8 @@ public struct DiscoveryView: View { .font(Theme.Fonts.titleSmall) .foregroundColor(Theme.Colors.textPrimary) }.listRowBackground(Color.clear) + .accessibilityElement(children: .ignore) + .accessibilityLabel(DiscoveryLocalization.Header.title1 + DiscoveryLocalization.Header.title2) public init(viewModel: DiscoveryViewModel) { self._viewModel = StateObject(wrappedValue: { viewModel }()) @@ -56,12 +58,15 @@ public struct DiscoveryView: View { Theme.Shapes.textInputShape .stroke(lineWidth: 1) .fill(Theme.Colors.textInputUnfocusedStroke) - ).onTapGesture { + ) + .onTapGesture { viewModel.router.showDiscoverySearch() viewModel.discoverySearchBarClicked() } .padding(.horizontal, 24) .padding(.bottom, 20) + .accessibilityElement(children: .ignore) + .accessibilityLabel(DiscoveryLocalization.search) ZStack { RefreshableScrollViewCompat(action: { @@ -112,8 +117,9 @@ public struct DiscoveryView: View { } VStack {}.frame(height: 40) } - }.frameLimit() - } + } + .frameLimit() + }.accessibilityAction {} }.padding(.top, 8) // MARK: - Offline mode SnackBar diff --git a/Discovery/Discovery/Presentation/SearchView.swift b/Discovery/Discovery/Presentation/SearchView.swift index 09e4619cf..77dd693c8 100644 --- a/Discovery/Discovery/Presentation/SearchView.swift +++ b/Discovery/Discovery/Presentation/SearchView.swift @@ -10,10 +10,12 @@ import Core public struct SearchView: View { + @FocusState + private var focused: Bool + @ObservedObject private var viewModel: SearchViewModel @State private var animated: Bool = false - @State private var becomeFirstResponderRunOnce = false public init(viewModel: SearchViewModel) { self.viewModel = viewModel @@ -38,6 +40,7 @@ public struct SearchView: View { ? Theme.Colors.accentColor : Theme.Colors.textPrimary ) + .accessibilityHidden(true) TextField( !viewModel.isSearchActive @@ -47,13 +50,10 @@ public struct SearchView: View { onEditingChanged: { editing in viewModel.isSearchActive = editing } - ) - .introspect(.textField, on: .iOS(.v14, .v15, .v16, .v17), customize: { textField in - if !becomeFirstResponderRunOnce { - textField.becomeFirstResponder() - self.becomeFirstResponderRunOnce = true + ).focused($focused) + .onAppear { + self.focused = true } - }) .foregroundColor(Theme.Colors.textPrimary) Spacer() if !viewModel.searchText.trimmingCharacters(in: .whitespaces).isEmpty { @@ -169,6 +169,8 @@ public struct SearchView: View { .font(Theme.Fonts.titleSmall) .foregroundColor(Theme.Colors.textPrimary) }.listRowBackground(Color.clear) + .accessibilityElement(children: .ignore) + .accessibilityLabel(DiscoveryLocalization.Search.title + searchDescription(viewModel: viewModel)) } private func searchDescription(viewModel: SearchViewModel) -> String { diff --git a/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionSearchTopicsView.swift b/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionSearchTopicsView.swift index 24d4335da..c1526b020 100644 --- a/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionSearchTopicsView.swift +++ b/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionSearchTopicsView.swift @@ -10,9 +10,11 @@ import Core public struct DiscussionSearchTopicsView: View { + @FocusState + private var focused: Bool + @ObservedObject private var viewModel: DiscussionSearchTopicsViewModel @State private var animated: Bool = false - @State private var becomeFirstResponderRunOnce = false public init(viewModel: DiscussionSearchTopicsViewModel) { self.viewModel = viewModel @@ -44,13 +46,10 @@ public struct DiscussionSearchTopicsView: View { onEditingChanged: { editing in viewModel.isSearchActive = editing } - ) - .introspect(.textField, on: .iOS(.v14, .v15, .v16, .v17), customize: { textField in - if !becomeFirstResponderRunOnce { - textField.becomeFirstResponder() - self.becomeFirstResponderRunOnce = true + ).focused($focused) + .onAppear { + self.focused = true } - }) .foregroundColor(Theme.Colors.textPrimary) Spacer() if !viewModel.searchText.trimmingCharacters(in: .whitespaces).isEmpty { diff --git a/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift b/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift index 722e1b9fd..4e690d15a 100644 --- a/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift +++ b/Discussion/Discussion/Presentation/DiscussionTopics/DiscussionTopicsView.swift @@ -49,6 +49,8 @@ public struct DiscussionTopicsView: View { } .padding(.horizontal, 24) .padding(.bottom, 20) + .accessibilityElement(children: .ignore) + .accessibilityLabel(DiscussionLocalization.Topics.search) // MARK: - Page Body VStack { diff --git a/Discussion/Discussion/Presentation/Posts/PostsView.swift b/Discussion/Discussion/Presentation/Posts/PostsView.swift index 906a47ce2..4cd46f5cb 100644 --- a/Discussion/Discussion/Presentation/Posts/PostsView.swift +++ b/Discussion/Discussion/Presentation/Posts/PostsView.swift @@ -186,7 +186,8 @@ public struct PostsView: View { } } } - }.frameLimit() + }.accessibilityAction {} + .frameLimit() .animation(nil) .onRightSwipeGesture { router.back() diff --git a/Profile/Profile/Presentation/Profile/ProfileView.swift b/Profile/Profile/Presentation/Profile/ProfileView.swift index 3456a1444..8df18256e 100644 --- a/Profile/Profile/Presentation/Profile/ProfileView.swift +++ b/Profile/Profile/Presentation/Profile/ProfileView.swift @@ -66,6 +66,15 @@ public struct ProfileView: View { } } } + .accessibilityElement(children: .ignore) + .accessibilityLabel( + (viewModel.userModel?.yearOfBirth != 0 ? + ProfileLocalization.Edit.Fields.yearOfBirth + String(viewModel.userModel?.yearOfBirth ?? 0) : + "") + + (viewModel.userModel?.shortBiography != nil ? + ProfileLocalization.bio + (viewModel.userModel?.shortBiography ?? "") : + "") + ) .cardStyle( bgColor: Theme.Colors.textInputUnfocusedBackground, strokeColor: .clear @@ -90,7 +99,10 @@ public struct ProfileView: View { } }) - }.cardStyle( + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(ProfileLocalization.settingsVideo) + .cardStyle( bgColor: Theme.Colors.textInputUnfocusedBackground, strokeColor: .clear ) @@ -113,6 +125,8 @@ public struct ProfileView: View { }) .buttonStyle(PlainButtonStyle()) .foregroundColor(.primary) + .accessibilityElement(children: .ignore) + .accessibilityLabel(ProfileLocalization.supportInfo) Rectangle() .frame(height: 1) .foregroundColor(Theme.Colors.textSecondary) @@ -131,6 +145,8 @@ public struct ProfileView: View { }) .buttonStyle(PlainButtonStyle()) .foregroundColor(.primary) + .accessibilityElement(children: .ignore) + .accessibilityLabel(ProfileLocalization.terms) Rectangle() .frame(height: 1) .foregroundColor(Theme.Colors.textSecondary) @@ -149,55 +165,57 @@ public struct ProfileView: View { }) .buttonStyle(PlainButtonStyle()) .foregroundColor(.primary) + .accessibilityElement(children: .ignore) + .accessibilityLabel(ProfileLocalization.privacy) } // MARK: Version - Rectangle() - .frame(height: 1) - .foregroundColor(Theme.Colors.textSecondary) - Button(action: { - viewModel.openAppStore() - }, label: { - HStack { - VStack(alignment: .leading, spacing: 0) { - HStack { - if viewModel.versionState == .updateRequired { - CoreAssets.warningFilled.swiftUIImage - .resizable() - .frame(width: 24, height: 24) - } - Text("\(ProfileLocalization.Settings.version) \(viewModel.currentVersion)") + Rectangle() + .frame(height: 1) + .foregroundColor(Theme.Colors.textSecondary) + Button(action: { + viewModel.openAppStore() + }, label: { + HStack { + VStack(alignment: .leading, spacing: 0) { + HStack { + if viewModel.versionState == .updateRequired { + CoreAssets.warningFilled.swiftUIImage + .resizable() + .frame(width: 24, height: 24) } - switch viewModel.versionState { - case .actual: - HStack { - CoreAssets.checkmark.swiftUIImage - .renderingMode(.template) - .foregroundColor(.green) - Text(ProfileLocalization.Settings.upToDate) - .font(Theme.Fonts.labelMedium) - .foregroundStyle(Theme.Colors.textSecondary) - } - case .updateNeeded: - Text("\(ProfileLocalization.Settings.tapToUpdate) \(viewModel.latestVersion)") - .font(Theme.Fonts.labelMedium) - .foregroundStyle(Theme.Colors.accentColor) - case .updateRequired: - Text(ProfileLocalization.Settings.tapToInstall) + Text("\(ProfileLocalization.Settings.version) \(viewModel.currentVersion)") + } + switch viewModel.versionState { + case .actual: + HStack { + CoreAssets.checkmark.swiftUIImage + .renderingMode(.template) + .foregroundColor(.green) + Text(ProfileLocalization.Settings.upToDate) .font(Theme.Fonts.labelMedium) - .foregroundStyle(Theme.Colors.accentColor) + .foregroundStyle(Theme.Colors.textSecondary) } - } - Spacer() - if viewModel.versionState != .actual { - Image(systemName: "arrow.up.circle") - .resizable() - .frame(width: 24, height: 24) + case .updateNeeded: + Text("\(ProfileLocalization.Settings.tapToUpdate) \(viewModel.latestVersion)") + .font(Theme.Fonts.labelMedium) + .foregroundStyle(Theme.Colors.accentColor) + case .updateRequired: + Text(ProfileLocalization.Settings.tapToInstall) + .font(Theme.Fonts.labelMedium) .foregroundStyle(Theme.Colors.accentColor) } - } - }).disabled(viewModel.versionState == .actual) + Spacer() + if viewModel.versionState != .actual { + Image(systemName: "arrow.up.circle") + .resizable() + .frame(width: 24, height: 24) + .foregroundStyle(Theme.Colors.accentColor) + } + + } + }).disabled(viewModel.versionState == .actual) }.cardStyle( bgColor: Theme.Colors.textInputUnfocusedBackground, @@ -230,7 +248,8 @@ public struct ProfileView: View { Image(systemName: "rectangle.portrait.and.arrow.right") } }) - + .accessibilityElement(children: .ignore) + .accessibilityLabel(ProfileLocalization.logout) } .foregroundColor(Theme.Colors.alert) .cardStyle(bgColor: Theme.Colors.textInputUnfocusedBackground, @@ -241,7 +260,8 @@ public struct ProfileView: View { Spacer() } } - }.frameLimit(sizePortrait: 420) + }.accessibilityAction {} + .frameLimit(sizePortrait: 420) .padding(.top, 8) .onChange(of: settingsTapped, perform: { _ in let userModel = viewModel.userModel ?? UserProfile()