mirror of
https://github.com/yattee/yattee.git
synced 2024-11-09 15:58:20 +00:00
Share button
This commit is contained in:
parent
b50d915d8e
commit
544dc70c5d
@ -74,6 +74,15 @@ struct Instance: Defaults.Serializable, Hashable, Identifiable {
|
|||||||
Account(instanceID: id, name: "Anonymous", url: url, anonymous: true)
|
Account(instanceID: id, name: "Anonymous", url: url, anonymous: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var urlComponents: URLComponents {
|
||||||
|
URLComponents(string: url)!
|
||||||
|
}
|
||||||
|
|
||||||
|
var frontendHost: String {
|
||||||
|
// TODO: piped frontend link
|
||||||
|
urlComponents.host!.replacingOccurrences(of: "api", with: "")
|
||||||
|
}
|
||||||
|
|
||||||
func hash(into hasher: inout Hasher) {
|
func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(url)
|
hasher.combine(url)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import Siesta
|
import Siesta
|
||||||
|
|
||||||
protocol VideosAPI {
|
protocol VideosAPI {
|
||||||
|
var account: Account! { get }
|
||||||
var signedIn: Bool { get }
|
var signedIn: Bool { get }
|
||||||
|
|
||||||
func channel(_ id: String) -> Resource
|
func channel(_ id: String) -> Resource
|
||||||
@ -25,6 +26,7 @@ protocol VideosAPI {
|
|||||||
func channelPlaylist(_ id: String) -> Resource?
|
func channelPlaylist(_ id: String) -> Resource?
|
||||||
|
|
||||||
func loadDetails(_ item: PlayerQueueItem, completionHandler: @escaping (PlayerQueueItem) -> Void)
|
func loadDetails(_ item: PlayerQueueItem, completionHandler: @escaping (PlayerQueueItem) -> Void)
|
||||||
|
func shareURL(_ item: ContentItem) -> URL
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VideosAPI {
|
extension VideosAPI {
|
||||||
@ -45,4 +47,21 @@ extension VideosAPI {
|
|||||||
completionHandler(newItem)
|
completionHandler(newItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shareURL(_ item: ContentItem) -> URL {
|
||||||
|
var urlComponents = account.instance.urlComponents
|
||||||
|
urlComponents.host = account.instance.frontendHost
|
||||||
|
switch item.contentType {
|
||||||
|
case .video:
|
||||||
|
urlComponents.path = "/watch"
|
||||||
|
urlComponents.query = "v=\(item.video.videoID)"
|
||||||
|
case .channel:
|
||||||
|
urlComponents.path = "/channel/\(item.channel.id)"
|
||||||
|
case .playlist:
|
||||||
|
urlComponents.path = "/playlist"
|
||||||
|
urlComponents.query = "list=\(item.playlist.id)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlComponents.url!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ extension PlayerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult func remove(_ item: PlayerQueueItem) -> PlayerQueueItem? {
|
@discardableResult func remove(_ item: PlayerQueueItem) -> PlayerQueueItem? {
|
||||||
if let index = queue.firstIndex(where: { $0 == item }) {
|
if let index = queue.firstIndex(where: { $0.videoID == item.videoID }) {
|
||||||
return queue.remove(at: index)
|
return queue.remove(at: index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ extension PlayerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addItemToHistory(_ item: PlayerQueueItem) {
|
func addItemToHistory(_ item: PlayerQueueItem) {
|
||||||
if let index = history.firstIndex(where: { $0.video.videoID == item.video?.videoID }) {
|
if let index = history.firstIndex(where: { $0.video?.videoID == item.video?.videoID }) {
|
||||||
history.remove(at: index)
|
history.remove(at: index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +191,9 @@
|
|||||||
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AAF27F26737550007FC770 /* SearchView.swift */; };
|
||||||
377FC7ED267A0A0800A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7EC267A0A0800A6BBAF /* SwiftyJSON */; };
|
377FC7ED267A0A0800A6BBAF /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7EC267A0A0800A6BBAF /* SwiftyJSON */; };
|
||||||
377FC7F3267A0A0800A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7F2267A0A0800A6BBAF /* Logging */; };
|
377FC7F3267A0A0800A6BBAF /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 377FC7F2267A0A0800A6BBAF /* Logging */; };
|
||||||
|
3784B23B272894DA00B09468 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23A272894DA00B09468 /* ShareSheet.swift */; };
|
||||||
|
3784B23D2728B85300B09468 /* ShareButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23C2728B85300B09468 /* ShareButton.swift */; };
|
||||||
|
3784B23E2728B85300B09468 /* ShareButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3784B23C2728B85300B09468 /* ShareButton.swift */; };
|
||||||
3788AC2726F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
|
3788AC2726F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
|
||||||
3788AC2826F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
|
3788AC2826F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
|
||||||
3788AC2926F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
|
3788AC2926F6840700F6BAA9 /* WatchNowSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */; };
|
||||||
@ -540,6 +543,8 @@
|
|||||||
37732FEF2703A26300F04329 /* AccountValidationStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidationStatus.swift; sourceTree = "<group>"; };
|
37732FEF2703A26300F04329 /* AccountValidationStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidationStatus.swift; sourceTree = "<group>"; };
|
||||||
37732FF32703D32400F04329 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = "<group>"; };
|
37732FF32703D32400F04329 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = "<group>"; };
|
||||||
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = "<group>"; };
|
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = "<group>"; };
|
||||||
|
3784B23A272894DA00B09468 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
|
||||||
|
3784B23C2728B85300B09468 /* ShareButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareButton.swift; sourceTree = "<group>"; };
|
||||||
3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowSection.swift; sourceTree = "<group>"; };
|
3788AC2626F6840700F6BAA9 /* WatchNowSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowSection.swift; sourceTree = "<group>"; };
|
||||||
3788AC2A26F6842D00F6BAA9 /* WatchNowSectionBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowSectionBody.swift; sourceTree = "<group>"; };
|
3788AC2A26F6842D00F6BAA9 /* WatchNowSectionBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNowSectionBody.swift; sourceTree = "<group>"; };
|
||||||
378E50FA26FE8B9F00F49626 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = "<group>"; };
|
378E50FA26FE8B9F00F49626 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = "<group>"; };
|
||||||
@ -805,6 +810,7 @@
|
|||||||
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */,
|
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */,
|
||||||
37AAF27D26737323007FC770 /* PopularView.swift */,
|
37AAF27D26737323007FC770 /* PopularView.swift */,
|
||||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||||
|
3784B23C2728B85300B09468 /* ShareButton.swift */,
|
||||||
376B2E0626F920D600B1D64D /* SignInRequiredView.swift */,
|
376B2E0626F920D600B1D64D /* SignInRequiredView.swift */,
|
||||||
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
||||||
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
|
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
|
||||||
@ -917,6 +923,7 @@
|
|||||||
37992DC826CC50CD003D4C27 /* iOS */ = {
|
37992DC826CC50CD003D4C27 /* iOS */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
3784B23A272894DA00B09468 /* ShareSheet.swift */,
|
||||||
37992DC726CC50BC003D4C27 /* Info.plist */,
|
37992DC726CC50BC003D4C27 /* Info.plist */,
|
||||||
);
|
);
|
||||||
path = iOS;
|
path = iOS;
|
||||||
@ -1173,10 +1180,10 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 37D4B0EC2671614900C925CA /* Build configuration list for PBXNativeTarget "Pearvidious (iOS)" */;
|
buildConfigurationList = 37D4B0EC2671614900C925CA /* Build configuration list for PBXNativeTarget "Pearvidious (iOS)" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
37CC3F48270CE89B00608308 /* ShellScript */,
|
||||||
37D4B0C52671614900C925CA /* Sources */,
|
37D4B0C52671614900C925CA /* Sources */,
|
||||||
37D4B0C62671614900C925CA /* Frameworks */,
|
37D4B0C62671614900C925CA /* Frameworks */,
|
||||||
37D4B0C72671614900C925CA /* Resources */,
|
37D4B0C72671614900C925CA /* Resources */,
|
||||||
37CC3F48270CE89B00608308 /* ShellScript */,
|
|
||||||
37A3B1932725735F000FB5EE /* Embed App Extensions */,
|
37A3B1932725735F000FB5EE /* Embed App Extensions */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
@ -1205,10 +1212,10 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 37D4B0EF2671614900C925CA /* Build configuration list for PBXNativeTarget "Pearvidious (macOS)" */;
|
buildConfigurationList = 37D4B0EF2671614900C925CA /* Build configuration list for PBXNativeTarget "Pearvidious (macOS)" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
37CC3F4A270CE8D000608308 /* ShellScript */,
|
||||||
37D4B0CB2671614900C925CA /* Sources */,
|
37D4B0CB2671614900C925CA /* Sources */,
|
||||||
37D4B0CC2671614900C925CA /* Frameworks */,
|
37D4B0CC2671614900C925CA /* Frameworks */,
|
||||||
37D4B0CD2671614900C925CA /* Resources */,
|
37D4B0CD2671614900C925CA /* Resources */,
|
||||||
37CC3F4A270CE8D000608308 /* ShellScript */,
|
|
||||||
37A3B17127255E7F000FB5EE /* Embed App Extensions */,
|
37A3B17127255E7F000FB5EE /* Embed App Extensions */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
@ -1272,10 +1279,10 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 37D4B177267164B000C925CA /* Build configuration list for PBXNativeTarget "Pearvidious (tvOS)" */;
|
buildConfigurationList = 37D4B177267164B000C925CA /* Build configuration list for PBXNativeTarget "Pearvidious (tvOS)" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
37CC3F49270CE8CA00608308 /* ShellScript */,
|
||||||
37D4B154267164AE00C925CA /* Sources */,
|
37D4B154267164AE00C925CA /* Sources */,
|
||||||
37D4B155267164AE00C925CA /* Frameworks */,
|
37D4B155267164AE00C925CA /* Frameworks */,
|
||||||
37D4B156267164AE00C925CA /* Resources */,
|
37D4B156267164AE00C925CA /* Resources */,
|
||||||
37CC3F49270CE8CA00608308 /* ShellScript */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -1498,7 +1505,7 @@
|
|||||||
};
|
};
|
||||||
37CC3F48270CE89B00608308 /* ShellScript */ = {
|
37CC3F48270CE89B00608308 /* ShellScript */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 12;
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
@ -1511,7 +1518,7 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
shellScript = "if test -d \"/opt/homebrew/bin/\"; then\n PATH=\"/opt/homebrew/bin/:${PATH}\"\nfi\n\nexport PATH\n\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
};
|
};
|
||||||
37CC3F49270CE8CA00608308 /* ShellScript */ = {
|
37CC3F49270CE8CA00608308 /* ShellScript */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
@ -1528,7 +1535,7 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
shellScript = "if test -d \"/opt/homebrew/bin/\"; then\n PATH=\"/opt/homebrew/bin/:${PATH}\"\nfi\n\nexport PATH\n\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
};
|
};
|
||||||
37CC3F4A270CE8D000608308 /* ShellScript */ = {
|
37CC3F4A270CE8D000608308 /* ShellScript */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
@ -1545,7 +1552,7 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
shellScript = "if test -d \"/opt/homebrew/bin/\"; then\n PATH=\"/opt/homebrew/bin/:${PATH}\"\nfi\n\nexport PATH\n\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
};
|
};
|
||||||
37FD43EA2704A2350073EE42 /* ShellScript */ = {
|
37FD43EA2704A2350073EE42 /* ShellScript */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
@ -1608,6 +1615,7 @@
|
|||||||
37CC3F45270CE30600608308 /* PlayerQueueItem.swift in Sources */,
|
37CC3F45270CE30600608308 /* PlayerQueueItem.swift in Sources */,
|
||||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
||||||
37CB12792724C76D00213B45 /* VideoURLParser.swift in Sources */,
|
37CB12792724C76D00213B45 /* VideoURLParser.swift in Sources */,
|
||||||
|
3784B23D2728B85300B09468 /* ShareButton.swift in Sources */,
|
||||||
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
3743CA52270F284F00E4D32B /* View+Borders.swift in Sources */,
|
3743CA52270F284F00E4D32B /* View+Borders.swift in Sources */,
|
||||||
3763495126DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */,
|
3763495126DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */,
|
||||||
@ -1677,6 +1685,7 @@
|
|||||||
3743CA4E270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */,
|
3743CA4E270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */,
|
||||||
37BD672426F13D65004BE0C1 /* AppSidebarPlaylists.swift in Sources */,
|
37BD672426F13D65004BE0C1 /* AppSidebarPlaylists.swift in Sources */,
|
||||||
37B17DA2268A1F8A006AEE9B /* VideoContextMenuView.swift in Sources */,
|
37B17DA2268A1F8A006AEE9B /* VideoContextMenuView.swift in Sources */,
|
||||||
|
3784B23B272894DA00B09468 /* ShareSheet.swift in Sources */,
|
||||||
379775932689365600DD52A8 /* Array+Next.swift in Sources */,
|
379775932689365600DD52A8 /* Array+Next.swift in Sources */,
|
||||||
37B81AFC26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
|
37B81AFC26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
|
||||||
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
||||||
@ -1799,6 +1808,7 @@
|
|||||||
37732FF52703D32400F04329 /* Sidebar.swift in Sources */,
|
37732FF52703D32400F04329 /* Sidebar.swift in Sources */,
|
||||||
379775942689365600DD52A8 /* Array+Next.swift in Sources */,
|
379775942689365600DD52A8 /* Array+Next.swift in Sources */,
|
||||||
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
|
3784B23E2728B85300B09468 /* ShareButton.swift in Sources */,
|
||||||
37BE0BDA26A214630092E2DB /* PlayerViewController.swift in Sources */,
|
37BE0BDA26A214630092E2DB /* PlayerViewController.swift in Sources */,
|
||||||
37E64DD226D597EB00C71877 /* SubscriptionsModel.swift in Sources */,
|
37E64DD226D597EB00C71877 /* SubscriptionsModel.swift in Sources */,
|
||||||
37C7A1D6267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
37C7A1D6267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
|
||||||
|
@ -15,6 +15,7 @@ struct PearvidiousApp: App {
|
|||||||
.handlesExternalEvents(matching: Set(["*"]))
|
.handlesExternalEvents(matching: Set(["*"]))
|
||||||
.commands {
|
.commands {
|
||||||
SidebarCommands()
|
SidebarCommands()
|
||||||
|
CommandGroup(replacing: .newItem, addition: {})
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ struct VideoDetails: View {
|
|||||||
@State private var subscribed = false
|
@State private var subscribed = false
|
||||||
@State private var confirmationShown = false
|
@State private var confirmationShown = false
|
||||||
@State private var presentingAddToPlaylist = false
|
@State private var presentingAddToPlaylist = false
|
||||||
|
@State private var presentingShareSheet = false
|
||||||
|
|
||||||
@State private var currentPage = Page.details
|
@State private var currentPage = Page.details
|
||||||
|
|
||||||
@ -249,6 +250,11 @@ struct VideoDetails: View {
|
|||||||
Group {
|
Group {
|
||||||
if let video = player.currentVideo {
|
if let video = player.currentVideo {
|
||||||
HStack {
|
HStack {
|
||||||
|
ShareButton(
|
||||||
|
contentItem: ContentItem(video: video),
|
||||||
|
presentingShareSheet: $presentingShareSheet
|
||||||
|
)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if let views = video.viewsCount {
|
if let views = video.viewsCount {
|
||||||
@ -269,14 +275,17 @@ struct VideoDetails: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button {
|
if accounts.app.supportsUserPlaylists {
|
||||||
presentingAddToPlaylist = true
|
Button {
|
||||||
} label: {
|
presentingAddToPlaylist = true
|
||||||
Label("Add to Playlist", systemImage: "text.badge.plus")
|
} label: {
|
||||||
.labelStyle(.iconOnly)
|
Label("Add to Playlist", systemImage: "text.badge.plus")
|
||||||
.help("Add to Playlist...")
|
.labelStyle(.iconOnly)
|
||||||
|
.help("Add to Playlist...")
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.foregroundColor(.blue)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
}
|
||||||
.frame(maxHeight: 35)
|
.frame(maxHeight: 35)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
@ -287,6 +296,17 @@ struct VideoDetails: View {
|
|||||||
AddToPlaylistView(video: video)
|
AddToPlaylistView(video: video)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if os(iOS)
|
||||||
|
.sheet(isPresented: $presentingShareSheet) {
|
||||||
|
ShareSheet(activityItems: [
|
||||||
|
accounts.api.shareURL(contentItem)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private var contentItem: ContentItem {
|
||||||
|
ContentItem(video: player.currentVideo!)
|
||||||
}
|
}
|
||||||
|
|
||||||
var detailsPage: some View {
|
var detailsPage: some View {
|
||||||
|
@ -4,6 +4,8 @@ import SwiftUI
|
|||||||
struct ChannelPlaylistView: View {
|
struct ChannelPlaylistView: View {
|
||||||
var playlist: ChannelPlaylist
|
var playlist: ChannelPlaylist
|
||||||
|
|
||||||
|
@State private var presentingShareSheet = false
|
||||||
|
|
||||||
@StateObject private var store = Store<ChannelPlaylist>()
|
@StateObject private var store = Store<ChannelPlaylist>()
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
@ -44,12 +46,26 @@ struct ChannelPlaylistView: View {
|
|||||||
#endif
|
#endif
|
||||||
VerticalCells(items: items)
|
VerticalCells(items: items)
|
||||||
}
|
}
|
||||||
|
#if os(iOS)
|
||||||
|
.sheet(isPresented: $presentingShareSheet) {
|
||||||
|
ShareSheet(activityItems: [
|
||||||
|
accounts.api.shareURL(contentItem)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
#endif
|
||||||
.onAppear {
|
.onAppear {
|
||||||
resource?.addObserver(store)
|
resource?.addObserver(store)
|
||||||
resource?.loadIfNeeded()
|
resource?.loadIfNeeded()
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
ToolbarItem(placement: shareButtonPlacement) {
|
||||||
|
ShareButton(
|
||||||
|
contentItem: contentItem,
|
||||||
|
presentingShareSheet: $presentingShareSheet
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ToolbarItem(placement: .cancellationAction) {
|
ToolbarItem(placement: .cancellationAction) {
|
||||||
if inNavigationView {
|
if inNavigationView {
|
||||||
Button("Done") {
|
Button("Done") {
|
||||||
@ -64,6 +80,18 @@ struct ChannelPlaylistView: View {
|
|||||||
.background(.thickMaterial)
|
.background(.thickMaterial)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var shareButtonPlacement: ToolbarItemPlacement {
|
||||||
|
#if os(iOS)
|
||||||
|
.navigation
|
||||||
|
#else
|
||||||
|
.automatic
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private var contentItem: ContentItem {
|
||||||
|
ContentItem(playlist: playlist)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChannelPlaylistView_Previews: PreviewProvider {
|
struct ChannelPlaylistView_Previews: PreviewProvider {
|
||||||
|
@ -4,6 +4,8 @@ import SwiftUI
|
|||||||
struct ChannelVideosView: View {
|
struct ChannelVideosView: View {
|
||||||
let channel: Channel
|
let channel: Channel
|
||||||
|
|
||||||
|
@State private var presentingShareSheet = false
|
||||||
|
|
||||||
@StateObject private var store = Store<Channel>()
|
@StateObject private var store = Store<Channel>()
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
@ -70,6 +72,13 @@ struct ChannelVideosView: View {
|
|||||||
#endif
|
#endif
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
ToolbarItem(placement: shareButtonPlacement) {
|
||||||
|
ShareButton(
|
||||||
|
contentItem: contentItem,
|
||||||
|
presentingShareSheet: $presentingShareSheet
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ToolbarItem {
|
ToolbarItem {
|
||||||
HStack {
|
HStack {
|
||||||
Text("**\(store.item?.subscriptionsString ?? "loading")** subscribers")
|
Text("**\(store.item?.subscriptionsString ?? "loading")** subscribers")
|
||||||
@ -91,6 +100,13 @@ struct ChannelVideosView: View {
|
|||||||
#else
|
#else
|
||||||
.background(.thickMaterial)
|
.background(.thickMaterial)
|
||||||
#endif
|
#endif
|
||||||
|
#if os(iOS)
|
||||||
|
.sheet(isPresented: $presentingShareSheet) {
|
||||||
|
ShareSheet(activityItems: [
|
||||||
|
accounts.api.shareURL(contentItem)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
#endif
|
||||||
.modifier(UnsubscribeAlertModifier())
|
.modifier(UnsubscribeAlertModifier())
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if store.item.isNil {
|
if store.item.isNil {
|
||||||
@ -101,14 +117,14 @@ struct ChannelVideosView: View {
|
|||||||
.navigationTitle(navigationTitle)
|
.navigationTitle(navigationTitle)
|
||||||
}
|
}
|
||||||
|
|
||||||
var resource: Resource {
|
private var resource: Resource {
|
||||||
let resource = accounts.api.channel(channel.id)
|
let resource = accounts.api.channel(channel.id)
|
||||||
resource.addObserver(store)
|
resource.addObserver(store)
|
||||||
|
|
||||||
return resource
|
return resource
|
||||||
}
|
}
|
||||||
|
|
||||||
var subscriptionToggleButton: some View {
|
private var subscriptionToggleButton: some View {
|
||||||
Group {
|
Group {
|
||||||
if accounts.app.supportsSubscriptions && accounts.signedIn {
|
if accounts.app.supportsSubscriptions && accounts.signedIn {
|
||||||
if subscriptions.isSubscribing(channel.id) {
|
if subscriptions.isSubscribing(channel.id) {
|
||||||
@ -126,7 +142,19 @@ struct ChannelVideosView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var navigationTitle: String {
|
private var shareButtonPlacement: ToolbarItemPlacement {
|
||||||
|
#if os(iOS)
|
||||||
|
.navigation
|
||||||
|
#else
|
||||||
|
.automatic
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private var contentItem: ContentItem {
|
||||||
|
ContentItem(channel: channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var navigationTitle: String {
|
||||||
store.item?.name ?? channel.name
|
store.item?.name ?? channel.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
Shared/Views/ShareButton.swift
Normal file
39
Shared/Views/ShareButton.swift
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ShareButton: View {
|
||||||
|
let contentItem: ContentItem
|
||||||
|
@Binding var presentingShareSheet: Bool
|
||||||
|
|
||||||
|
@EnvironmentObject<AccountsModel> private var accounts
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button {
|
||||||
|
#if os(iOS)
|
||||||
|
presentingShareSheet = true
|
||||||
|
#else
|
||||||
|
NSPasteboard.general.clearContents()
|
||||||
|
NSPasteboard.general.setString(shareURL, forType: .string)
|
||||||
|
#endif
|
||||||
|
} label: {
|
||||||
|
#if os(iOS)
|
||||||
|
Label("Share", systemImage: "square.and.arrow.up")
|
||||||
|
#else
|
||||||
|
EmptyView()
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.keyboardShortcut("c")
|
||||||
|
.foregroundColor(.blue)
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var shareURL: String {
|
||||||
|
accounts.api.shareURL(contentItem).absoluteString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ShareButton_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
ShareButton(contentItem: ContentItem(video: Video.fixture), presentingShareSheet: .constant(false))
|
||||||
|
}
|
||||||
|
}
|
28
iOS/ShareSheet.swift
Normal file
28
iOS/ShareSheet.swift
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ShareSheet: UIViewControllerRepresentable {
|
||||||
|
typealias Callback = (_ activityType: UIActivity.ActivityType?,
|
||||||
|
_ completed: Bool,
|
||||||
|
_ returnedItems: [Any]?,
|
||||||
|
_ error: Error?) -> Void
|
||||||
|
|
||||||
|
let activityItems: [Any]
|
||||||
|
let applicationActivities = [UIActivity]()
|
||||||
|
let excludedActivityTypes = [UIActivity.ActivityType]()
|
||||||
|
let callback: Callback? = nil
|
||||||
|
|
||||||
|
func makeUIViewController(context _: Context) -> UIActivityViewController {
|
||||||
|
let controller = UIActivityViewController(
|
||||||
|
activityItems: activityItems,
|
||||||
|
applicationActivities: applicationActivities
|
||||||
|
)
|
||||||
|
|
||||||
|
controller.excludedActivityTypes = excludedActivityTypes
|
||||||
|
controller.completionWithItemsHandler = callback
|
||||||
|
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIViewController(_: UIActivityViewController, context _: Context) {}
|
||||||
|
}
|
@ -6,6 +6,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applicationWillFinishLaunching(_: Notification) {
|
||||||
|
NSWindow.allowsAutomaticWindowTabbing = false
|
||||||
|
}
|
||||||
|
|
||||||
func applicationWillTerminate(_: Notification) {
|
func applicationWillTerminate(_: Notification) {
|
||||||
ScreenSaverManager.shared.enable()
|
ScreenSaverManager.shared.enable()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user