From b60866534ca826a93ce3117b659d0bc24badcd58 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Lapersonne Date: Thu, 25 Jan 2024 11:31:06 +0100 Subject: [PATCH] fix(#598): a11y - one column for grid and definable line limits for small card (#643) Signed-off-by: Pierre-Yves Lapersonne --- CHANGELOG.md | 2 + .../Components/Cards/ODSCardSmall.swift | 39 ++++++++++++++++--- .../GridOfSmallCards.swift | 37 +++++++++++------- docs/components/cards.md | 14 ++++++- 4 files changed, 72 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 512c8b13..7fde2965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - [SDK] Update cards to align buttons when text is too long ([#630](https://github.com/Orange-OpenSource/ods-ios/issues/6380)) - [Tooling] Upgrate to xcode 15 ([#638](https://github.com/Orange-OpenSource/ods-ios/issues/638)) +- [DemoApp/SDK] ODSSmallCard and GridOfSmallCards a11i issue if accessible text sizes in use ([#598](https://github.com/Orange-OpenSource/ods-ios/issues/598)) +- [Tooling] Upgrade to Xcode 15 ([#638](https://github.com/Orange-OpenSource/ods-ios/issues/638)) - [Tooling] Upgrade tools versions and internal librairies ([#639](https://github.com/Orange-OpenSource/ods-ios/issues/639)) - [Docs] Update documentation with illustration ([#602](https://github.com/Orange-OpenSource/ods-ios/issues/602)) - [Tooling] Add GitHub Actions for Gitleaks runs to look for secrets leaks ([#605](https://github.com/Orange-OpenSource/ods-ios/issues/605)) diff --git a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift index d4204f6d..6817a731 100644 --- a/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift +++ b/OrangeDesignSystem/Sources/OrangeDesignSystem/Components/Cards/ODSCardSmall.swift @@ -24,6 +24,10 @@ public struct ODSCardSmall: View { private let title: Text private let subtitle: Text? private let imageSource: ODSImage.Source + private let titleAccessibleLineLimit: Int? + private let subtitleAccessibleLineLimit: Int? + + @Environment(\.sizeCategory) private var sizeCategory // ================= // MARK: Initializer @@ -34,12 +38,15 @@ public struct ODSCardSmall: View { /// - Parameters: /// - title: Title displayed into the card. /// - imageSource: Image from source [ODSImage.Source] displayed into the card. - /// - subtitle: Optional subtitle displayed into the card. - /// - public init(title: Text, imageSource: ODSImage.Source, subtitle: Text? = nil) { + /// - subtitle: Optional subtitle displayed into the card,d efault set to `nil` + /// - titleAccessibleLineLimit: The line limit to apply to the title is size category is accessibility category, default set to `nil` + /// - subtitleAccessibleLineLimit: The line limit to apply to the subtitle is size category is accessibility category, default set to `nil` + public init(title: Text, imageSource: ODSImage.Source, subtitle: Text? = nil, titleAccessibleLineLimit: Int? = nil, subtitleAccessibleLineLimit: Int? = nil) { self.title = title self.subtitle = subtitle self.imageSource = imageSource + self.titleAccessibleLineLimit = titleAccessibleLineLimit + self.subtitleAccessibleLineLimit = subtitleAccessibleLineLimit } // ========== @@ -56,23 +63,45 @@ public struct ODSCardSmall: View { VStack(alignment: .leading, spacing: ODSSpacing.xs) { title - .lineLimit(1) + .lineLimit(sizeCategory.isAccessibilityCategory ? titleAccessibleLineLimit : 1) .odsFont(.bodyLBold) .frame(maxWidth: .infinity, alignment: .leading) subtitle? - .lineLimit(1) + .lineLimit(sizeCategory.isAccessibilityCategory ? subtitleAccessibleLineLimit : 1) .odsFont(.bodyLRegular) .frame(maxWidth: .infinity, alignment: .leading) } .accessibilityElement(children: .combine) .padding(.all, ODSSpacing.m) + .modifier(AccessibleMultilineTextAlignment()) } .foregroundColor(.primary) .modifier(CardShadowModifier()) } } +// =========================================== +// MARK: - Accessible Multiline Text Alignment +// =========================================== + +private struct AccessibleMultilineTextAlignment: ViewModifier { + + @Environment(\.sizeCategory) private var sizeCategory + + func body(content: Content) -> some View { + if sizeCategory.isAccessibilityCategory { + content.multilineTextAlignment(.leading) + } else { + content + } + } +} + +// ======================== +// MARK: - Preview Provider +// ======================== + #if DEBUG struct SmallCardView_Previews: PreviewProvider { diff --git a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/CardListAndCollection/GridOfSmallCards.swift b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/CardListAndCollection/GridOfSmallCards.swift index 785d8d56..69e79124 100644 --- a/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/CardListAndCollection/GridOfSmallCards.swift +++ b/OrangeDesignSystemDemo/OrangeDesignSystemDemo/Screens/Modules/CardListAndCollection/GridOfSmallCards.swift @@ -16,6 +16,8 @@ import SwiftUI struct GrifOfSmallCards: View { + @Environment(\.sizeCategory) private var sizeCategory + // ======================= // MARK: Stored Properties // ======================= @@ -30,21 +32,30 @@ struct GrifOfSmallCards: View { var body: some View { ScrollView { - LazyVGrid(columns: columns, spacing: ODSSpacing.xs) { - ForEach(RecipeBook.shared.recipes, id: \.id) { recipe in - NavigationLink { - Text("shared.bon_app") - .navigationBarTitleDisplayMode(.inline) - .navigationbarMenuForThemeSelection() - } label: { - ODSCardSmall( - title: Text(recipe.title), - imageSource: .asyncImage(recipe.url, Image("ods_empty", bundle: Bundle.ods)), - subtitle: Text(recipe.subtitle)) - } + if sizeCategory.isAccessibilityCategory { + recipesCards() + .padding(.all, ODSSpacing.m) + } else { + LazyVGrid(columns: columns, spacing: ODSSpacing.xs) { + recipesCards() } + .padding(.all, ODSSpacing.m) + } + } + } + + private func recipesCards() -> some View { + ForEach(RecipeBook.shared.recipes, id: \.id) { recipe in + NavigationLink { + Text("shared.bon_app") + .navigationBarTitleDisplayMode(.inline) + .navigationbarMenuForThemeSelection() + } label: { + ODSCardSmall( + title: Text(recipe.title), + imageSource: .asyncImage(recipe.url, Image("ods_empty", bundle: Bundle.ods)), + subtitle: Text(recipe.subtitle)) } - .padding(.all, ODSSpacing.m) } } } diff --git a/docs/components/cards.md b/docs/components/cards.md index 9edcc129..0cc5ba36 100644 --- a/docs/components/cards.md +++ b/docs/components/cards.md @@ -200,6 +200,16 @@ ScrollView { ``` - - +However for accessibility edge cases, like when text sizes are accessibility sizes, the behaviour is different for such components. They won't be displayed in one truncated line because the text will be too truncated and difficult to read. +If this choice is too impacting for your UI, it is possible to define the limit number of lines to use if a11y size are used +```swift +ODSCardSmall( + title: Text("Title"), + imageSource: .image(Image("ods_empty", bundle: Bundle.ods)), + subtitle: Text("Subtitle"), + // Here 3 is the number of lines you want for such edge cases + titleAccessibleLineLimit: 3, + subtitleAccessibleLineLimit: 3 +) +```