mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Change in the slider and added +10 -10 controls
This commit is contained in:
parent
bd23b5f210
commit
d88d9acb60
8 changed files with 497 additions and 228 deletions
|
|
@ -361,21 +361,32 @@ struct MusicSliderView: View {
|
|||
let isPlaying: Bool
|
||||
let isLiveStream: Bool
|
||||
var onValueChange: (Double) -> Void
|
||||
var labelLayout: TimeLabelLayout = .stacked
|
||||
var trailingLabel: TrailingLabel = .duration
|
||||
var restingTrackHeight: CGFloat = 5
|
||||
var draggingTrackHeight: CGFloat = 9
|
||||
|
||||
enum TimeLabelLayout {
|
||||
case stacked
|
||||
case inline
|
||||
}
|
||||
|
||||
enum TrailingLabel {
|
||||
case duration
|
||||
case remaining
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
sliderContent
|
||||
.frame(height: 10, alignment: .center)
|
||||
if !isLiveStream {
|
||||
HStack {
|
||||
Text(timeString(from: sliderValue))
|
||||
Spacer()
|
||||
Text(timeString(from: duration))
|
||||
Group {
|
||||
if isLiveStream {
|
||||
liveStreamView
|
||||
} else {
|
||||
switch labelLayout {
|
||||
case .stacked:
|
||||
stackedContent
|
||||
case .inline:
|
||||
inlineContent
|
||||
}
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(timeLabelColor)
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
.onChange(of: currentDate) { newDate in
|
||||
|
|
@ -390,23 +401,73 @@ struct MusicSliderView: View {
|
|||
}
|
||||
}
|
||||
|
||||
private var stackedContent: some View {
|
||||
VStack(spacing: 6) {
|
||||
sliderCore
|
||||
.frame(height: sliderFrameHeight)
|
||||
|
||||
HStack {
|
||||
Text(timeString(from: sliderValue))
|
||||
Spacer()
|
||||
Text(trailingTimeText)
|
||||
}
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(timeLabelColor)
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
|
||||
private var inlineContent: some View {
|
||||
HStack(spacing: 10) {
|
||||
Text(timeString(from: sliderValue))
|
||||
.font(inlineLabelFont)
|
||||
.foregroundColor(timeLabelColor)
|
||||
.frame(width: 42, alignment: .leading)
|
||||
|
||||
sliderCore
|
||||
.frame(height: sliderFrameHeight)
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Text(trailingTimeText)
|
||||
.font(inlineLabelFont)
|
||||
.foregroundColor(timeLabelColor)
|
||||
.frame(width: 48, alignment: .trailing)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var sliderContent: some View {
|
||||
if isLiveStream {
|
||||
private var liveStreamView: some View {
|
||||
switch labelLayout {
|
||||
case .stacked:
|
||||
LiveStreamProgressIndicator(tint: sliderTint)
|
||||
.frame(maxWidth: .infinity)
|
||||
} else {
|
||||
CustomSlider(
|
||||
value: $sliderValue,
|
||||
range: 0 ... duration,
|
||||
color: sliderTint,
|
||||
dragging: $dragging,
|
||||
lastDragged: $lastDragged,
|
||||
onValueChange: onValueChange
|
||||
)
|
||||
.frame(height: sliderFrameHeight)
|
||||
case .inline:
|
||||
HStack(spacing: 10) {
|
||||
Spacer()
|
||||
.frame(width: 42)
|
||||
LiveStreamProgressIndicator(tint: sliderTint)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: sliderFrameHeight)
|
||||
Spacer()
|
||||
.frame(width: 48)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var sliderCore: some View {
|
||||
CustomSlider(
|
||||
value: $sliderValue,
|
||||
range: 0 ... duration,
|
||||
color: sliderTint,
|
||||
dragging: $dragging,
|
||||
lastDragged: $lastDragged,
|
||||
onValueChange: onValueChange,
|
||||
restingTrackHeight: restingTrackHeight,
|
||||
draggingTrackHeight: draggingTrackHeight
|
||||
)
|
||||
}
|
||||
|
||||
private var sliderTint: Color {
|
||||
switch Defaults[.sliderColor] {
|
||||
case .albumArt:
|
||||
|
|
@ -424,6 +485,24 @@ struct MusicSliderView: View {
|
|||
: .gray
|
||||
}
|
||||
|
||||
private var trailingTimeText: String {
|
||||
switch trailingLabel {
|
||||
case .duration:
|
||||
return timeString(from: duration)
|
||||
case .remaining:
|
||||
let remaining = max(duration - sliderValue, 0)
|
||||
return "-" + timeString(from: remaining)
|
||||
}
|
||||
}
|
||||
|
||||
private var inlineLabelFont: Font {
|
||||
.system(size: 11, weight: .medium, design: .monospaced)
|
||||
}
|
||||
|
||||
private var sliderFrameHeight: CGFloat {
|
||||
max(restingTrackHeight, draggingTrackHeight)
|
||||
}
|
||||
|
||||
func timeString(from seconds: Double) -> String {
|
||||
let totalMinutes = Int(seconds) / 60
|
||||
let remainingSeconds = Int(seconds) % 60
|
||||
|
|
@ -448,11 +527,13 @@ struct CustomSlider: View {
|
|||
@Binding var lastDragged: Date
|
||||
var onValueChange: ((Double) -> Void)?
|
||||
var thumbSize: CGFloat = 12
|
||||
var restingTrackHeight: CGFloat = 5
|
||||
var draggingTrackHeight: CGFloat = 9
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
let width = geometry.size.width
|
||||
let height = CGFloat(dragging ? 9 : 5)
|
||||
let trackHeight = CGFloat(dragging ? draggingTrackHeight : restingTrackHeight)
|
||||
let rangeSpan = range.upperBound - range.lowerBound
|
||||
|
||||
let progress = rangeSpan == .zero ? 0 : (value - range.lowerBound) / rangeSpan
|
||||
|
|
@ -462,15 +543,15 @@ struct CustomSlider: View {
|
|||
// Background track
|
||||
Rectangle()
|
||||
.fill(.gray.opacity(0.3))
|
||||
.frame(height: height)
|
||||
.frame(height: trackHeight)
|
||||
|
||||
// Filled track
|
||||
Rectangle()
|
||||
.fill(color)
|
||||
.frame(width: filledTrackWidth, height: height)
|
||||
.frame(width: filledTrackWidth, height: trackHeight)
|
||||
}
|
||||
.cornerRadius(height / 2)
|
||||
.frame(height: 10)
|
||||
.cornerRadius(trackHeight / 2)
|
||||
.frame(height: max(restingTrackHeight, draggingTrackHeight))
|
||||
.contentShape(Rectangle())
|
||||
.highPriorityGesture(
|
||||
DragGesture(minimumDistance: 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue