7 changed files with 327 additions and 20 deletions
-
8kplayer.xcodeproj/project.pbxproj
-
120kplayer/core/DatabaseManager.swift
-
2kplayer/core/MediaItem.swift
-
26kplayer/detail/EditItemView.swift
-
19kplayer/master/MasterViewController.swift
-
50kplayer/master/SearchItemView.swift
-
98kplayer/util/FlexibleView.swift
@ -0,0 +1,50 @@ |
|||
// |
|||
// Created by Marco Schmickler on 26.01.22. |
|||
// Copyright (c) 2022 Marco Schmickler. All rights reserved. |
|||
// |
|||
|
|||
import Foundation |
|||
import SwiftUI |
|||
|
|||
struct SearchItemView: View { |
|||
@ObservedObject |
|||
var item: MediaItem |
|||
|
|||
var completionHandler: (() -> Void)? |
|||
|
|||
var body: some View { |
|||
VStack { |
|||
FlexibleView( |
|||
data: DatabaseManager.sharedInstance.allTags, |
|||
spacing: 15, |
|||
alignment: .leading |
|||
) { tag in |
|||
Button(action: { |
|||
if item.tags.contains(tag) { |
|||
item.tags.removeAll(where: { toRemove in toRemove == tag }) |
|||
} else { |
|||
item.tags.append(tag) |
|||
} |
|||
item.objectWillChange.send() |
|||
print(tag) |
|||
}, label: { |
|||
Text(verbatim: tag) |
|||
.padding(8) |
|||
.background( |
|||
RoundedRectangle(cornerRadius: 8) |
|||
.fill(item.tags.contains(tag) ? |
|||
Color.yellow.opacity(0.4) : |
|||
Color.gray.opacity(0.2) |
|||
) |
|||
) |
|||
}) |
|||
.buttonStyle(BorderlessButtonStyle()) |
|||
} |
|||
Button(action: { |
|||
self.completionHandler?() |
|||
}, label: { |
|||
Text("ok") |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
// |
|||
// Created by Marco Schmickler on 26.01.22. |
|||
// Copyright (c) 2022 Marco Schmickler. All rights reserved. |
|||
// |
|||
|
|||
import Foundation |
|||
import SwiftUI |
|||
|
|||
struct _FlexibleView<Data: Collection, Content: View>: View where Data.Element: Hashable { |
|||
let availableWidth: CGFloat |
|||
let data: Data |
|||
let spacing: CGFloat |
|||
let alignment: HorizontalAlignment |
|||
let content: (Data.Element) -> Content |
|||
@State var elementsSize: [Data.Element: CGSize] = [:] |
|||
|
|||
var body : some View { |
|||
VStack(alignment: alignment, spacing: spacing) { |
|||
ForEach(computeRows(), id: \.self) { rowElements in |
|||
HStack(spacing: spacing) { |
|||
ForEach(rowElements, id: \.self) { element in |
|||
content(element) |
|||
.fixedSize() |
|||
.readSize { size in |
|||
elementsSize[element] = size |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
func computeRows() -> [[Data.Element]] { |
|||
var rows: [[Data.Element]] = [[]] |
|||
var currentRow = 0 |
|||
var remainingWidth = availableWidth |
|||
|
|||
for element in data { |
|||
let elementSize = elementsSize[element, default: CGSize(width: availableWidth, height: 1)] |
|||
|
|||
if remainingWidth - (elementSize.width + spacing) >= 0 { |
|||
rows[currentRow].append(element) |
|||
} else { |
|||
currentRow = currentRow + 1 |
|||
rows.append([element]) |
|||
remainingWidth = availableWidth |
|||
} |
|||
|
|||
remainingWidth = remainingWidth - (elementSize.width + spacing) |
|||
} |
|||
|
|||
return rows |
|||
} |
|||
} |
|||
|
|||
struct FlexibleView<Data: Collection, Content: View>: View where Data.Element: Hashable { |
|||
let data: Data |
|||
let spacing: CGFloat |
|||
let alignment: HorizontalAlignment |
|||
let content: (Data.Element) -> Content |
|||
@State private var availableWidth: CGFloat = 0 |
|||
|
|||
var body: some View { |
|||
ZStack(alignment: Alignment(horizontal: alignment, vertical: .center)) { |
|||
Color.clear |
|||
.frame(height: 1) |
|||
.readSize { size in |
|||
availableWidth = size.width |
|||
} |
|||
|
|||
_FlexibleView( |
|||
availableWidth: availableWidth, |
|||
data: data, |
|||
spacing: spacing, |
|||
alignment: alignment, |
|||
content: content |
|||
) |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
extension View { |
|||
func readSize(onChange: @escaping (CGSize) -> Void) -> some View { |
|||
background( |
|||
GeometryReader { geometryProxy in |
|||
Color.clear |
|||
.preference(key: SizePreferenceKey.self, value: geometryProxy.size) |
|||
} |
|||
) |
|||
.onPreferenceChange(SizePreferenceKey.self, perform: onChange) |
|||
} |
|||
} |
|||
|
|||
private struct SizePreferenceKey: PreferenceKey { |
|||
static var defaultValue: CGSize = .zero |
|||
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue