Merge pull request #3274 from omnivore-app/feat/ios-accesibility-issues
Fixes for users with the accessibility buttonShapes feature enabled on iOS
This commit is contained in:
@ -140,8 +140,11 @@ public struct ShareExtensionView: View {
|
||||
Text("Add Labels").font(Font.system(size: 12, weight: .medium)).tint(Color.white)
|
||||
} icon: {
|
||||
Image.label.resizable(resizingMode: .stretch).frame(width: 17, height: 17).tint(Color.white)
|
||||
}.padding(.leading, 10).padding(.trailing, 12)
|
||||
}
|
||||
.foregroundColor(Color.white)
|
||||
.padding(.leading, 10).padding(.trailing, 12)
|
||||
})
|
||||
.buttonStyle(.plain)
|
||||
.frame(height: 28)
|
||||
.background(Color.blue)
|
||||
.cornerRadius(24)
|
||||
@ -243,7 +246,7 @@ public struct ShareExtensionView: View {
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 15, height: 15)
|
||||
}
|
||||
}
|
||||
}.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
var closeButton: some View {
|
||||
@ -262,7 +265,7 @@ public struct ShareExtensionView: View {
|
||||
.font(Font.title.weight(.bold))
|
||||
.frame(width: 12, height: 12)
|
||||
}
|
||||
})
|
||||
}).buttonStyle(.plain)
|
||||
}
|
||||
|
||||
var titleBar: some View {
|
||||
@ -337,12 +340,14 @@ public struct ShareExtensionView: View {
|
||||
viewModel.handleReadNowAction(extensionContext: extensionContext)
|
||||
}, label: {
|
||||
Text("Read Now")
|
||||
.foregroundColor(Color.white)
|
||||
#if os(iOS)
|
||||
.font(Font.system(size: 17, weight: .semibold))
|
||||
.tint(Color.white)
|
||||
.padding(20)
|
||||
#endif
|
||||
})
|
||||
.buttonStyle(.plain)
|
||||
#if os(iOS)
|
||||
.frame(height: 50)
|
||||
.background(Color.blue)
|
||||
|
||||
@ -38,6 +38,6 @@ struct TabBarButton: View {
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(selectedTab == key ? Color.blue : Color.themeTabButtonColor)
|
||||
.frame(maxWidth: .infinity)
|
||||
})
|
||||
}).buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +61,6 @@ struct ToolBarButton: View {
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(ThemeManager.currentTheme.toolbarColor)
|
||||
.frame(maxWidth: .infinity)
|
||||
})
|
||||
}).buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ struct LibraryFeatureCardNavigationLink: View {
|
||||
LibraryFeatureCard(item: item, viewer: dataService.currentViewer)
|
||||
}
|
||||
)
|
||||
.buttonStyle(.plain)
|
||||
.confirmationDialog("", isPresented: $showFeatureActions) {
|
||||
if FeaturedItemFilter(rawValue: viewModel.fetcher.featureFilter) == .pinned {
|
||||
Button("Unpin", action: {
|
||||
|
||||
@ -86,6 +86,7 @@ struct LibraryItemGridCardNavigationLink: View {
|
||||
GridCard(item: LibraryItemData.make(from: item), isContextMenuOpen: $isContextMenuOpen, actionHandler: actionHandler)
|
||||
}
|
||||
)
|
||||
.buttonStyle(.plain)
|
||||
.aspectRatio(1.0, contentMode: .fill)
|
||||
.background(
|
||||
Color.secondarySystemGroupedBackground
|
||||
|
||||
@ -7,6 +7,76 @@ import UserNotifications
|
||||
import Utils
|
||||
import Views
|
||||
|
||||
struct FiltersHeader: View {
|
||||
@ObservedObject var viewModel: HomeFeedViewModel
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { reader in
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
if viewModel.searchTerm.count > 0 {
|
||||
TextChipButton.makeSearchFilterButton(title: viewModel.searchTerm) {
|
||||
viewModel.searchTerm = ""
|
||||
}.frame(maxWidth: reader.size.width * 0.66)
|
||||
} else {
|
||||
if UIDevice.isIPhone {
|
||||
Menu(
|
||||
content: {
|
||||
ForEach(viewModel.filters) { filter in
|
||||
Button(filter.name, action: {
|
||||
viewModel.appliedFilter = filter
|
||||
})
|
||||
}
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: viewModel.appliedFilter?.name ?? "-",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
).buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
Menu(
|
||||
content: {
|
||||
ForEach(LinkedItemSort.allCases, id: \.self) { sort in
|
||||
Button(sort.displayName, action: { viewModel.appliedSort = sort.rawValue })
|
||||
}
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
).buttonStyle(.plain)
|
||||
|
||||
TextChipButton.makeAddLabelButton(color: .systemGray6, onTap: { viewModel.showLabelsSheet = true })
|
||||
ForEach(viewModel.selectedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) {
|
||||
viewModel.selectedLabels.removeAll { $0.id == label.id }
|
||||
}
|
||||
}
|
||||
ForEach(viewModel.negatedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: true) {
|
||||
viewModel.negatedLabels.removeAll { $0.id == label.id }
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top, 0)
|
||||
.padding(.bottom, 10)
|
||||
.padding(.leading, 15)
|
||||
.listRowSpacing(0)
|
||||
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
.frame(maxWidth: .infinity, minHeight: 38)
|
||||
.background(Color.systemBackground)
|
||||
.dynamicTypeSize(.small ... .accessibility1)
|
||||
}
|
||||
}
|
||||
|
||||
struct AnimatingCellHeight: AnimatableModifier {
|
||||
var height: CGFloat = 0
|
||||
|
||||
@ -189,7 +259,6 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
action: { isEditMode = isEditMode == .active ? .inactive : .active },
|
||||
label: {
|
||||
Image.selectMultiple
|
||||
.foregroundColor(Color.appGrayTextContrast)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -211,14 +280,12 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
},
|
||||
label: {
|
||||
Image.addLink
|
||||
.foregroundColor(Color.appGrayTextContrast)
|
||||
}
|
||||
)
|
||||
Button(
|
||||
action: { searchPresented = true },
|
||||
label: {
|
||||
Image.magnifyingGlass
|
||||
.foregroundColor(Color.appGrayTextContrast)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -229,10 +296,12 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
viewModel.bulkAction(dataService: dataService, action: .archive, items: Array(selection))
|
||||
isEditMode = .inactive
|
||||
}, label: { Image(systemName: "archivebox") })
|
||||
.padding(.trailing, 10)
|
||||
Button(action: {
|
||||
viewModel.bulkAction(dataService: dataService, action: .delete, items: Array(selection))
|
||||
isEditMode = .inactive
|
||||
}, label: { Image(systemName: "trash") })
|
||||
.padding(.trailing, 10)
|
||||
Spacer()
|
||||
Text("\(selection.count) selected").font(.footnote)
|
||||
Spacer()
|
||||
@ -350,72 +419,12 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
@ObservedObject var networkMonitor = NetworkMonitor()
|
||||
|
||||
var filtersHeader: some View {
|
||||
GeometryReader { reader in
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
if viewModel.searchTerm.count > 0 {
|
||||
TextChipButton.makeSearchFilterButton(title: viewModel.searchTerm) {
|
||||
viewModel.searchTerm = ""
|
||||
}.frame(maxWidth: reader.size.width * 0.66)
|
||||
} else {
|
||||
if UIDevice.isIPhone {
|
||||
Menu(
|
||||
content: {
|
||||
ForEach(viewModel.filters) { filter in
|
||||
Button(filter.name, action: {
|
||||
viewModel.appliedFilter = filter
|
||||
})
|
||||
}
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: viewModel.appliedFilter?.name ?? "-",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Menu(
|
||||
content: {
|
||||
ForEach(LinkedItemSort.allCases, id: \.self) { sort in
|
||||
Button(sort.displayName, action: { viewModel.appliedSort = sort.rawValue })
|
||||
}
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
TextChipButton.makeAddLabelButton(color: .systemGray6, onTap: { viewModel.showLabelsSheet = true })
|
||||
ForEach(viewModel.selectedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) {
|
||||
viewModel.selectedLabels.removeAll { $0.id == label.id }
|
||||
}
|
||||
}
|
||||
ForEach(viewModel.negatedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: true) {
|
||||
viewModel.negatedLabels.removeAll { $0.id == label.id }
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top, 0)
|
||||
.padding(.bottom, 10)
|
||||
.padding(.leading, 15)
|
||||
.listRowSpacing(0)
|
||||
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
.frame(maxWidth: .infinity, minHeight: 38)
|
||||
.background(Color.systemBackground)
|
||||
.overlay(Rectangle()
|
||||
.padding(.leading, 15)
|
||||
.frame(width: nil, height: 0.5, alignment: .bottom)
|
||||
.foregroundColor(isListScrolled ? Color(hex: "#3D3D3D") : Color.systemBackground), alignment: .bottom)
|
||||
.dynamicTypeSize(.small ... .accessibility1)
|
||||
FiltersHeader(viewModel: viewModel)
|
||||
.overlay(Rectangle()
|
||||
.padding(.leading, 15)
|
||||
.frame(width: nil, height: 0.5, alignment: .bottom)
|
||||
.foregroundColor(isListScrolled ? Color(hex: "#3D3D3D") : Color.systemBackground), alignment: .bottom)
|
||||
.dynamicTypeSize(.small ... .accessibility1)
|
||||
}
|
||||
|
||||
func menuItems(for item: Models.LibraryItem) -> some View {
|
||||
@ -464,7 +473,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
.background(Color(hex: "#007AFF")?.opacity(0.1))
|
||||
.cornerRadius(5)
|
||||
}.frame(maxWidth: .infinity, alignment: .leading)
|
||||
})
|
||||
}).buttonStyle(.plain)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.top, 10)
|
||||
@ -820,59 +829,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
}
|
||||
|
||||
var filtersHeader: some View {
|
||||
GeometryReader { reader in
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
if viewModel.searchTerm.count > 0 {
|
||||
TextChipButton.makeSearchFilterButton(title: viewModel.searchTerm) {
|
||||
viewModel.searchTerm = ""
|
||||
}.frame(maxWidth: reader.size.width * 0.66)
|
||||
} else {
|
||||
Menu(
|
||||
content: {
|
||||
ForEach(viewModel.filters, id: \.self) { filter in
|
||||
Button(filter.name, action: { viewModel.appliedFilter = filter })
|
||||
}
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: viewModel.appliedFilter?.name ?? "-",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
Menu(
|
||||
content: {
|
||||
ForEach(LinkedItemSort.allCases, id: \.self) { sort in
|
||||
Button(sort.displayName, action: { viewModel.appliedSort = sort.rawValue })
|
||||
}
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
TextChipButton.makeAddLabelButton(color: .systemGray6, onTap: { viewModel.showLabelsSheet = true })
|
||||
ForEach(viewModel.selectedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) {
|
||||
viewModel.selectedLabels.removeAll { $0.id == label.id }
|
||||
}
|
||||
}
|
||||
ForEach(viewModel.negatedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: true) {
|
||||
viewModel.negatedLabels.removeAll { $0.id == label.id }
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(0)
|
||||
}
|
||||
.listRowSeparator(.hidden)
|
||||
}
|
||||
.dynamicTypeSize(.small ... .accessibility1)
|
||||
FiltersHeader(viewModel: viewModel)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
||||
@ -94,8 +94,12 @@ struct FiltersView: View {
|
||||
}
|
||||
|
||||
Section(header: Text("Saved Searches")) {
|
||||
ForEach(viewModel.libraryFilters) { filter in
|
||||
Text(filter.name)
|
||||
if viewModel.libraryFilters.count > 0 {
|
||||
ForEach(viewModel.libraryFilters) { filter in
|
||||
Text(filter.name)
|
||||
}
|
||||
} else {
|
||||
Text("No saved searches found")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -76,12 +76,13 @@ struct NewsletterEmailsView: View {
|
||||
OperationToast(operationMessage: $viewModel.operationMessage, showOperationToast: $viewModel.showOperationToast, operationStatus: $viewModel.operationStatus)
|
||||
} label: {
|
||||
EmptyView()
|
||||
}
|
||||
}.buttonStyle(.plain)
|
||||
|
||||
WindowLink(level: .alert, transition: .move(edge: .bottom), isPresented: $viewModel.showAddressCopied) {
|
||||
MessageToast()
|
||||
} label: {
|
||||
EmptyView()
|
||||
}
|
||||
}.buttonStyle(.plain)
|
||||
|
||||
#if os(iOS)
|
||||
Form {
|
||||
|
||||
@ -161,7 +161,8 @@ struct SubscriptionsView: View {
|
||||
OperationToast(operationMessage: $viewModel.operationMessage, showOperationToast: $viewModel.showOperationToast, operationStatus: $viewModel.operationStatus)
|
||||
} label: {
|
||||
EmptyView()
|
||||
}
|
||||
}.buttonStyle(.plain)
|
||||
|
||||
if viewModel.feeds.isEmpty, viewModel.newsletters.isEmpty, viewModel.isLoading {
|
||||
ProgressView()
|
||||
} else if viewModel.hasNetworkError {
|
||||
|
||||
@ -129,29 +129,31 @@ struct WebReaderContainerView: View {
|
||||
return AnyView(ProgressView()
|
||||
.padding(.horizontal))
|
||||
} else {
|
||||
return AnyView(Button(
|
||||
action: {
|
||||
switch audioController.state {
|
||||
case .playing:
|
||||
if audioController.itemAudioProperties?.itemID == self.item.unwrappedID {
|
||||
audioController.pause()
|
||||
return
|
||||
return AnyView(
|
||||
Button(
|
||||
action: {
|
||||
switch audioController.state {
|
||||
case .playing:
|
||||
if audioController.itemAudioProperties?.itemID == self.item.unwrappedID {
|
||||
audioController.pause()
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case .paused:
|
||||
if audioController.itemAudioProperties?.itemID == self.item.unwrappedID {
|
||||
audioController.unpause()
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
audioController.play(itemAudioProperties: item.audioProperties)
|
||||
}
|
||||
fallthrough
|
||||
case .paused:
|
||||
if audioController.itemAudioProperties?.itemID == self.item.unwrappedID {
|
||||
audioController.unpause()
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
audioController.play(itemAudioProperties: item.audioProperties)
|
||||
},
|
||||
label: {
|
||||
textToSpeechButtonImage
|
||||
}
|
||||
},
|
||||
label: {
|
||||
textToSpeechButtonImage
|
||||
}
|
||||
))
|
||||
).buttonStyle(.plain)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,6 +260,8 @@ struct WebReaderContainerView: View {
|
||||
.padding(.vertical)
|
||||
}
|
||||
)
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Spacer()
|
||||
#endif
|
||||
|
||||
@ -267,6 +271,7 @@ struct WebReaderContainerView: View {
|
||||
Image.label
|
||||
}
|
||||
)
|
||||
.buttonStyle(.plain)
|
||||
.padding(.trailing, 4)
|
||||
|
||||
Button(
|
||||
@ -275,6 +280,7 @@ struct WebReaderContainerView: View {
|
||||
Image.notebook
|
||||
}
|
||||
)
|
||||
.buttonStyle(.plain)
|
||||
.padding(.trailing, 4)
|
||||
|
||||
#if os(iOS)
|
||||
@ -292,6 +298,7 @@ struct WebReaderContainerView: View {
|
||||
Image.readerSettings
|
||||
}
|
||||
)
|
||||
.buttonStyle(.plain)
|
||||
.padding(.horizontal, 5)
|
||||
.popover(isPresented: $showPreferencesPopover) {
|
||||
webPreferencesPopoverView
|
||||
@ -318,6 +325,7 @@ struct WebReaderContainerView: View {
|
||||
#endif
|
||||
}
|
||||
)
|
||||
.buttonStyle(.plain)
|
||||
#if os(macOS)
|
||||
.frame(maxWidth: 100)
|
||||
.padding(.trailing, 16)
|
||||
@ -372,7 +380,8 @@ struct WebReaderContainerView: View {
|
||||
OperationToast(operationMessage: $viewModel.operationMessage, showOperationToast: $viewModel.showOperationToast, operationStatus: $viewModel.operationStatus)
|
||||
} label: {
|
||||
EmptyView()
|
||||
}
|
||||
}.buttonStyle(.plain)
|
||||
|
||||
if let articleContent = viewModel.articleContent {
|
||||
WebReader(
|
||||
item: item,
|
||||
|
||||
@ -149,6 +149,7 @@ struct WelcomeView: View {
|
||||
.sheet(isPresented: $showAboutPage) {
|
||||
if let url = URL(string: "https://omnivore.app/about") {
|
||||
SafariView(url: url)
|
||||
.ignoresSafeArea(.all, edges: .bottom)
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
|
||||
Reference in New Issue
Block a user