Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ struct NCAudioViewerContentView: View {
Button {
model.restart()
} label: {
Image(systemName: "backward.end.circle")
Image(systemName: "backward.end.circle.fill")
.font(.system(size: sideButtonSize, weight: .regular))
.foregroundStyle(mutedForegroundStyle)
.foregroundStyle(primaryForegroundStyle)
}
.buttonStyle(.plain)
.disabled(!isSelected || model.duration <= 0)
Expand All @@ -177,16 +177,14 @@ struct NCAudioViewerContentView: View {
VStack {
HStack(spacing: 8) {
audioPlaybackOptionButton(
systemName: "repeat.1",
isActive: playbackOptions.isRepeatEnabled,
systemName: playbackOptions.isRepeatEnabled ? "repeat.1.circle.fill" : "repeat.1",
accessibilityLabel: "_repeat_current_media_"
) {
playbackOptions.toggleRepeat()
}

audioPlaybackOptionButton(
systemName: playbackOptions.isAutoAdvanceEnabled ? "forward.end.fill" : "forward.end",
isActive: playbackOptions.isAutoAdvanceEnabled,
accessibilityLabel: "_play_next_media_automatically_"
) {
playbackOptions.toggleAutoAdvance()
Expand Down Expand Up @@ -270,20 +268,13 @@ struct NCAudioViewerContentView: View {

private func audioPlaybackOptionButton(
systemName: String,
isActive: Bool,
accessibilityLabel: String,
action: @escaping () -> Void
) -> some View {
Button(action: action) {
Image(systemName: systemName)
.font(.system(size: 17, weight: .regular))
.foregroundStyle(isActive ? Color.accentColor : primaryForegroundStyle)
.shadow(
color: .black.opacity(0.35),
radius: 2,
x: 0,
y: 1
)
.foregroundStyle(.primary)
.frame(width: 38, height: 38)
.audioControlGlassBackground(shape: Circle())
}
Expand Down Expand Up @@ -332,22 +323,6 @@ struct NCAudioViewerContentView: View {
}
}

private var mutedForegroundStyle: Color {
switch backgroundStyle {
case .black:
return .white.opacity(0.45)

case .white:
return .black.opacity(0.40)

case .system:
return .secondary.opacity(0.70)

case .custom:
return .white.opacity(0.45)
}
}

private var artworkPlaceholderBackground: Color {
switch backgroundStyle {
case .black:
Expand Down Expand Up @@ -418,24 +393,10 @@ private extension View {
) -> some View {
if #available(iOS 26.0, *) {
self
.glassEffect(.regular, in: shape)
.overlay {
shape
.stroke(.white.opacity(0.58), lineWidth: 1.2)
}
.shadow(
color: .black.opacity(0.18),
radius: 14,
x: 0,
y: 4
)
.glassEffect(.regular.interactive(), in: shape)
} else {
self
.background(.ultraThinMaterial, in: shape)
.overlay {
shape
.stroke(.primary.opacity(0.12), lineWidth: 1)
}
.background(.regularMaterial)
.clipShape(shape)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,9 @@ enum NCVideoAVPlayerPresenter {

navigationController.modalPresentationStyle = .fullScreen
navigationController.navigationBar.prefersLargeTitles = false
navigationController.navigationBar.barStyle = .black
navigationController.navigationBar.tintColor = .white
navigationController.navigationBar.tintColor = .label
navigationController.navigationBar.titleTextAttributes = [
.foregroundColor: UIColor.white
.foregroundColor: UIColor.label
]

if !playbackStartReason.shouldShowControlsOnStart {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,17 +513,16 @@ private struct NCVideoControlsSwiftUIView: View {
}
.padding(.horizontal, 18)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.controlGlassBackground(shape: Capsule())
.controlGlassBackground(shape: Capsule(), isInteractive: false)
.contentShape(Capsule())
}

private var topActions: some View {
HStack(spacing: NCVideoControlsView.topActionsSpacing) {
Button(action: onToggleRepeat) {
topActionIcon(
systemName: "repeat.1",
pointSize: 17,
isActive: state.isRepeatEnabled
systemName: state.isRepeatEnabled ? "repeat.1.circle.fill" : "repeat.1",
pointSize: 17
)
}
.buttonStyle(.plain)
Expand All @@ -532,8 +531,7 @@ private struct NCVideoControlsSwiftUIView: View {
Button(action: onToggleAutoAdvance) {
topActionIcon(
systemName: state.isAutoAdvanceEnabled ? "forward.end.fill" : "forward.end",
pointSize: 17,
isActive: state.isAutoAdvanceEnabled
pointSize: 17
)
}
.buttonStyle(.plain)
Expand All @@ -557,7 +555,6 @@ private struct NCVideoControlsSwiftUIView: View {
width: NCVideoControlsView.topActionsButtonSize,
height: NCVideoControlsView.topActionsButtonSize
)
.videoControlIconShadow()
.controlGlassBackground(shape: Circle())

case .vlcTracks:
Expand Down Expand Up @@ -663,13 +660,11 @@ private struct NCVideoControlsSwiftUIView: View {

private func topActionIcon(
systemName: String,
pointSize: CGFloat,
isActive: Bool = false
pointSize: CGFloat
) -> some View {
Image(systemName: systemName)
.font(.system(size: pointSize, weight: .regular))
.foregroundStyle(isActive ? Color.accentColor : .white)
.videoControlIconShadow()
.foregroundStyle(.primary)
.frame(
width: NCVideoControlsView.topActionsButtonSize,
height: NCVideoControlsView.topActionsButtonSize
Expand All @@ -693,8 +688,7 @@ private struct NCVideoControlsSwiftUIView: View {
} label: {
Image(systemName: systemName)
.font(.system(size: pointSize, weight: .regular))
.foregroundStyle(.white)
.videoControlIconShadow()
.foregroundStyle(.primary)
.frame(width: size, height: size)
.controlGlassBackground(shape: Circle())
}
Expand All @@ -707,8 +701,7 @@ private struct NCVideoControlsSwiftUIView: View {
private func timeLabel(_ text: String) -> some View {
Text(text)
.font(.system(size: 15, weight: .medium, design: .rounded).monospacedDigit())
.foregroundStyle(.gray)
.videoControlIconShadow()
.foregroundStyle(.secondary)
.lineLimit(1)
.minimumScaleFactor(0.85)
}
Expand All @@ -720,8 +713,8 @@ private struct NCVideoAirPlayRoutePickerView: UIViewRepresentable {
func makeUIView(context: Context) -> AVRoutePickerView {
let routePickerView = AVRoutePickerView()
routePickerView.backgroundColor = .clear
routePickerView.tintColor = .white
routePickerView.activeTintColor = .white
routePickerView.tintColor = .label
routePickerView.activeTintColor = .label
routePickerView.prioritizesVideoDevices = true
return routePickerView
}
Expand All @@ -735,46 +728,20 @@ private struct NCVideoAirPlayRoutePickerView: UIViewRepresentable {
private extension View {
@ViewBuilder
func controlGlassBackground<BackgroundShape: Shape>(
shape: BackgroundShape
shape: BackgroundShape,
isInteractive: Bool = true
) -> some View {
if #available(iOS 26.0, *) {
self
.glassEffect(.regular, in: shape)
.overlay {
shape
.stroke(.white.opacity(0.58), lineWidth: 1.2)
}
.overlay {
shape
.stroke(.white.opacity(0.20), lineWidth: 4)
.blur(radius: 2)
.mask(shape)
}
.shadow(
color: .black.opacity(0.18),
radius: 14,
x: 0,
y: 4
)
.glassEffect(.regular.interactive(isInteractive), in: shape)
} else {
self
.background(.white.opacity(0.92))
.background(.regularMaterial)
.clipShape(shape)
}
}
}

private extension View {
func videoControlIconShadow() -> some View {
shadow(
color: .black.opacity(0.5),
radius: 2.5,
x: 0,
y: 1
)
}
}

// MARK: - Preview

#Preview("Video Controls") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,19 @@ struct NCVideoPlaybackCoverView: View {
if isLoading || isLaunchingPlayback {
ProgressView()
.controlSize(.large)
.tint(.white)
.tint(.primary)
.transition(.opacity)
} else {
// Color.primary, not .primary: the default button style resolves .primary against the accent tint.
// The default style stays because .plain fades disabled content, like the loading spinner.
Image(systemName: "play.fill")
.font(.system(size: 36, weight: .regular))
.foregroundStyle(isPlayEnabled ? .white : .black.opacity(0.35))
.videoControlIconShadow()
.foregroundStyle(Color.primary.opacity(isPlayEnabled ? 1 : 0.35))
.transition(.opacity)
}
}
.frame(width: 62, height: 62)
.coverPlayButtonBackground(isEnabled: isPlayEnabled)
.coverPlayButtonBackground()
}
.disabled(!isPlayEnabled || isLoading || isLaunchingPlayback)
.scaleEffect(isLaunchingPlayback ? 1.06 : 1)
Expand Down Expand Up @@ -108,45 +109,18 @@ struct NCVideoPlaybackCoverView: View {

private extension View {
@ViewBuilder
func coverPlayButtonBackground(isEnabled: Bool) -> some View {
func coverPlayButtonBackground() -> some View {
if #available(iOS 26.0, *) {
self
.glassEffect(.regular, in: .circle)
.overlay {
Circle()
.stroke(.white.opacity(0.58), lineWidth: 1.2)
}
.overlay {
Circle()
.stroke(.white.opacity(0.20), lineWidth: 4)
.blur(radius: 2)
.mask(Circle())
}
.shadow(
color: .black.opacity(0.18),
radius: 14,
x: 0,
y: 4
)
.glassEffect(.regular.interactive(), in: .circle)
} else {
self
.background(.white.opacity(isEnabled ? 0.92 : 0.45))
.background(.regularMaterial)
.clipShape(Circle())
}
}
}

private extension View {
func videoControlIconShadow() -> some View {
shadow(
color: .black.opacity(0.5),
radius: 2.5,
x: 0,
y: 1
)
}
}

#Preview("Video Playback Cover") {
NCVideoPlaybackCoverView(
previewURL: NCVideoPlaybackCoverPreviewImage.url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,9 @@ enum NCVideoVLCPresenter {

navigationController.modalPresentationStyle = .fullScreen
navigationController.navigationBar.prefersLargeTitles = false
navigationController.navigationBar.barStyle = .black
navigationController.navigationBar.tintColor = .white
navigationController.navigationBar.tintColor = .label
navigationController.navigationBar.titleTextAttributes = [
.foregroundColor: UIColor.white
.foregroundColor: UIColor.label
]

if !playbackStartReason.shouldShowControlsOnStart {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1083,9 +1083,10 @@ final class NCVideoVLCViewController: UIViewController {
return nil
}

// VLC reports the "Disable" track as index -1.
return NCVideoTrackMenuItem(
index: trackIndex,
title: title,
title: trackIndex == -1 ? NSLocalizedString("_disable_", comment: "") : title,
isSelected: currentIndex == Int(trackIndex)
)
}
Expand Down
Loading