mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Update toolbar items
This commit is contained in:
parent
53a355f3cb
commit
8c0db16d9a
10 changed files with 208 additions and 60 deletions
|
|
@ -53,7 +53,8 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
}
|
||||
|
||||
var showFeatureCards: Bool {
|
||||
viewModel.listConfig.hasFeatureCards &&
|
||||
isEditMode == .inactive &&
|
||||
viewModel.listConfig.hasFeatureCards &&
|
||||
!viewModel.hideFeatureSection &&
|
||||
viewModel.fetcher.items.count > 0 &&
|
||||
viewModel.searchTerm.isEmpty &&
|
||||
|
|
@ -204,14 +205,6 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
}
|
||||
.frame(maxWidth: .infinity, alignment: .bottomLeading)
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .barTrailing) {
|
||||
if UIDevice.isIPad, viewModel.folder == "inbox" {
|
||||
Button(action: { addLinkPresented = true }, label: {
|
||||
Label("Add Link", systemImage: "plus")
|
||||
})
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: UIDevice.isIPhone ? .barLeading : .barTrailing) {
|
||||
if enableGrid {
|
||||
Button(
|
||||
|
|
@ -226,26 +219,31 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
Button(
|
||||
action: { searchPresented = true },
|
||||
label: {
|
||||
Image(systemName: "magnifyingglass")
|
||||
Image.magnifyingGlass
|
||||
.foregroundColor(Color.appGrayTextContrast)
|
||||
}
|
||||
)
|
||||
}
|
||||
ToolbarItem(placement: .barTrailing) {
|
||||
if UIDevice.isIPhone {
|
||||
Menu(content: {
|
||||
Button(action: {
|
||||
isEditMode = isEditMode == .inactive ? .active : .inactive
|
||||
}, label: {
|
||||
Text(isEditMode == .inactive ? "Select Multiple" : "End Multiselect")
|
||||
})
|
||||
Button(action: { addLinkPresented = true }, label: {
|
||||
Label("Add Link", systemImage: "plus.circle")
|
||||
})
|
||||
}, label: {
|
||||
Image.utilityMenu
|
||||
})
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
Button(
|
||||
action: { isEditMode = isEditMode == .active ? .inactive : .active },
|
||||
label: {
|
||||
Image.selectMultiple
|
||||
.foregroundColor(Color.appGrayTextContrast)
|
||||
}
|
||||
)
|
||||
}
|
||||
ToolbarItem(placement: .barTrailing) {
|
||||
if viewModel.folder == "inbox" {
|
||||
Button(
|
||||
action: { addLinkPresented = true },
|
||||
label: {
|
||||
Image.addLink
|
||||
.foregroundColor(Color.appGrayTextContrast)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
ToolbarItemGroup(placement: .bottomBar) {
|
||||
|
|
@ -594,8 +592,45 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
}
|
||||
}
|
||||
|
||||
var listItems: some View {
|
||||
ForEach(Array(viewModel.fetcher.items.enumerated()), id: \.1.unwrappedID) { _, item in
|
||||
let horizontalInset = CGFloat(UIDevice.isIPad ? 20 : 10)
|
||||
|
||||
FeedCardNavigationLink(
|
||||
item: item,
|
||||
isInMultiSelectMode: viewModel.isInMultiSelectMode,
|
||||
viewModel: viewModel
|
||||
)
|
||||
.background(GeometryReader { geometry in
|
||||
Color.clear
|
||||
.preference(key: ScrollOffsetPreferenceKey.self, value: geometry.frame(in: .named("scroll")).origin)
|
||||
})
|
||||
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in
|
||||
if value.y < 100, value.y > 0 {
|
||||
if item.savedAt != nil, topItem != item {
|
||||
setTopItem(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
.listRowSeparatorTint(Color.thBorderColor)
|
||||
.listRowInsets(.init(top: 0, leading: horizontalInset, bottom: 10, trailing: horizontalInset))
|
||||
.contextMenu {
|
||||
menuItems(for: item)
|
||||
}
|
||||
.swipeActions(edge: .leading, allowsFullSwipe: true) {
|
||||
ForEach(viewModel.listConfig.leadingSwipeActions, id: \.self) { action in
|
||||
swipeActionButton(action: action, item: item)
|
||||
}
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
ForEach(viewModel.listConfig.trailingSwipeActions, id: \.self) { action in
|
||||
swipeActionButton(action: action, item: item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let horizontalInset = CGFloat(UIDevice.isIPad ? 20 : 10)
|
||||
VStack(spacing: 0) {
|
||||
Color.systemBackground.frame(height: 1)
|
||||
ScrollViewReader { reader in
|
||||
|
|
@ -634,38 +669,14 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
}
|
||||
}
|
||||
|
||||
ForEach(Array(viewModel.fetcher.items.enumerated()), id: \.1.unwrappedID) { _, item in
|
||||
FeedCardNavigationLink(
|
||||
item: item,
|
||||
isInMultiSelectMode: viewModel.isInMultiSelectMode,
|
||||
viewModel: viewModel
|
||||
)
|
||||
.background(GeometryReader { geometry in
|
||||
Color.clear
|
||||
.preference(key: ScrollOffsetPreferenceKey.self, value: geometry.frame(in: .named("scroll")).origin)
|
||||
})
|
||||
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in
|
||||
if value.y < 100, value.y > 0 {
|
||||
if item.savedAt != nil, topItem != item {
|
||||
setTopItem(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
.listRowSeparatorTint(Color.thBorderColor)
|
||||
.listRowInsets(.init(top: 0, leading: horizontalInset, bottom: 10, trailing: horizontalInset))
|
||||
.contextMenu {
|
||||
menuItems(for: item)
|
||||
}
|
||||
.swipeActions(edge: .leading, allowsFullSwipe: true) {
|
||||
ForEach(viewModel.listConfig.leadingSwipeActions, id: \.self) { action in
|
||||
swipeActionButton(action: action, item: item)
|
||||
}
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
ForEach(viewModel.listConfig.trailingSwipeActions, id: \.self) { action in
|
||||
swipeActionButton(action: action, item: item)
|
||||
}
|
||||
if viewModel.showLoadingBar {
|
||||
HStack(alignment: .center, spacing: 10) {
|
||||
ProgressView()
|
||||
}
|
||||
.frame(height: 100)
|
||||
.listRowSeparator(.hidden)
|
||||
} else {
|
||||
listItems
|
||||
}
|
||||
}
|
||||
}, header: {
|
||||
|
|
|
|||
|
|
@ -152,10 +152,9 @@ import Views
|
|||
|
||||
func loadItems(dataService: DataService, isRefresh: Bool) async {
|
||||
isLoading = true
|
||||
showLoadingBar = true
|
||||
showLoadingBar = isRefresh
|
||||
|
||||
await fetcher.loadItems(dataService: dataService, filterState: filterState, isRefresh: isRefresh)
|
||||
|
||||
updateFeatureFilter(context: dataService.viewContext, filter: FeaturedItemFilter(rawValue: featureFilter))
|
||||
|
||||
isLoading = false
|
||||
|
|
@ -164,12 +163,10 @@ import Views
|
|||
|
||||
func loadMoreItems(dataService: DataService, filterState: FetcherFilterState, isRefresh: Bool) async {
|
||||
isLoading = true
|
||||
showLoadingBar = true
|
||||
|
||||
await fetcher.loadMoreItems(dataService: dataService, filterState: filterState, isRefresh: isRefresh)
|
||||
|
||||
isLoading = false
|
||||
showLoadingBar = false
|
||||
}
|
||||
|
||||
func loadFeatureItems(context: NSManagedObjectContext, predicate: NSPredicate, sort: NSSortDescriptor) async -> [Models.LibraryItem] {
|
||||
|
|
|
|||
31
apple/OmnivoreKit/Sources/Utils/FirstFewWords.swift
Normal file
31
apple/OmnivoreKit/Sources/Utils/FirstFewWords.swift
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Jackson Harper on 12/8/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import NaturalLanguage
|
||||
|
||||
public func extractFirstFewWords(_ title: String) -> String {
|
||||
let languageRecognizer = NLLanguageRecognizer()
|
||||
|
||||
languageRecognizer.processString(title)
|
||||
let language = languageRecognizer.dominantLanguage ?? NLLanguage.english
|
||||
|
||||
let tokenizer = NLTokenizer(unit: .word)
|
||||
tokenizer.setLanguage(language)
|
||||
tokenizer.string = title
|
||||
|
||||
var words: [String] = []
|
||||
tokenizer.enumerateTokens(in: title.startIndex ..< title.endIndex) { range, _ in
|
||||
let word = String(title[range])
|
||||
words.append(word)
|
||||
return true
|
||||
}
|
||||
|
||||
print("WORDS: ", words)
|
||||
let truncatedTitle = words.prefix(2).joined(separator: " ")
|
||||
return truncatedTitle
|
||||
}
|
||||
|
|
@ -21,6 +21,10 @@ public extension Image {
|
|||
static var readerSettings: Image { Image("reader-settings", bundle: .module) }
|
||||
static var utilityMenu: Image { Image("utility-menu", bundle: .module) }
|
||||
|
||||
static var addLink: Image { Image("add-link", bundle: .module) }
|
||||
static var selectMultiple: Image { Image("select-multiple", bundle: .module) }
|
||||
static var magnifyingGlass: Image { Image("magnifying-glass", bundle: .module) }
|
||||
|
||||
static var archive: Image { Image("archive", bundle: .module) }
|
||||
static var unarchive: Image { Image("unarchive", bundle: .module) }
|
||||
static var remove: Image { Image("remove", bundle: .module) }
|
||||
|
|
|
|||
24
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/add-link.imageset/Contents.json
vendored
Normal file
24
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/add-link.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "add-link.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
11
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/add-link.imageset/add-link.svg
vendored
Normal file
11
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/add-link.imageset/add-link.svg
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<svg width="26" height="25" viewBox="0 0 26 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6802_32635)">
|
||||
<path d="M13.3398 5.20801V19.7913" stroke="#EDEDED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.0481 12.5H20.6314" stroke="#EDEDED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_6802_32635">
|
||||
<rect width="25" height="25" fill="white" transform="translate(0.839844)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 519 B |
24
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/magnifying-glass.imageset/Contents.json
vendored
Normal file
24
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/magnifying-glass.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "magnifying-glass.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<svg width="26" height="25" viewBox="0 0 26 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6802_32619)">
|
||||
<path d="M5.08984 10.6667C5.08984 11.5093 5.25582 12.3437 5.57828 13.1222C5.90075 13.9007 6.3734 14.6081 6.96924 15.2039C7.56508 15.7998 8.27245 16.2724 9.05096 16.5949C9.82946 16.9174 10.6639 17.0833 11.5065 17.0833C12.3492 17.0833 13.1836 16.9174 13.9621 16.5949C14.7406 16.2724 15.4479 15.7998 16.0438 15.2039C16.6396 14.6081 17.1123 13.9007 17.4347 13.1222C17.7572 12.3437 17.9232 11.5093 17.9232 10.6667C17.9232 9.82402 17.7572 8.98962 17.4347 8.21111C17.1123 7.43261 16.6396 6.72524 16.0438 6.1294C15.4479 5.53356 14.7406 5.06091 13.9621 4.73844C13.1836 4.41597 12.3492 4.25 11.5065 4.25C10.6639 4.25 9.82946 4.41597 9.05096 4.73844C8.27245 5.06091 7.56508 5.53356 6.96924 6.1294C6.3734 6.72524 5.90075 7.43261 5.57828 8.21111C5.25582 8.98962 5.08984 9.82402 5.08984 10.6667Z" stroke="#EDEDED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M21.5898 20.75L16.0898 15.25" stroke="#EDEDED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_6802_32619">
|
||||
<rect width="25" height="25" fill="white" transform="translate(0.839844)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
24
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/select-multiple.imageset/Contents.json
vendored
Normal file
24
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/select-multiple.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "multiple-select.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6802_32631)">
|
||||
<path d="M10.3398 12.2402L13.3398 15.2402L21.3398 7.24023" stroke="#EDEDED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M21.3398 13.2402V19.2402C21.3398 19.7707 21.1291 20.2794 20.7541 20.6544C20.379 21.0295 19.8703 21.2402 19.3398 21.2402H7.33984C6.80941 21.2402 6.3007 21.0295 5.92563 20.6544C5.55056 20.2794 5.33984 19.7707 5.33984 19.2402V7.24023C5.33984 6.7098 5.55056 6.20109 5.92563 5.82602C6.3007 5.45095 6.80941 5.24023 7.33984 5.24023H16.3398" stroke="#EDEDED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_6802_32631">
|
||||
<rect width="25" height="25" fill="white" transform="translate(0.839844 0.740234)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 864 B |
Loading…
Reference in a new issue