Merge pull request #479 from PangMo5/PangMo5/chapters-slider
Improve Chapters features of Player
This commit is contained in:
commit
d5c2d62a5c
|
@ -354,6 +354,8 @@ internal enum L10n {
|
||||||
internal static var settings: String { return L10n.tr("Localizable", "settings") }
|
internal static var settings: String { return L10n.tr("Localizable", "settings") }
|
||||||
/// Show Cast & Crew
|
/// Show Cast & Crew
|
||||||
internal static var showCastAndCrew: String { return L10n.tr("Localizable", "showCastAndCrew") }
|
internal static var showCastAndCrew: String { return L10n.tr("Localizable", "showCastAndCrew") }
|
||||||
|
/// Show Chapters Info In Bottom Overlay
|
||||||
|
internal static var showChaptersInfoInBottomOverlay: String { return L10n.tr("Localizable", "showChaptersInfoInBottomOverlay") }
|
||||||
/// Flatten Library Items
|
/// Flatten Library Items
|
||||||
internal static var showFlattenView: String { return L10n.tr("Localizable", "showFlattenView") }
|
internal static var showFlattenView: String { return L10n.tr("Localizable", "showFlattenView") }
|
||||||
/// Show Missing Episodes
|
/// Show Missing Episodes
|
||||||
|
|
|
@ -73,6 +73,10 @@ extension Defaults.Keys {
|
||||||
default: true,
|
default: true,
|
||||||
suite: SwiftfinStore.Defaults.generalSuite)
|
suite: SwiftfinStore.Defaults.generalSuite)
|
||||||
|
|
||||||
|
static let shouldShowChaptersInfoInBottomOverlay = Key<Bool>("shouldShowChaptersInfoInBottomOverlay",
|
||||||
|
default: true,
|
||||||
|
suite: SwiftfinStore.Defaults.generalSuite)
|
||||||
|
|
||||||
// Experimental settings
|
// Experimental settings
|
||||||
enum Experimental {
|
enum Experimental {
|
||||||
static let syncSubtitleStateWithAdjacent = Key<Bool>("experimental.syncSubtitleState",
|
static let syncSubtitleStateWithAdjacent = Key<Bool>("experimental.syncSubtitleState",
|
||||||
|
|
|
@ -131,6 +131,7 @@ final class VideoPlayerViewModel: ViewModel {
|
||||||
let systemControlGesturesEnabled: Bool
|
let systemControlGesturesEnabled: Bool
|
||||||
let seekSlideGestureEnabled: Bool
|
let seekSlideGestureEnabled: Bool
|
||||||
let playerGesturesLockGestureEnabled: Bool
|
let playerGesturesLockGestureEnabled: Bool
|
||||||
|
let shouldShowChaptersInfoInBottomOverlay: Bool
|
||||||
let resumeOffset: Bool
|
let resumeOffset: Bool
|
||||||
let streamType: ServerStreamType
|
let streamType: ServerStreamType
|
||||||
let container: String
|
let container: String
|
||||||
|
@ -263,6 +264,7 @@ final class VideoPlayerViewModel: ViewModel {
|
||||||
self.playerGesturesLockGestureEnabled = Defaults[.playerGesturesLockGestureEnabled]
|
self.playerGesturesLockGestureEnabled = Defaults[.playerGesturesLockGestureEnabled]
|
||||||
self.seekSlideGestureEnabled = Defaults[.seekSlideGestureEnabled]
|
self.seekSlideGestureEnabled = Defaults[.seekSlideGestureEnabled]
|
||||||
self.shouldShowJumpButtonsInOverlayMenu = Defaults[.shouldShowJumpButtonsInOverlayMenu]
|
self.shouldShowJumpButtonsInOverlayMenu = Defaults[.shouldShowJumpButtonsInOverlayMenu]
|
||||||
|
self.shouldShowChaptersInfoInBottomOverlay = Defaults[.shouldShowChaptersInfoInBottomOverlay]
|
||||||
|
|
||||||
self.resumeOffset = Defaults[.resumeOffset]
|
self.resumeOffset = Defaults[.resumeOffset]
|
||||||
|
|
||||||
|
@ -334,6 +336,7 @@ extension VideoPlayerViewModel {
|
||||||
|
|
||||||
TvShowsAPI.getEpisodes(seriesId: seriesID,
|
TvShowsAPI.getEpisodes(seriesId: seriesID,
|
||||||
userId: SessionManager.main.currentLogin.user.id,
|
userId: SessionManager.main.currentLogin.user.id,
|
||||||
|
fields: [.chapters],
|
||||||
adjacentTo: item.id,
|
adjacentTo: item.id,
|
||||||
limit: 3)
|
limit: 3)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
|
|
|
@ -152,6 +152,8 @@
|
||||||
6220D0C926D63F3700B8E046 /* Stinsen in Frameworks */ = {isa = PBXBuildFile; productRef = 6220D0C826D63F3700B8E046 /* Stinsen */; };
|
6220D0C926D63F3700B8E046 /* Stinsen in Frameworks */ = {isa = PBXBuildFile; productRef = 6220D0C826D63F3700B8E046 /* Stinsen */; };
|
||||||
6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6220D0CB26D640C400B8E046 /* AppURLHandler.swift */; };
|
6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6220D0CB26D640C400B8E046 /* AppURLHandler.swift */; };
|
||||||
6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; };
|
6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; };
|
||||||
|
62400C4B287ED19600F6AD3D /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
||||||
|
62400C4C287ED19600F6AD3D /* UDPBroadcast.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; };
|
624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; };
|
||||||
62553429282190A00087FE20 /* PanDirectionGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62553428282190A00087FE20 /* PanDirectionGestureRecognizer.swift */; };
|
62553429282190A00087FE20 /* PanDirectionGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62553428282190A00087FE20 /* PanDirectionGestureRecognizer.swift */; };
|
||||||
625CB56F2678C23300530A6E /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB56E2678C23300530A6E /* HomeView.swift */; };
|
625CB56F2678C23300530A6E /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB56E2678C23300530A6E /* HomeView.swift */; };
|
||||||
|
@ -250,7 +252,6 @@
|
||||||
631759CF2879DB6A00A621AD /* PublicUserSignInCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631759CE2879DB6A00A621AD /* PublicUserSignInCellView.swift */; };
|
631759CF2879DB6A00A621AD /* PublicUserSignInCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631759CE2879DB6A00A621AD /* PublicUserSignInCellView.swift */; };
|
||||||
6334175B287DDFB9000603CE /* QuickConnectSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175A287DDFB9000603CE /* QuickConnectSettingsView.swift */; };
|
6334175B287DDFB9000603CE /* QuickConnectSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175A287DDFB9000603CE /* QuickConnectSettingsView.swift */; };
|
||||||
6334175D287DE0D0000603CE /* QuickConnectSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175C287DE0D0000603CE /* QuickConnectSettingsViewModel.swift */; };
|
6334175D287DE0D0000603CE /* QuickConnectSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6334175C287DE0D0000603CE /* QuickConnectSettingsViewModel.swift */; };
|
||||||
637FCAF4287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
|
||||||
637FCAF5287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
637FCAF5287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
||||||
AE8C3159265D6F90008AA076 /* bitrates.json in Resources */ = {isa = PBXBuildFile; fileRef = AE8C3158265D6F90008AA076 /* bitrates.json */; };
|
AE8C3159265D6F90008AA076 /* bitrates.json in Resources */ = {isa = PBXBuildFile; fileRef = AE8C3158265D6F90008AA076 /* bitrates.json */; };
|
||||||
C400DB6A27FE894F007B65FE /* LiveTVChannelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */; };
|
C400DB6A27FE894F007B65FE /* LiveTVChannelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */; };
|
||||||
|
@ -551,6 +552,7 @@
|
||||||
dstSubfolderSpec = 10;
|
dstSubfolderSpec = 10;
|
||||||
files = (
|
files = (
|
||||||
62666E3D27E503F200EC0ECD /* GoogleCastSDK.xcframework in Embed Frameworks */,
|
62666E3D27E503F200EC0ECD /* GoogleCastSDK.xcframework in Embed Frameworks */,
|
||||||
|
62400C4C287ED19600F6AD3D /* UDPBroadcast.xcframework in Embed Frameworks */,
|
||||||
62666DF827E5012C00EC0ECD /* MobileVLCKit.xcframework in Embed Frameworks */,
|
62666DF827E5012C00EC0ECD /* MobileVLCKit.xcframework in Embed Frameworks */,
|
||||||
);
|
);
|
||||||
name = "Embed Frameworks";
|
name = "Embed Frameworks";
|
||||||
|
@ -974,7 +976,7 @@
|
||||||
62666E0C27E501A500EC0ECD /* OpenGLES.framework in Frameworks */,
|
62666E0C27E501A500EC0ECD /* OpenGLES.framework in Frameworks */,
|
||||||
C409CE9E285044C800CABC12 /* SwiftUICollection in Frameworks */,
|
C409CE9E285044C800CABC12 /* SwiftUICollection in Frameworks */,
|
||||||
62666E0127E5016900EC0ECD /* CoreFoundation.framework in Frameworks */,
|
62666E0127E5016900EC0ECD /* CoreFoundation.framework in Frameworks */,
|
||||||
637FCAF4287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */,
|
62400C4B287ED19600F6AD3D /* UDPBroadcast.xcframework in Frameworks */,
|
||||||
E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */,
|
E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */,
|
||||||
62666E2427E501F300EC0ECD /* Foundation.framework in Frameworks */,
|
62666E2427E501F300EC0ECD /* Foundation.framework in Frameworks */,
|
||||||
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
||||||
|
|
|
@ -21,6 +21,8 @@ struct OverlaySettingsView: View {
|
||||||
var shouldShowAutoPlay
|
var shouldShowAutoPlay
|
||||||
@Default(.shouldShowJumpButtonsInOverlayMenu)
|
@Default(.shouldShowJumpButtonsInOverlayMenu)
|
||||||
var shouldShowJumpButtonsInOverlayMenu
|
var shouldShowJumpButtonsInOverlayMenu
|
||||||
|
@Default(.shouldShowChaptersInfoInBottomOverlay)
|
||||||
|
var shouldShowChaptersInfoInBottomOverlay
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
|
@ -52,6 +54,13 @@ struct OverlaySettingsView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: $shouldShowChaptersInfoInBottomOverlay) {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "photo.on.rectangle")
|
||||||
|
L10n.showChaptersInfoInBottomOverlay.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Toggle(L10n.editJumpLengths, isOn: $shouldShowJumpButtonsInOverlayMenu)
|
Toggle(L10n.editJumpLengths, isOn: $shouldShowJumpButtonsInOverlayMenu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -339,6 +339,21 @@ struct VLCPlayerOverlayView: View {
|
||||||
.frame(height: 70)
|
.frame(height: 70)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
if viewModel.shouldShowChaptersInfoInBottomOverlay,
|
||||||
|
let currentChapter = viewModel.currentChapter
|
||||||
|
{
|
||||||
|
Button {
|
||||||
|
viewModel.playerOverlayDelegate?.didSelectChapters()
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
Text(currentChapter.name ?? "--")
|
||||||
|
Image(systemName: "chevron.right")
|
||||||
|
}
|
||||||
|
.font(.system(size: 16, weight: .semibold, design: .default))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
if viewModel.overlayType == .compact {
|
if viewModel.overlayType == .compact {
|
||||||
HStack {
|
HStack {
|
||||||
|
@ -377,9 +392,29 @@ struct VLCPlayerOverlayView: View {
|
||||||
viewModel.sliderIsScrubbing = editing
|
viewModel.sliderIsScrubbing = editing
|
||||||
})
|
})
|
||||||
.valueSliderStyle(HorizontalValueSliderStyle(track:
|
.valueSliderStyle(HorizontalValueSliderStyle(track:
|
||||||
|
GeometryReader { proxy in
|
||||||
|
ZStack(alignment: .leading) {
|
||||||
HorizontalValueTrack(view:
|
HorizontalValueTrack(view:
|
||||||
Capsule().foregroundColor(.purple))
|
Capsule().foregroundColor(.purple))
|
||||||
.background(Capsule().foregroundColor(Color.gray.opacity(0.25)))
|
.background(Capsule().foregroundColor(Color.gray.opacity(0.75)))
|
||||||
|
|
||||||
|
if viewModel.shouldShowChaptersInfoInBottomOverlay {
|
||||||
|
// Chapters seek masks
|
||||||
|
ForEach(viewModel.chapters, id: \.startPositionTicks) { chapter in
|
||||||
|
let ticksRatio = CGFloat(chapter.startPositionTicks ?? 0) /
|
||||||
|
CGFloat(viewModel.item.runTimeTicks ?? 0)
|
||||||
|
let x = proxy.size.width * ticksRatio
|
||||||
|
if x != 0 {
|
||||||
|
Rectangle()
|
||||||
|
.blendMode(.destinationOut)
|
||||||
|
.offset(x: x - 1.5)
|
||||||
|
.frame(width: 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.compositingGroup()
|
||||||
|
}
|
||||||
.frame(height: 4),
|
.frame(height: 4),
|
||||||
thumb: Circle().foregroundColor(.purple),
|
thumb: Circle().foregroundColor(.purple),
|
||||||
thumbSize: CGSize.Circle(radius: viewModel.sliderIsScrubbing ? 20 : 15),
|
thumbSize: CGSize.Circle(radius: viewModel.sliderIsScrubbing ? 20 : 15),
|
||||||
|
@ -393,6 +428,7 @@ struct VLCPlayerOverlayView: View {
|
||||||
.accessibilityLabel(L10n.remainingTime)
|
.accessibilityLabel(L10n.remainingTime)
|
||||||
.accessibilityValue(viewModel.rightLabelText)
|
.accessibilityValue(viewModel.rightLabelText)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.padding(.horizontal, UIDevice.current.userInterfaceIdiom == .pad ? 30 : 0)
|
.padding(.horizontal, UIDevice.current.userInterfaceIdiom == .pad ? 30 : 0)
|
||||||
.padding(.bottom, UIDevice.current.userInterfaceIdiom == .pad ? 10 : 0)
|
.padding(.bottom, UIDevice.current.userInterfaceIdiom == .pad ? 10 : 0)
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue