diff --git a/AccessibilityTalk.xcodeproj/project.pbxproj b/AccessibilityTalk.xcodeproj/project.pbxproj index 0e6e57a..74e4260 100644 --- a/AccessibilityTalk.xcodeproj/project.pbxproj +++ b/AccessibilityTalk.xcodeproj/project.pbxproj @@ -21,10 +21,15 @@ 96088D862B799B1400E062FB /* TextSizingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D852B799B1400E062FB /* TextSizingView.swift */; }; 96088D882B7AFE7D00E062FB /* BadGoodView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D872B7AFE7D00E062FB /* BadGoodView.swift */; }; 96088D8A2B7B009400E062FB /* FlexibleSizingUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D892B7B009400E062FB /* FlexibleSizingUIView.swift */; }; + 96088D8E2B7B1BF300E062FB /* BadDayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D8D2B7B1BF300E062FB /* BadDayView.swift */; }; + 96088D902B7B20FE00E062FB /* DayState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D8F2B7B20FE00E062FB /* DayState.swift */; }; + 96088D922B7B220200E062FB /* GoodDayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D912B7B220200E062FB /* GoodDayView.swift */; }; + 96088D942B7B286E00E062FB /* CalendarBadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D932B7B286E00E062FB /* CalendarBadView.swift */; }; + 96088D962B7B300C00E062FB /* CalendarGoodView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96088D952B7B300C00E062FB /* CalendarGoodView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 96088D5E2B797B7700E062FB /* AccessibilityTalk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AccessibilityTalk.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 96088D5E2B797B7700E062FB /* Accesibility Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Accesibility Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 96088D612B797B7700E062FB /* AccessibilityTalkApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityTalkApp.swift; sourceTree = ""; }; 96088D632B797B7700E062FB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 96088D652B797B7900E062FB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -39,6 +44,11 @@ 96088D852B799B1400E062FB /* TextSizingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextSizingView.swift; sourceTree = ""; }; 96088D872B7AFE7D00E062FB /* BadGoodView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadGoodView.swift; sourceTree = ""; }; 96088D892B7B009400E062FB /* FlexibleSizingUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlexibleSizingUIView.swift; sourceTree = ""; }; + 96088D8D2B7B1BF300E062FB /* BadDayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadDayView.swift; sourceTree = ""; }; + 96088D8F2B7B20FE00E062FB /* DayState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayState.swift; sourceTree = ""; }; + 96088D912B7B220200E062FB /* GoodDayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoodDayView.swift; sourceTree = ""; }; + 96088D932B7B286E00E062FB /* CalendarBadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarBadView.swift; sourceTree = ""; }; + 96088D952B7B300C00E062FB /* CalendarGoodView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarGoodView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -63,7 +73,7 @@ 96088D5F2B797B7700E062FB /* Products */ = { isa = PBXGroup; children = ( - 96088D5E2B797B7700E062FB /* AccessibilityTalk.app */, + 96088D5E2B797B7700E062FB /* Accesibility Demo.app */, ); name = Products; sourceTree = ""; @@ -74,6 +84,11 @@ 96088D612B797B7700E062FB /* AccessibilityTalkApp.swift */, 96088D652B797B7900E062FB /* Assets.xcassets */, 96088D872B7AFE7D00E062FB /* BadGoodView.swift */, + 96088D8D2B7B1BF300E062FB /* BadDayView.swift */, + 96088D912B7B220200E062FB /* GoodDayView.swift */, + 96088D932B7B286E00E062FB /* CalendarBadView.swift */, + 96088D952B7B300C00E062FB /* CalendarGoodView.swift */, + 96088D8F2B7B20FE00E062FB /* DayState.swift */, 96088D632B797B7700E062FB /* ContentView.swift */, 96088D732B7980D700E062FB /* DynamicTypeAdaptiveView.swift */, 96088D792B79827D00E062FB /* ExampleFormBadView.swift */, @@ -114,7 +129,7 @@ ); name = AccessibilityTalk; productName = AccessibilityTalk; - productReference = 96088D5E2B797B7700E062FB /* AccessibilityTalk.app */; + productReference = 96088D5E2B797B7700E062FB /* Accesibility Demo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -168,17 +183,22 @@ buildActionMask = 2147483647; files = ( 96088D762B7981DC00E062FB /* FlexibleSizingView.swift in Sources */, + 96088D962B7B300C00E062FB /* CalendarGoodView.swift in Sources */, 96088D742B7980D700E062FB /* DynamicTypeAdaptiveView.swift in Sources */, 96088D642B797B7700E062FB /* ContentView.swift in Sources */, 96088D622B797B7700E062FB /* AccessibilityTalkApp.swift in Sources */, 96088D722B797FBA00E062FB /* FlipLayoutAxisView.swift in Sources */, 96088D822B79925200E062FB /* FlexibleSizingGoodUIView.swift in Sources */, + 96088D8E2B7B1BF300E062FB /* BadDayView.swift in Sources */, 96088D7A2B79827D00E062FB /* ExampleFormBadView.swift in Sources */, 96088D782B7981EB00E062FB /* ExampleFormGoodView.swift in Sources */, 96088D882B7AFE7D00E062FB /* BadGoodView.swift in Sources */, 96088D8A2B7B009400E062FB /* FlexibleSizingUIView.swift in Sources */, 96088D802B798DBE00E062FB /* FlexibleSizingBadUIView.swift in Sources */, + 96088D902B7B20FE00E062FB /* DayState.swift in Sources */, + 96088D922B7B220200E062FB /* GoodDayView.swift in Sources */, 96088D862B799B1400E062FB /* TextSizingView.swift in Sources */, + 96088D942B7B286E00E062FB /* CalendarBadView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -326,7 +346,7 @@ ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = co.1se.AccessibilityTalk; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "Accesibility Demo"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -355,7 +375,7 @@ ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = co.1se.AccessibilityTalk; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "Accesibility Demo"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/AccessibilityTalk/Assets.xcassets/AccentColor.colorset/Contents.json b/AccessibilityTalk/Assets.xcassets/AccentColor.colorset/Contents.json index eb87897..a9f9aaa 100644 --- a/AccessibilityTalk/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/AccessibilityTalk/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,6 +1,10 @@ { "colors" : [ { + "color" : { + "platform" : "universal", + "reference" : "systemPurpleColor" + }, "idiom" : "universal" } ], diff --git a/AccessibilityTalk/Assets.xcassets/AppIcon.appiconset/AccessibilityTalkAppIcon-1024.png b/AccessibilityTalk/Assets.xcassets/AppIcon.appiconset/AccessibilityTalkAppIcon-1024.png new file mode 100644 index 0000000..b4c07f6 Binary files /dev/null and b/AccessibilityTalk/Assets.xcassets/AppIcon.appiconset/AccessibilityTalkAppIcon-1024.png differ diff --git a/AccessibilityTalk/Assets.xcassets/AppIcon.appiconset/Contents.json b/AccessibilityTalk/Assets.xcassets/AppIcon.appiconset/Contents.json index 13613e3..bc45e38 100644 --- a/AccessibilityTalk/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/AccessibilityTalk/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,6 +1,7 @@ { "images" : [ { + "filename" : "AccessibilityTalkAppIcon-1024.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/AccessibilityTalk/Assets.xcassets/Geese.imageset/Contents.json b/AccessibilityTalk/Assets.xcassets/Geese.imageset/Contents.json new file mode 100644 index 0000000..007844e --- /dev/null +++ b/AccessibilityTalk/Assets.xcassets/Geese.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "geese.jpg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AccessibilityTalk/Assets.xcassets/Geese.imageset/geese.jpg b/AccessibilityTalk/Assets.xcassets/Geese.imageset/geese.jpg new file mode 100644 index 0000000..de7e1a8 Binary files /dev/null and b/AccessibilityTalk/Assets.xcassets/Geese.imageset/geese.jpg differ diff --git a/AccessibilityTalk/Assets.xcassets/IceCube.imageset/Contents.json b/AccessibilityTalk/Assets.xcassets/IceCube.imageset/Contents.json new file mode 100644 index 0000000..cc90cbf --- /dev/null +++ b/AccessibilityTalk/Assets.xcassets/IceCube.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "good-day.jpeg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AccessibilityTalk/Assets.xcassets/IceCube.imageset/good-day.jpeg b/AccessibilityTalk/Assets.xcassets/IceCube.imageset/good-day.jpeg new file mode 100644 index 0000000..e2dc0e5 Binary files /dev/null and b/AccessibilityTalk/Assets.xcassets/IceCube.imageset/good-day.jpeg differ diff --git a/AccessibilityTalk/BadDayView.swift b/AccessibilityTalk/BadDayView.swift new file mode 100644 index 0000000..c211a13 --- /dev/null +++ b/AccessibilityTalk/BadDayView.swift @@ -0,0 +1,76 @@ +// +// DayView.swift +// AccessibilityTalk +// +// Created by Work on 2024-02-12. +// + +import SwiftUI + +struct BadDayView: View { + @State var state: DayState = DayState() + + var body: some View { + ZStack { + if state.snippetCount == 0 { + Color(.systemGray3) + } else { + Image("Geese") + .resizable() + .scaledToFill() + .clipped() + } + + date + .font(.headline) + .bold() + .foregroundStyle(.thickMaterial) + .padding(4) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + + if state.hasJournal { + Image(systemName: "pencil.circle") + .font(.headline) + .bold() + .foregroundStyle(.thickMaterial) + .padding(4) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing) + } + + snippetDescription + .font(.headline) + .bold() + .foregroundStyle(.thickMaterial) + .padding(4) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading) + } + } + + private var date: some View { + Text("\(state.date.formatted(date: .abbreviated, time: .omitted))") + } + + @ViewBuilder + private var snippetDescription: some View { + switch state.snippetCount { + case 0: + EmptyView() + + case 1: + Text("1 snippet") + + default: + Text("\(state.snippetCount) snippets") + } + } +} + +#Preview { + VStack { + BadDayView() + + BadDayView(state: DayState(hasJournal: false, snippetCount: 1)) + + BadDayView(state: DayState(hasJournal: true, snippetCount: 2)) + } +} diff --git a/AccessibilityTalk/CalendarBadView.swift b/AccessibilityTalk/CalendarBadView.swift new file mode 100644 index 0000000..0f08935 --- /dev/null +++ b/AccessibilityTalk/CalendarBadView.swift @@ -0,0 +1,35 @@ +// +// CalendarBadView.swift +// AccessibilityTalk +// +// Created by Work on 2024-02-12. +// + +import SwiftUI + +struct CalendarBadView: View { + var body: some View { + LazyVGrid(columns: gridColumns, spacing: 0) { + Group { + BadDayView() + + BadDayView(state: DayState(hasJournal: false, snippetCount: 1)) + + BadDayView(state: DayState(hasJournal: true, snippetCount: 2)) + } + } + } + + private var gridColumns: [GridItem] { + let item = GridItem(.flexible(), spacing: 0) + return Array(repeating: item, count: 3) + } +} + +#Preview { + NavigationStack { + CalendarBadView() + .navigationTitle("❌ Calendar Grid") + .navigationBarTitleDisplayMode(.inline) + } +} diff --git a/AccessibilityTalk/CalendarGoodView.swift b/AccessibilityTalk/CalendarGoodView.swift new file mode 100644 index 0000000..0df1d58 --- /dev/null +++ b/AccessibilityTalk/CalendarGoodView.swift @@ -0,0 +1,40 @@ +// +// CalendarGoodView.swift +// AccessibilityTalk +// +// Created by Work on 2024-02-12. +// + +import SwiftUI + +struct CalendarGoodView: View { + @Environment(\.dynamicTypeSize) var typeSize + + var body: some View { + ScrollView { + LazyVGrid(columns: gridColumns, spacing: 0) { + Group { + GoodDayView() + + GoodDayView(state: DayState(hasJournal: false, snippetCount: 1)) + + GoodDayView(state: DayState(hasJournal: true, snippetCount: 2)) + } + } + } + .navigationTitle("✅ Calendar Grid") + .navigationBarTitleDisplayMode(.inline) + } + + private var gridColumns: [GridItem] { + let item = GridItem(.flexible(), spacing: 0) + let count = typeSize.isAccessibilitySize ? 1 : 3 + return Array(repeating: item, count: count) + } +} + +#Preview { + NavigationStack { + CalendarGoodView() + } +} diff --git a/AccessibilityTalk/ContentView.swift b/AccessibilityTalk/ContentView.swift index eaf07a8..14c2521 100644 --- a/AccessibilityTalk/ContentView.swift +++ b/AccessibilityTalk/ContentView.swift @@ -28,6 +28,13 @@ struct ContentView: View { .accessibilityLabel("Good SwiftUI Form") } } + Section("5. Calendar Grid") { + NavigationLink("❌ Bad SwiftUI Grid") { CalendarBadView() } + NavigationLink(destination: CalendarGoodView()) { + Text("✅ Good SwiftUI Grid") + .accessibilityLabel("Good SwiftUI Grid") + } + } } .navigationTitle("Accessibility Demo") .navigationBarTitleDisplayMode(.inline) diff --git a/AccessibilityTalk/DayState.swift b/AccessibilityTalk/DayState.swift new file mode 100644 index 0000000..a480b1b --- /dev/null +++ b/AccessibilityTalk/DayState.swift @@ -0,0 +1,16 @@ +// +// DayState.swift +// AccessibilityTalk +// +// Created by Work on 2024-02-12. +// + +import Foundation + +struct DayState: Hashable { + var date: Date = .now + var hasJournal: Bool = false + var snippetCount: Int = 0 + + var isEmpty: Bool { !hasJournal && snippetCount == 0 } +} diff --git a/AccessibilityTalk/GoodDayView.swift b/AccessibilityTalk/GoodDayView.swift new file mode 100644 index 0000000..92d7977 --- /dev/null +++ b/AccessibilityTalk/GoodDayView.swift @@ -0,0 +1,115 @@ +// +// GoodDayView.swift +// AccessibilityTalk +// +// Created by Work on 2024-02-12. +// + +import SwiftUI + +struct GoodDayView: View { + @State var state: DayState = DayState() + + @Environment(\.dynamicTypeSize) var typeSize + + var body: some View { + VStack(spacing: 4) { + ZStack { + if state.snippetCount == 0 { + if !typeSize.isAccessibilitySize { + Color(.systemGray3) + } + } else { + Image("IceCube") + .resizable() + .scaledToFit() + .clipped() + } + + if !typeSize.isAccessibilitySize { + Group { + date + .font(.headline) + .bold() + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + + journalIndicator + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing) + + description + .font(.headline) + .bold() + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading) + } + .foregroundStyle(.thickMaterial) + .padding(4) + } + } + .accessibilityElement() + + if typeSize.isAccessibilitySize { + date + .bold() + .padding(4) + .frame(maxWidth: .infinity, alignment: .leading) + + HStack { + description + .frame(maxWidth: .infinity, alignment: .leading) + + journalIndicator + } + .padding(4) + } + } + .accessibilityElement() + .accessibilityLabel(accessibilityDescription) + } + + private var date: some View { + Text("\(state.date.formatted(date: .abbreviated, time: .omitted))") + } + + @ViewBuilder + private var description: some View { + switch state.snippetCount { + case 0: + EmptyView() + + case 1: + Text("1 snippet") + + default: + Text("\(state.snippetCount) snippets") + } + } + + @ViewBuilder + private var journalIndicator: some View { + if state.hasJournal { + Image(systemName: "pencil.circle") + } + } + + private var accessibilityDescription: String { + [ + state.date.formatted(date: .abbreviated, time: .omitted), + state.isEmpty ? "empty" : nil, + state.snippetCount == 1 ? "1 snippet" : nil, + state.snippetCount > 1 ? "\(state.snippetCount) snippets" : nil, + state.hasJournal ? "journal entry" : nil, + ].compactMap { $0 }.joined(separator: ", ") + } +} + +#Preview { + ScrollView { + VStack { + GoodDayView() + + GoodDayView(state: DayState(hasJournal: false, snippetCount: 1)) + + GoodDayView(state: DayState(hasJournal: true, snippetCount: 2)) + } + } +}