Merge pull request #2777 from omnivore-app/fix/ios-audio-crash
Handle ios out of bounds issue
This commit is contained in:
@ -1400,7 +1400,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 1.29.0;
|
||||
MARKETING_VERSION = 1.30.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app;
|
||||
@ -1435,7 +1435,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MARKETING_VERSION = 1.29.0;
|
||||
MARKETING_VERSION = 1.30.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -1490,7 +1490,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.29.0;
|
||||
MARKETING_VERSION = 1.30.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app;
|
||||
PRODUCT_NAME = Omnivore;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -1831,7 +1831,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.29.0;
|
||||
MARKETING_VERSION = 1.30.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app;
|
||||
PRODUCT_NAME = Omnivore;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@ -20,7 +20,31 @@ struct FilterByLabelsView: View {
|
||||
viewModel.selectedLabels.contains(where: { $0.id == label.id })
|
||||
}
|
||||
|
||||
var innerBody: some View {
|
||||
func loadLabelsAsync() {
|
||||
Task {
|
||||
await viewModel.loadLabels(
|
||||
dataService: dataService,
|
||||
initiallySelectedLabels: initiallySelected,
|
||||
initiallyNegatedLabels: initiallyNegated
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var navBody: some View {
|
||||
if let errorMessage = viewModel.errorMessage {
|
||||
AnyView(
|
||||
VStack {
|
||||
Text(errorMessage)
|
||||
Button("Retry", action: loadLabelsAsync)
|
||||
})
|
||||
} else if viewModel.labels.isEmpty, viewModel.isLoading {
|
||||
AnyView(ProgressView())
|
||||
} else {
|
||||
AnyView(labelsList)
|
||||
}
|
||||
}
|
||||
|
||||
var labelsList: some View {
|
||||
List {
|
||||
ForEach(viewModel.labels.applySearchFilter(viewModel.labelSearchFilter), id: \.self) { label in
|
||||
Button(
|
||||
@ -48,7 +72,18 @@ struct FilterByLabelsView: View {
|
||||
}
|
||||
}
|
||||
.listStyle(PlainListStyle())
|
||||
.navigationTitle("Filter by Label")
|
||||
}
|
||||
|
||||
var innerBody: some View {
|
||||
navBody
|
||||
.navigationTitle("Filter by Label")
|
||||
.refreshable {
|
||||
await viewModel.loadLabels(
|
||||
dataService: dataService,
|
||||
initiallySelectedLabels: initiallySelected,
|
||||
initiallyNegatedLabels: initiallyNegated
|
||||
)
|
||||
}
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
@ -73,20 +108,16 @@ struct FilterByLabelsView: View {
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
if viewModel.isLoading {
|
||||
EmptyView()
|
||||
} else {
|
||||
#if os(iOS)
|
||||
innerBody
|
||||
.searchable(
|
||||
text: $viewModel.labelSearchFilter,
|
||||
placement: .navigationBarDrawer(displayMode: .always),
|
||||
prompt: "Filter Labels"
|
||||
)
|
||||
#else
|
||||
innerBody
|
||||
#endif
|
||||
}
|
||||
#if os(iOS)
|
||||
innerBody
|
||||
.searchable(
|
||||
text: $viewModel.labelSearchFilter,
|
||||
placement: .navigationBarDrawer(displayMode: .always),
|
||||
prompt: "Filter Labels"
|
||||
)
|
||||
#else
|
||||
innerBody
|
||||
#endif
|
||||
}
|
||||
.task {
|
||||
await viewModel.loadLabels(
|
||||
|
||||
@ -6,6 +6,7 @@ import Views
|
||||
|
||||
@MainActor final class FilterByLabelsViewModel: ObservableObject {
|
||||
@Published var isLoading = false
|
||||
@Published var errorMessage: String? = nil
|
||||
@Published var labels = [LinkedItemLabel]()
|
||||
@Published var selectedLabels = [LinkedItemLabel]()
|
||||
@Published var negatedLabels = [LinkedItemLabel]()
|
||||
@ -26,7 +27,7 @@ import Views
|
||||
initiallyNegatedLabels: [LinkedItemLabel]
|
||||
) async {
|
||||
isLoading = true
|
||||
|
||||
errorMessage = nil
|
||||
await loadLabelsFromStore(dataService: dataService)
|
||||
for label in labels {
|
||||
if initiallySelectedLabels.contains(label) {
|
||||
@ -37,6 +38,11 @@ import Views
|
||||
unselectedLabels.append(label)
|
||||
}
|
||||
}
|
||||
isLoading = false
|
||||
|
||||
if labels.isEmpty {
|
||||
isLoading = true
|
||||
}
|
||||
|
||||
Task.detached(priority: .userInitiated) {
|
||||
if let labelIDs = try? await dataService.labels() {
|
||||
@ -53,11 +59,14 @@ import Views
|
||||
self.unselectedLabels.append(label)
|
||||
}
|
||||
}
|
||||
self.isLoading = false
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.errorMessage = "Error loading labels"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
func loadLabelsFromStore(dataService: DataService) async {
|
||||
|
||||
@ -411,13 +411,15 @@
|
||||
currentItemOffset = max(currentItemOffset, 0)
|
||||
|
||||
let idx = currentAudioIndex // item.speechItem.audioIdx
|
||||
let currentItem = document?.utterances[idx].text ?? ""
|
||||
let currentReadIndex = currentItem.index(currentItem.startIndex, offsetBy: min(currentItemOffset, currentItem.count))
|
||||
let lastItem = String(currentItem[..<currentReadIndex])
|
||||
let lastItemAfter = String(currentItem[currentReadIndex...])
|
||||
if idx < document?.utterances.count ?? 0 {
|
||||
let currentItem = document?.utterances[idx].text ?? ""
|
||||
let currentReadIndex = currentItem.index(currentItem.startIndex, offsetBy: min(currentItemOffset, currentItem.count))
|
||||
let lastItem = String(currentItem[..<currentReadIndex])
|
||||
let lastItemAfter = String(currentItem[currentReadIndex...])
|
||||
|
||||
readText = lastItem
|
||||
unreadText = lastItemAfter
|
||||
readText = lastItem
|
||||
unreadText = lastItemAfter
|
||||
}
|
||||
} else {
|
||||
readText = ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user