diff --git a/IceCubesApp/App/AppRouter.swift b/IceCubesApp/App/AppRouter.swift index addc10f5..dcb99135 100644 --- a/IceCubesApp/App/AppRouter.swift +++ b/IceCubesApp/App/AppRouter.swift @@ -31,9 +31,9 @@ extension View { case let .conversationDetail(conversation): ConversationDetailView(conversation: conversation) case let .hashTag(tag, accountId): - TimelineView(timeline: .constant(.hashtag(tag: tag, accountId: accountId)), scrollToTopSignal: .constant(0)) + TimelineView(timeline: .constant(.hashtag(tag: tag, accountId: accountId)), scrollToTopSignal: .constant(0), canFilterTimeline: false) case let .list(list): - TimelineView(timeline: .constant(.list(list: list)), scrollToTopSignal: .constant(0)) + TimelineView(timeline: .constant(.list(list: list)), scrollToTopSignal: .constant(0), canFilterTimeline: false) case let .following(id): AccountsListView(mode: .following(accountId: id)) case let .followers(id): @@ -45,7 +45,7 @@ extension View { case let .accountsList(accounts): AccountsListView(mode: .accountsList(accounts: accounts)) case .trendingTimeline: - TimelineView(timeline: .constant(.trending), scrollToTopSignal: .constant(0)) + TimelineView(timeline: .constant(.trending), scrollToTopSignal: .constant(0), canFilterTimeline: false) case let .tagsList(tags): TagsListView(tags: tags) } diff --git a/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift b/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift index 6023918a..53382608 100644 --- a/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift +++ b/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift @@ -32,7 +32,7 @@ struct TimelineTab: View { var body: some View { NavigationStack(path: $routerPath.path) { - TimelineView(timeline: $timeline, scrollToTopSignal: $scrollToTopSignal) + TimelineView(timeline: $timeline, scrollToTopSignal: $scrollToTopSignal, canFilterTimeline: canFilterTimeline) .withAppRouter() .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .toolbar { diff --git a/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings index 07924067..d899669f 100644 --- a/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings @@ -529,6 +529,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Уліковыя запісы"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -562,6 +564,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Дадатковая інфармацыя"; diff --git a/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings index 70816fc4..91fb0991 100644 --- a/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings @@ -523,6 +523,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Accounts"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -556,6 +558,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Additional Info"; diff --git a/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings index cef11f1d..ec13e7a6 100644 --- a/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings @@ -519,6 +519,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Erzeugen"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld neue Beiträge"; "accessibility.tabs.timeline.unread-posts.hint" = "Bewegt durch die Timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Konten"; "accessibility.app-account.selector.accounts.hint" = "Öffnet die Optionen."; "accessibility.tabs.profile.options.label" = "Optionen"; @@ -552,6 +554,7 @@ "accessibility.status.a-replied-to-%@" = "%@ antwortete auf"; "accessibility.image.alt-text-%@" = "Alternativer Bildtext: %@"; "accessibility.image.alt-text-more.label" = "Weiterer Alt.-Text verfügbar"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Zusätzliche Informationen"; diff --git a/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings index f526a4be..82a64759 100644 --- a/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings @@ -523,6 +523,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.editor.button.characters-remaining" = "Characters remaining"; "accessibility.editor.privacy.label" = "Visibility"; "accessibility.editor.privacy.hint" = "Changes post audience."; @@ -559,6 +561,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Additional Info"; diff --git a/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings index f0cc4545..b438594d 100644 --- a/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings @@ -525,6 +525,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Accounts"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -558,6 +560,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Additional Info"; diff --git a/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings index 0d2ff498..69f4b784 100644 --- a/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings @@ -525,6 +525,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Crear"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld publicaciones nuevas"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Cuentas"; "accessibility.app-account.selector.accounts.hint" = "Abrir opciones."; "accessibility.tabs.profile.options.label" = "Opciones"; @@ -558,6 +560,7 @@ "accessibility.status.a-replied-to-%@" = "%@ respondió a"; "accessibility.image.alt-text-%@" = "Texto alt de la imagen: %@"; "accessibility.image.alt-text-more.label" = "Hay más text alt disponible"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Información adicional"; diff --git a/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings index 3570e276..aaf347ca 100644 --- a/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings @@ -513,6 +513,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Sortu"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld bidalketa berri"; "accessibility.tabs.timeline.unread-posts.hint" = "Denbora-lerroa korritzen du."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Kontuak"; "accessibility.app-account.selector.accounts.hint" = "Aukeren orria irekitzen du."; "accessibility.tabs.profile.options.label" = "Aukerak"; @@ -546,6 +548,7 @@ "accessibility.status.a-replied-to-%@" = "%@(e)k honi erantzun dio:"; "accessibility.image.alt-text-%@" = "Irudiaren deskribapena: %@"; "accessibility.image.alt-text-more.label" = "Deskribapen testu gehiago dago"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Informazio gehigarria"; diff --git a/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings index d95c6e1a..fe7b3636 100644 --- a/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings @@ -520,6 +520,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Comptes"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -553,6 +555,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Information supplémentaire"; diff --git a/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings index 7c2840fe..ac716279 100644 --- a/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings @@ -524,6 +524,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Account"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -557,6 +559,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Informazioni aggiuntive"; diff --git a/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings index d7ec4607..84268f0b 100644 --- a/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings @@ -524,6 +524,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "作成"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld 件の新しい投稿"; "accessibility.tabs.timeline.unread-posts.hint" = "タイムラインをスクロールします。"; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "アカウント"; "accessibility.app-account.selector.accounts.hint" = "オプション シートを開きます。"; "accessibility.tabs.profile.options.label" = "オプション"; @@ -557,6 +559,7 @@ "accessibility.status.a-replied-to-%@" = "%@ に返信"; "accessibility.image.alt-text-%@" = "画像の代替テキスト: %@"; "accessibility.image.alt-text-more.label" = "より多くの代替テキストを利用できます"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "追加情報"; diff --git a/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings index f9f6208d..9fe99f25 100644 --- a/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings @@ -526,6 +526,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "계정"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -559,6 +561,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "추가 정보"; diff --git a/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings index 2dd21f97..65a6b3bc 100644 --- a/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings @@ -524,6 +524,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Accounts"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -557,6 +559,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Additional Info"; diff --git a/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings index 9c243bce..ee1eb5d2 100644 --- a/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings @@ -521,6 +521,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Maak aan"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld nieuwe posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrollt de tijdlijn."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Accounts"; "accessibility.app-account.selector.accounts.hint" = "Opent paneel voor opties."; "accessibility.tabs.profile.options.label" = "Opties"; @@ -554,6 +556,7 @@ "accessibility.status.a-replied-to-%@" = "%@ heeft geantwoord op"; "accessibility.image.alt-text-%@" = "Tekst voor afbeedling: %@"; "accessibility.image.alt-text-more.label" = "Meer tekst beschikbaar"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Aanvullende informatie"; diff --git a/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings index 48cc7070..36d6f4a6 100644 --- a/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings @@ -515,6 +515,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Konta"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Opcje"; @@ -548,6 +550,7 @@ "accessibility.status.a-replied-to-%@" = "%@ odpowiedział do"; "accessibility.image.alt-text-%@" = "Tekst alternatywny obrazka: %@"; "accessibility.image.alt-text-more.label" = "Dostępna jest większa ilość tekstu alternatywnego"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Informacja dodatkowa"; diff --git a/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings index ad1e51bb..fcf54307 100644 --- a/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings @@ -524,6 +524,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Contas"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -557,6 +559,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Informação Adicional"; diff --git a/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings index 8511a56a..5a2a4185 100644 --- a/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings @@ -524,6 +524,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Accounts"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -557,6 +559,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Additional Info"; diff --git a/IceCubesApp/Resources/Localization/uk.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/uk.lproj/Localizable.strings index f74757b6..57b9cdfd 100644 --- a/IceCubesApp/Resources/Localization/uk.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/uk.lproj/Localizable.strings @@ -525,6 +525,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "Профілі"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -558,6 +560,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "Додаткова інформація"; diff --git a/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings index 69d01c58..d5222f08 100644 --- a/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings @@ -559,6 +559,7 @@ "accessibility.status.a-replied-to-%@" = "%@ 回复给"; "accessibility.image.alt-text-%@" = "图片描述文本:%@"; "accessibility.image.alt-text-more.label" = "更多描述文本可用"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "附加信息"; diff --git a/IceCubesApp/Resources/Localization/zh-Hant.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/zh-Hant.lproj/Localizable.strings index f69e72b1..ee01449a 100644 --- a/IceCubesApp/Resources/Localization/zh-Hant.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/zh-Hant.lproj/Localizable.strings @@ -524,6 +524,8 @@ "accessibility.tabs.timeline.new-post.inputLabel2" = "Create"; "accessibility.tabs.timeline.unread-posts.label-%lld" = "%lld new posts"; "accessibility.tabs.timeline.unread-posts.hint" = "Scrolls the timeline."; +"accessibility.tabs.timeline.content-link-%@" = "Visit %@"; +"accessibility.tabs.timeline.content-hashtag-%@" = "Hashtag %@"; "accessibility.app-account.selector.accounts" = "帳號"; "accessibility.app-account.selector.accounts.hint" = "Opens options sheet."; "accessibility.tabs.profile.options.label" = "Options"; @@ -557,6 +559,7 @@ "accessibility.status.a-replied-to-%@" = "%@ replied to"; "accessibility.image.alt-text-%@" = "Image alt text: %@"; "accessibility.image.alt-text-more.label" = "More alt text available"; +"accessibility.tabs.messages.unread.label" = "Unread"; // MARK: Report "report.comment.placeholder" = "附加資訊"; diff --git a/Packages/Conversations/Sources/Conversations/List/ConversationsListRow.swift b/Packages/Conversations/Sources/Conversations/List/ConversationsListRow.swift index c69f29ff..909fbe48 100644 --- a/Packages/Conversations/Sources/Conversations/List/ConversationsListRow.swift +++ b/Packages/Conversations/Sources/Conversations/List/ConversationsListRow.swift @@ -15,55 +15,75 @@ struct ConversationsListRow: View { @ObservedObject var viewModel: ConversationsListViewModel var body: some View { - VStack(alignment: .leading) { - HStack(alignment: .top, spacing: 8) { - AvatarView(url: conversation.accounts.first!.avatar) - VStack(alignment: .leading, spacing: 4) { - HStack { - EmojiTextApp(.init(stringValue: conversation.accounts.map { $0.safeDisplayName }.joined(separator: ", ")), - emojis: conversation.accounts.flatMap { $0.emojis }) - .font(.scaledSubheadline) - .foregroundColor(theme.labelColor) - .emojiSize(Font.scaledSubheadlineFont.emojiSize) - .emojiBaselineOffset(Font.scaledSubheadlineFont.emojiBaselineOffset) - .fontWeight(.semibold) - .foregroundColor(theme.labelColor) + Button { + Task { + await viewModel.markAsRead(conversation: conversation) + } + routerPath.navigate(to: .conversationDetail(conversation: conversation)) + } label: { + VStack(alignment: .leading) { + HStack(alignment: .top, spacing: 8) { + AvatarView(url: conversation.accounts.first!.avatar) + .accessibilityHidden(true) + VStack(alignment: .leading, spacing: 4) { + HStack { + EmojiTextApp(.init(stringValue: conversation.accounts.map { $0.safeDisplayName }.joined(separator: ", ")), + emojis: conversation.accounts.flatMap { $0.emojis }) + .font(.scaledSubheadline) + .foregroundColor(theme.labelColor) + .emojiSize(Font.scaledSubheadlineFont.emojiSize) + .emojiBaselineOffset(Font.scaledSubheadlineFont.emojiBaselineOffset) + .fontWeight(.semibold) + .foregroundColor(theme.labelColor) + .multilineTextAlignment(.leading) + Spacer() + if conversation.unread { + Circle() + .foregroundColor(theme.tintColor) + .frame(width: 10, height: 10) + .accessibilityRepresentation { + Text("accessibility.tabs.messages.unread.label") + } + .accessibilitySortPriority(1) + } + if let message = conversation.lastStatus { + Text(message.createdAt.relativeFormatted) + .font(.scaledFootnote) + } + } + EmojiTextApp(conversation.lastStatus?.content ?? HTMLString(stringValue: ""), emojis: conversation.lastStatus?.emojis ?? []) .multilineTextAlignment(.leading) - Spacer() - if conversation.unread { - Circle() - .foregroundColor(theme.tintColor) - .frame(width: 10, height: 10) - } - if let message = conversation.lastStatus { - Text(message.createdAt.relativeFormatted) - .font(.scaledFootnote) - } + .font(.scaledBody) + .foregroundColor(theme.labelColor) + .emojiSize(Font.scaledBodyFont.emojiSize) + .emojiBaselineOffset(Font.scaledBodyFont.emojiBaselineOffset) + .accessibilityLabel(conversation.lastStatus?.content.asRawText ?? "") } - EmojiTextApp(conversation.lastStatus?.content ?? HTMLString(stringValue: ""), emojis: conversation.lastStatus?.emojis ?? []) - .multilineTextAlignment(.leading) - .font(.scaledBody) - .foregroundColor(theme.labelColor) - .emojiSize(Font.scaledBodyFont.emojiSize) - .emojiBaselineOffset(Font.scaledBodyFont.emojiBaselineOffset) + Spacer() } - Spacer() - } - .contentShape(Rectangle()) - .onTapGesture { - Task { - await viewModel.markAsRead(conversation: conversation) + .padding(.top, 4) + if conversation.lastStatus != nil { + actionsView + .padding(.bottom, 4) + .accessibilityHidden(true) } - routerPath.navigate(to: .conversationDetail(conversation: conversation)) } - .padding(.top, 4) - if conversation.lastStatus != nil { - actionsView - .padding(.bottom, 4) + .contextMenu { + contextMenu + .accessibilityHidden(true) + } + .accessibilityElement(children: .combine) + .accessibilityActions { + replyAction + contextMenu + accessibilityActions + } + .accessibilityAction(.magicTap) { + if let lastStatus = conversation.lastStatus { + HapticManager.shared.fireHaptic(of: .notification(.success)) + routerPath.presentedSheet = .replyToStatusEditor(status: lastStatus) + } } - } - .contextMenu { - contextMenu } } @@ -88,12 +108,14 @@ struct ConversationsListRow: View { @ViewBuilder private var contextMenu: some View { - Button { - Task { - await viewModel.markAsRead(conversation: conversation) + if conversation.unread { + Button { + Task { + await viewModel.markAsRead(conversation: conversation) + } + } label: { + Label("conversations.action.mark-read", systemImage: "eye") } - } label: { - Label("conversations.action.mark-read", systemImage: "eye") } if let message = conversation.lastStatus { @@ -152,4 +174,53 @@ struct ConversationsListRow: View { systemImage: conversation.lastStatus?.bookmarked ?? false ? "bookmark.fill" : "bookmark") } } + + // MARK: - Accessibility actions + + @ViewBuilder + var replyAction: some View { + if let lastStatus = conversation.lastStatus { + Button("status.action.reply") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + routerPath.presentedSheet = .replyToStatusEditor(status: lastStatus) + } + } else { + EmptyView() + } + } + + @ViewBuilder + private var accessibilityActions: some View { + if let lastStatus = conversation.lastStatus { + if lastStatus.account.id != currentAccount.account?.id { + Button("@\(lastStatus.account.username)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + routerPath.navigate(to: .accountDetail(id: lastStatus.account.id)) + } + } + // Add in each detected link in the content + ForEach(lastStatus.content.links) { link in + switch link.type { + case .url: + if UIApplication.shared.canOpenURL(link.url) { + Button("accessibility.tabs.timeline.content-link-\(link.title)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + _ = routerPath.handle(url: link.url) + } + } + case .hashtag: + Button("accessibility.tabs.timeline.content-hashtag-\(link.title)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + _ = routerPath.handle(url: link.url) + } + case .mention: + Button("\(link.title)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + _ = routerPath.handle(url: link.url) + } + } + } + } + + } } diff --git a/Packages/Models/Sources/Models/Alias/HTMLString.swift b/Packages/Models/Sources/Models/Alias/HTMLString.swift index 824fde71..d785cbcd 100644 --- a/Packages/Models/Sources/Models/Alias/HTMLString.swift +++ b/Packages/Models/Sources/Models/Alias/HTMLString.swift @@ -11,6 +11,7 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable { public var asMarkdown: String = "" public var asRawText: String = "" public var statusesURLs = [URL]() + public var links = [Link]() public var asSafeMarkdownAttributedString: AttributedString = .init() private var main_regex: NSRegularExpression? @@ -75,6 +76,15 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable { } catch { asSafeMarkdownAttributedString = AttributedString(stringLiteral: htmlValue) } + + links = asSafeMarkdownAttributedString.runs + .compactMap { run in + guard let link = run.link else { + return nil + } + + return Link(link, displayString: String(self.asSafeMarkdownAttributedString[run.range].characters)) + } } public init(stringValue: String, parseMarkdown: Bool = false) { @@ -94,6 +104,15 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable { } else { asSafeMarkdownAttributedString = AttributedString(stringLiteral: htmlValue) } + + links = asSafeMarkdownAttributedString.runs + .compactMap { run in + guard let link = run.link else { + return nil + } + + return Link(link, displayString: String(self.asSafeMarkdownAttributedString[run.range].characters)) + } } public func encode(to encoder: Encoder) throws { @@ -167,4 +186,39 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable { } } catch {} } + + public struct Link: Hashable, Identifiable { + public var id: Int { hashValue } + public let url: AttributeScopes.FoundationAttributes.LinkAttribute.Value + public let displayString: String + public let type: LinkType + public let title: String + + init(_ url: AttributeScopes.FoundationAttributes.LinkAttribute.Value, displayString: String) { + self.url = url + self.displayString = displayString + + switch displayString.first { + case "@": + self.type = .mention + self.title = displayString + case "#": + self.type = .hashtag + self.title = String(displayString.dropFirst()) + default: + self.type = .url + var hostNameUrl = url.host ?? url.absoluteString + if hostNameUrl.hasPrefix("www.") { + hostNameUrl = String(hostNameUrl.dropFirst(4)) + } + self.title = hostNameUrl + } + } + + public enum LinkType { + case url + case mention + case hashtag + } + } } diff --git a/Packages/Notifications/Sources/Notifications/NotificationRowView.swift b/Packages/Notifications/Sources/Notifications/NotificationRowView.swift index 94062af6..1c76a4ed 100644 --- a/Packages/Notifications/Sources/Notifications/NotificationRowView.swift +++ b/Packages/Notifications/Sources/Notifications/NotificationRowView.swift @@ -19,13 +19,17 @@ struct NotificationRowView: View { HStack(alignment: .top, spacing: 8) { if notification.accounts.count == 1 { makeAvatarView(type: notification.type) + .accessibilityHidden(true) } else { makeNotificationIconView(type: notification.type) .frame(width: AvatarView.Size.status.size.width, height: AvatarView.Size.status.size.height) + .accessibilityHidden(true) } VStack(alignment: .leading, spacing: 2) { makeMainLabel(type: notification.type) + // The main label is redundant for mentions + .accessibilityHidden(notification.type == .mention) makeContent(type: notification.type) if notification.type == .follow_request, followRequests.map(\.id).contains(notification.accounts[0].id) @@ -34,6 +38,12 @@ struct NotificationRowView: View { } } } + .accessibilityElement(children: .combine) + .accessibilityActions { + if notification.type == .follow { + accessibilityUserActions + } + } .alignmentGuide(.listRowSeparatorLeading) { _ in -100 } @@ -115,6 +125,7 @@ struct NotificationRowView: View { Text(" ⸱ ") Text(Image(systemName: status.visibility.iconName)) } + .accessibilityHidden(true) .font(.scaledFootnote) .fontWeight(.regular) .foregroundColor(.gray) @@ -130,6 +141,7 @@ struct NotificationRowView: View { routerPath.navigate(to: .accountsList(accounts: notification.accounts)) } } + .accessibilityElement(children: .combine) } @ViewBuilder @@ -161,6 +173,7 @@ struct NotificationRowView: View { if type == .follow { EmojiTextApp(notification.accounts[0].note, emojis: notification.accounts[0].emojis) + .accessibilityLabel(notification.accounts[0].note.asRawText) .lineLimit(3) .font(.scaledCallout) .emojiSize(Font.scaledCalloutFont.emojiSize) @@ -169,6 +182,7 @@ struct NotificationRowView: View { .environment(\.openURL, OpenURLAction { url in routerPath.handle(url: url) }) + .accessibilityAddTraits(.isButton) } } .contentShape(Rectangle()) @@ -181,4 +195,16 @@ struct NotificationRowView: View { } } } + + // MARK: - Accessibility actions + + @ViewBuilder + private var accessibilityUserActions: some View { + ForEach(notification.accounts) { account in + Button("@\(account.username)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + routerPath.navigate(to: .accountDetail(id: account.id)) + } + } + } } diff --git a/Packages/Notifications/Sources/Notifications/NotificationsListView.swift b/Packages/Notifications/Sources/Notifications/NotificationsListView.swift index 94f763a4..235124db 100644 --- a/Packages/Notifications/Sources/Notifications/NotificationsListView.swift +++ b/Packages/Notifications/Sources/Notifications/NotificationsListView.swift @@ -175,5 +175,6 @@ public struct NotificationsListView: View { .listRowSeparator(.hidden) .listRowInsets(.init()) .frame(height: .layoutPadding) + .accessibilityHidden(true) } } diff --git a/Packages/Status/Sources/Status/Detail/StatusDetailView.swift b/Packages/Status/Sources/Status/Detail/StatusDetailView.swift index 7e797f1f..526bdef3 100644 --- a/Packages/Status/Sources/Status/Detail/StatusDetailView.swift +++ b/Packages/Status/Sources/Status/Detail/StatusDetailView.swift @@ -191,5 +191,6 @@ public struct StatusDetailView: View { .listRowSeparator(.hidden) .listRowInsets(.init()) .frame(height: .layoutPadding) + .accessibilityHidden(true) } } diff --git a/Packages/Status/Sources/Status/Embed/StatusEmbededView.swift b/Packages/Status/Sources/Status/Embed/StatusEmbeddedView.swift similarity index 94% rename from Packages/Status/Sources/Status/Embed/StatusEmbededView.swift rename to Packages/Status/Sources/Status/Embed/StatusEmbeddedView.swift index 168a2f16..ba1c8a58 100644 --- a/Packages/Status/Sources/Status/Embed/StatusEmbededView.swift +++ b/Packages/Status/Sources/Status/Embed/StatusEmbeddedView.swift @@ -27,6 +27,7 @@ public struct StatusEmbeddedView: View { client: client, routerPath: routerPath, showActions: false) }) + .accessibilityLabel(status.content.asRawText) .environment(\.isCompact, true) } Spacer() @@ -39,6 +40,7 @@ public struct StatusEmbeddedView: View { .stroke(.gray.opacity(0.35), lineWidth: 1) ) .padding(.top, 8) + .accessibilityElement(children: .combine) } private func makeAccountView(account: Account) -> some View { diff --git a/Packages/Status/Sources/Status/Row/StatusRowView.swift b/Packages/Status/Sources/Status/Row/StatusRowView.swift index e208e951..e4598f55 100644 --- a/Packages/Status/Sources/Status/Row/StatusRowView.swift +++ b/Packages/Status/Sources/Status/Row/StatusRowView.swift @@ -11,6 +11,7 @@ public struct StatusRowView: View { @Environment(\.isInCaptureMode) private var isInCaptureMode: Bool @Environment(\.redactionReasons) private var reasons @Environment(\.isCompact) private var isCompact: Bool + @Environment(\.accessibilityEnabled) private var accessibilityEnabled @EnvironmentObject private var theme: Theme @@ -95,13 +96,13 @@ public struct StatusRowView: View { } .swipeActions(edge: .trailing) { // The actions associated with the swipes are exposed as custom accessibility actions and there is no way to remove them. - if !isCompact, UIAccessibility.isVoiceOverRunning == false { + if !isCompact, accessibilityEnabled == false { StatusRowSwipeView(viewModel: viewModel, mode: .trailing) } } .swipeActions(edge: .leading) { // The actions associated with the swipes are exposed as custom accessibility actions and there is no way to remove them. - if !isCompact, UIAccessibility.isVoiceOverRunning == false { + if !isCompact, accessibilityEnabled == false { StatusRowSwipeView(viewModel: viewModel, mode: .leading) } } @@ -111,18 +112,15 @@ public struct StatusRowView: View { bottom: 12, trailing: .layoutPadding)) .accessibilityElement(children: viewModel.isFocused ? .contain : .combine) - .accessibilityLabel(viewModel.isFocused == false && UIAccessibility.isVoiceOverRunning + .accessibilityLabel(viewModel.isFocused == false && accessibilityEnabled ? CombinedAccessibilityLabel(viewModel: viewModel).finalLabel() : Text("")) - .accessibilityCustomContent( - LocalizedStringKey("accessibility.status.spoiler-full-content"), - viewModel.finalStatus.content.asRawText, - importance: .high - ) .accessibilityAction { viewModel.navigateToDetail() } .accessibilityActions { - accessibilityActions + if viewModel.showActions { + accessibilityActions + } } .background { Color.clear @@ -161,11 +159,15 @@ public struct StatusRowView: View { @ViewBuilder private var accessibilityActions: some View { - // Add the individual mentions as accessibility actions - ForEach(viewModel.status.mentions, id: \.id) { mention in - Button("@\(mention.username)") { - viewModel.routerPath.navigate(to: .accountDetail(id: mention.id)) - } + // Add reply and quote, which are lost when the swipe actions are removed + Button("status.action.reply") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + viewModel.routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.status) + } + + Button("settings.swipeactions.status.action.quote") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + viewModel.routerPath.presentedSheet = .quoteStatusEditor(status: viewModel.status) } Button(viewModel.displaySpoiler ? "status.show-more" : "status.show-less") { @@ -175,8 +177,40 @@ public struct StatusRowView: View { } Button("@\(viewModel.status.account.username)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) viewModel.routerPath.navigate(to: .accountDetail(id: viewModel.status.account.id)) } + + // Add a reference to the post creator + if viewModel.status.account != viewModel.finalStatus.account { + Button("@\(viewModel.finalStatus.account.username)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + viewModel.routerPath.navigate(to: .accountDetail(id: viewModel.finalStatus.account.id)) + } + } + + // Add in each detected link in the content + ForEach(viewModel.finalStatus.content.links) { link in + switch link.type { + case .url: + if UIApplication.shared.canOpenURL(link.url) { + Button("accessibility.tabs.timeline.content-link-\(link.title)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + _ = viewModel.routerPath.handle(url: link.url) + } + } + case .hashtag: + Button("accessibility.tabs.timeline.content-hashtag-\(link.title)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + _ = viewModel.routerPath.handle(url: link.url) + } + case .mention: + Button("\(link.title)") { + HapticManager.shared.fireHaptic(of: .notification(.success)) + _ = viewModel.routerPath.handle(url: link.url) + } + } + } } private func makeFilterView(filter: Filter) -> some View { @@ -234,11 +268,11 @@ private struct CombinedAccessibilityLabel { Text(hasSpoiler ? viewModel.finalStatus.spoilerText.asRawText : viewModel.finalStatus.content.asRawText - ) + Text(", ") + + ) + Text(hasSpoiler ? "status.editor.spoiler" : "" - ) + Text(", ") + + ) + imageAltText() + Text(", ") + Text(viewModel.finalStatus.createdAt.relativeFormatted) + Text(", ") + Text("status.summary.n-replies \(viewModel.finalStatus.repliesCount)") + Text(", ") + diff --git a/Packages/Status/Sources/Status/Row/Subviews/StatusRowContentView.swift b/Packages/Status/Sources/Status/Row/Subviews/StatusRowContentView.swift index 4454c37f..42df66f3 100644 --- a/Packages/Status/Sources/Status/Row/Subviews/StatusRowContentView.swift +++ b/Packages/Status/Sources/Status/Row/Subviews/StatusRowContentView.swift @@ -44,6 +44,7 @@ struct StatusRowContentView: View { Spacer() } } + .accessibilityHidden(viewModel.isFocused == false) .padding(.vertical, 4) } diff --git a/Packages/Timeline/Sources/Timeline/TimelineView.swift b/Packages/Timeline/Sources/Timeline/TimelineView.swift index c4e60b64..07c5908d 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineView.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineView.swift @@ -27,10 +27,12 @@ public struct TimelineView: View { @Binding var timeline: TimelineFilter @Binding var scrollToTopSignal: Int + private let canFilterTimeline: Bool - public init(timeline: Binding, scrollToTopSignal: Binding) { + public init(timeline: Binding, scrollToTopSignal: Binding, canFilterTimeline: Bool) { _timeline = timeline _scrollToTopSignal = scrollToTopSignal + self.canFilterTimeline = canFilterTimeline } public var body: some View { @@ -99,9 +101,14 @@ public struct TimelineView: View { } } .accessibilityRepresentation { - Menu(timeline.localizedTitle()) {} + if canFilterTimeline { + Menu(timeline.localizedTitle()) {} + } else { + Text(timeline.localizedTitle()) + } } .accessibilityAddTraits(.isHeader) + .accessibilityRemoveTraits(.isButton) } } .navigationBarTitleDisplayMode(.inline) @@ -172,6 +179,7 @@ public struct TimelineView: View { .font(.scaledFootnote) .foregroundColor(.gray) } + .accessibilityElement(children: .combine) Spacer() Button { Task {