iOS 14/macOS Big Sur Support

This commit is contained in:
Arkadiusz Fal
2021-11-28 15:37:55 +01:00
parent 696751e07c
commit 5ef89ac9f4
57 changed files with 1147 additions and 813 deletions

View File

@@ -3,7 +3,8 @@ import Foundation
import SwiftUI
struct PlaybackBar: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.colorScheme) private var colorScheme
@Environment(\.presentationMode) private var presentationMode
@Environment(\.inNavigationView) private var inNavigationView
@EnvironmentObject<PlayerModel> private var player
@@ -64,18 +65,20 @@ struct PlaybackBar: View {
Spacer()
}
}
.alert(player.playerError?.localizedDescription ?? "", isPresented: $player.presentingErrorDetails) {
Button("OK") {}
.alert(isPresented: $player.presentingErrorDetails) {
Alert(
title: Text("Error"),
message: Text(player.playerError?.localizedDescription ?? "")
)
}
.environment(\.colorScheme, .dark)
.frame(minWidth: 0, maxWidth: .infinity)
.padding(4)
.background(.black)
.background(colorScheme == .dark ? Color.black : Color.white)
}
private var closeButton: some View {
Button {
dismiss()
presentationMode.wrappedValue.dismiss()
} label: {
Label(
"Close",
@@ -105,10 +108,18 @@ struct PlaybackBar: View {
return "less than a minute"
}
let timeFinishAt = Date.now.addingTimeInterval(remainingSeconds)
let timeFinishAtString = timeFinishAt.formatted(date: .omitted, time: .shortened)
let timeFinishAt = Date().addingTimeInterval(remainingSeconds)
return "ends at \(timeFinishAtString)"
return "ends at \(formattedTimeFinishAt(timeFinishAt))"
}
private func formattedTimeFinishAt(_ date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .none
dateFormatter.timeStyle = .short
return dateFormatter.string(from: date)
}
private var rateMenu: some View {

View File

@@ -44,16 +44,18 @@ struct PlayerQueueView: View {
}
ForEach(player.queue) { item in
PlayerQueueRow(item: item, fullScreen: $fullScreen)
let row = PlayerQueueRow(item: item, fullScreen: $fullScreen)
.contextMenu {
removeButton(item, history: false)
removeAllButton(history: false)
}
#if os(iOS)
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
row.swipeActions(edge: .trailing, allowsFullSwipe: true) {
removeButton(item, history: false)
}
#endif
} else {
row
}
}
}
}
@@ -63,14 +65,18 @@ struct PlayerQueueView: View {
if !player.history.isEmpty {
Section(header: Text("Played Previously")) {
ForEach(player.history) { item in
PlayerQueueRow(item: item, history: true, fullScreen: $fullScreen)
let row = PlayerQueueRow(item: item, history: true, fullScreen: $fullScreen)
.contextMenu {
removeButton(item, history: true)
removeAllButton(history: true)
}
#if os(iOS)
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
removeButton(item, history: true)
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
row.swipeActions(edge: .trailing, allowsFullSwipe: true) {
removeButton(item, history: true)
}
} else {
row
}
#endif
}
@@ -100,28 +106,44 @@ struct PlayerQueueView: View {
}
private func removeButton(_ item: PlayerQueueItem, history: Bool) -> some View {
Button(role: .destructive) {
if history {
player.removeHistory(item)
} else {
player.remove(item)
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
return Button(role: .destructive) {
removeButtonAction(item, history: history)
} label: {
Label("Remove", systemImage: "trash")
}
} else {
return Button {
removeButtonAction(item, history: history)
} label: {
Label("Remove", systemImage: "trash")
}
} label: {
Label("Remove", systemImage: "trash")
}
}
private func removeButtonAction(_ item: PlayerQueueItem, history: Bool) {
_ = history ? player.removeHistory(item) : player.remove(item)
}
private func removeAllButton(history: Bool) -> some View {
Button(role: .destructive) {
if history {
player.removeHistoryItems()
} else {
player.removeQueueItems()
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
return Button(role: .destructive) {
removeAllButtonAction(history: history)
} label: {
Label("Remove All", systemImage: "trash.fill")
}
} else {
return Button {
removeAllButtonAction(history: history)
} label: {
Label("Remove All", systemImage: "trash.fill")
}
} label: {
Label("Remove All", systemImage: "trash.fill")
}
}
private func removeAllButtonAction(history: Bool) {
_ = history ? player.removeHistoryItems() : player.removeQueueItems()
}
}
struct PlayerQueueView_Previews: PreviewProvider {

View File

@@ -11,14 +11,14 @@ struct VideoDetails: View {
@Binding var fullScreen: Bool
@State private var subscribed = false
@State private var confirmationShown = false
@State private var presentingUnsubscribeAlert = false
@State private var presentingAddToPlaylist = false
@State private var presentingShareSheet = false
@State private var shareURL: URL?
@State private var currentPage = Page.details
@Environment(\.dismiss) private var dismiss
@Environment(\.presentationMode) private var presentationMode
@Environment(\.inNavigationView) private var inNavigationView
@EnvironmentObject<AccountsModel> private var accounts
@@ -82,7 +82,7 @@ struct VideoDetails: View {
if fullScreen {
fullScreen = false
} else {
self.dismiss()
self.presentationMode.wrappedValue.dismiss()
}
}
}
@@ -184,19 +184,26 @@ struct VideoDetails: View {
Section {
if subscribed {
Button("Unsubscribe") {
confirmationShown = true
presentingUnsubscribeAlert = true
}
#if os(iOS)
.backport
.tint(.gray)
#endif
.confirmationDialog("Are you you want to unsubscribe from \(video!.channel.name)?", isPresented: $confirmationShown) {
Button("Unsubscribe") {
subscriptions.unsubscribe(video!.channel.id)
.alert(isPresented: $presentingUnsubscribeAlert) {
Alert(
title: Text(
"Are you you want to unsubscribe from \(video!.channel.name)?"
),
primaryButton: .destructive(Text("Unsubscribe")) {
subscriptions.unsubscribe(video!.channel.id)
withAnimation {
subscribed.toggle()
}
}
withAnimation {
subscribed.toggle()
}
},
secondaryButton: .cancel()
)
}
} else {
Button("Subscribe") {
@@ -206,12 +213,12 @@ struct VideoDetails: View {
subscribed.toggle()
}
}
.backport
.tint(.blue)
}
}
.font(.system(size: 13))
.buttonStyle(.borderless)
.buttonBorderShape(.roundedRectangle)
}
}
}
@@ -241,13 +248,13 @@ struct VideoDetails: View {
Text(published)
}
if let publishedAt = video.publishedAt {
if let date = video.publishedAt {
if video.publishedDate != nil {
Text("")
.foregroundColor(.secondary)
.opacity(0.3)
}
Text(publishedAt.formatted(date: .abbreviated, time: .omitted))
Text(formattedPublishedAt(date))
}
}
.font(.system(size: 12))
@@ -257,6 +264,15 @@ struct VideoDetails: View {
}
}
func formattedPublishedAt(_ date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .none
return dateFormatter.string(from: date)
}
var countsSection: some View {
Group {
if let video = player.currentVideo {
@@ -338,11 +354,17 @@ struct VideoDetails: View {
VStack(alignment: .leading, spacing: 10) {
if let description = video.description {
Text(description)
.textSelection(.enabled)
.frame(maxWidth: .infinity, alignment: .leading)
.font(.caption)
.padding(.bottom, 4)
Group {
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
Text(description)
.textSelection(.enabled)
} else {
Text(description)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.font(.caption)
.padding(.bottom, 4)
} else {
Text("No description")
.foregroundColor(.secondary)

View File

@@ -16,8 +16,10 @@ struct VideoPlayerView: View {
@State private var playerSize: CGSize = .zero
@State private var fullScreen = false
@Environment(\.colorScheme) private var colorScheme
#if os(iOS)
@Environment(\.dismiss) private var dismiss
@Environment(\.presentationMode) private var presentationMode
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(\.verticalSizeClass) private var verticalSizeClass
#endif
@@ -82,11 +84,11 @@ struct VideoPlayerView: View {
fullScreen = true
}
},
down: { dismiss() }
down: { presentationMode.wrappedValue.dismiss() }
)
#endif
.background(.black)
.background(Color.black)
Group {
#if os(iOS)
@@ -98,7 +100,7 @@ struct VideoPlayerView: View {
VideoDetails(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
#endif
}
.background()
.background(colorScheme == .dark ? Color.black : Color.white)
.modifier(VideoDetailsPaddingModifier(geometry: geometry, aspectRatio: player.controller?.aspectRatio, fullScreen: fullScreen))
}
#endif