mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Merge branch 'main' into use-mpvkit
This commit is contained in:
commit
757afd39da
@ -6,15 +6,9 @@ disabled_rules:
|
|||||||
- opening_brace
|
- opening_brace
|
||||||
- number_separator
|
- number_separator
|
||||||
- multiline_arguments
|
- multiline_arguments
|
||||||
opt_in_rules:
|
|
||||||
- implicit_return
|
- implicit_return
|
||||||
excluded:
|
excluded:
|
||||||
- Vendor
|
- Vendor
|
||||||
- Tests Apple TV
|
- Tests Apple TV
|
||||||
- Tests iOS
|
- Tests iOS
|
||||||
- Tests macOS
|
- Tests macOS
|
||||||
|
|
||||||
implicit_return:
|
|
||||||
included:
|
|
||||||
- function
|
|
||||||
- getter
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
extension Backport where Content: View {
|
|
||||||
@ViewBuilder func badge(_ count: Text?) -> some View {
|
|
||||||
#if os(tvOS)
|
|
||||||
content
|
|
||||||
#else
|
|
||||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
|
||||||
content.badge(count)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
extension Backport where Content: View {
|
|
||||||
@ViewBuilder func listRowSeparator(_ visible: Bool) -> some View {
|
|
||||||
if #available(iOS 15, macOS 13, *) {
|
|
||||||
content
|
|
||||||
#if !os(tvOS)
|
|
||||||
.listRowSeparator(visible ? .visible : .hidden)
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
extension Backport where Content: View {
|
|
||||||
@ViewBuilder func refreshable(action: @Sendable @escaping () async -> Void) -> some View {
|
|
||||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
|
||||||
content.refreshable(action: action)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
extension Backport where Content: View {
|
|
||||||
@ViewBuilder func tint(_ color: Color?) -> some View {
|
|
||||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
|
||||||
content.tint(color)
|
|
||||||
} else {
|
|
||||||
content.foregroundColor(color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
73
CHANGELOG.md
73
CHANGELOG.md
@ -1,67 +1,10 @@
|
|||||||
## Build 155
|
## Build 157
|
||||||
|
* Increased controls timeline/scrubber gesture area for easier handling
|
||||||
|
* Fixed issue where Piped videos would use audio for other language version
|
||||||
|
* Fixed issue with handling opening URLs on macOS
|
||||||
|
* Fixed issue with "Keep channels with unwatched videos on top of subscriptions list" setting not honored in sidebar
|
||||||
|
* Fixed performance issues with accounts with large amount of subscribed channels
|
||||||
|
* Fixed compatibility with iOS 17, macOS 14 and tvOS 17
|
||||||
|
* Dropped support for iOS 14 and macOS 11
|
||||||
* Fixed reported crashes
|
* Fixed reported crashes
|
||||||
* Minor performance improvements
|
|
||||||
|
|
||||||
## Previous Builds
|
|
||||||
* Fixed issue where AVPlayer would pause playing on exiting fullscreen
|
|
||||||
* Fixed issue with empty button appearing on subscriptions list on tvOS
|
|
||||||
|
|
||||||
* Fixed issue with AVPlayer not always using full width
|
|
||||||
* Fixed issue with layout when switching backend while in fullscreen
|
|
||||||
* Fixed issue with updating watched time on closing video
|
|
||||||
* Fixed issue with adjusting AVPlayer playback rate when using system controls
|
|
||||||
* Fixed issue where comments would load indefinitely
|
|
||||||
* Improved Home buttons layout on tvOS
|
|
||||||
* Reverted change to placeholders as were causing issues to properly display loading status, will be revisited in future
|
|
||||||
* Fixed performance issue with swiping back to subscribed channels list
|
|
||||||
* Fixed reported crashes
|
|
||||||
|
|
||||||
* Tapping second time on search tab button focuses the input field and selects entered query text (iOS)
|
|
||||||
* Added Browsing setting "Keep channels with unwatched videos on top of subscriptions list"
|
|
||||||
* Improved buttons and layout on tvOS
|
|
||||||
* Fixed issue with trending categories (Invidious) not working when using non-English language
|
|
||||||
* Fixed issue with search query suggestions not being displayed properly in some languages
|
|
||||||
* Changed subscriptions page picker label from icon to text
|
|
||||||
* Views will display information if there is no videos to show instead of always showing placeholders
|
|
||||||
* Fixed AVPlayer issue with music mode playing video track
|
|
||||||
* Added remove context menu option for all types of recent items in Search
|
|
||||||
* Added advanced setting "Show video context menu options to force selected backend"
|
|
||||||
* Fixed reported crashes
|
|
||||||
|
|
||||||
* Improved Home
|
|
||||||
- Added menu with view options on iOS and toolbar buttons on macOS/tvOS
|
|
||||||
- Added Home Settings
|
|
||||||
- Moved settings from Browsing to Home Settings
|
|
||||||
- Enhanced Favorites management: select listing type and videos limit for each element
|
|
||||||
- Select listing type for History just like for Favorites
|
|
||||||
* Added view option to hide watched videos
|
|
||||||
* Added Browsing setting "Startup section"
|
|
||||||
* Added feed/channels list segmented picker in Subscriptions and moved view options menu on iOS
|
|
||||||
* Thumbnails in list view respect "Round corners" setting
|
|
||||||
* Added watching progress indicator to list view
|
|
||||||
* Moved "Show toggle watch status button" to History settings
|
|
||||||
* Removed "Rotate to portrait when exiting fullscreen" setting - it is instead automatically decided depending on device type
|
|
||||||
* Fixed channels view layout on tvOS
|
|
||||||
* Fixed channels and playlists navigation on tvOS
|
|
||||||
* Fixed issue where controls were not visible when music mode was enabled
|
|
||||||
* Fixed issue with closing Picture in Picture on macOS
|
|
||||||
* Fixed issue where playing video with AVPlayer would cause it to be immediately marked as watched
|
|
||||||
* Fixed issue with playlists view showing duplicated buttons when "Show cache status" is enabled
|
|
||||||
* Fixed issue where navigating to channel from list view in Playlists and Search would immediately go back
|
|
||||||
* Fixed issue where first URL would fail to open
|
|
||||||
|
|
||||||
* Added support for AVPlayer native system controls on iOS and macOS
|
|
||||||
- Use system features such as AirPlay, subtitles switching (Piped with HLS), text detection and copy and more
|
|
||||||
- Added Controls setting: "Use system controls with AVPlayer"
|
|
||||||
* Player rotates for landscape videos on entering full screen on iOS
|
|
||||||
- Player > Orientation setting: "Rotate when entering fullscreen on landscape video"
|
|
||||||
* Added Player > Playback setting: "Close video and player on end"
|
|
||||||
* Added reporting for opening stream in OSD for AVPlayer
|
|
||||||
* Fixed issue with opening channels and playlists links
|
|
||||||
* Fixed issues where controls/player layout could break (e.g., when going to background and back)
|
|
||||||
* Fixed issue where stream picker would show duplicate entries
|
|
||||||
* Fixed issue where search suggestions would show unnecessary bottom padding
|
|
||||||
* Fixed landscape channel sheet layout in player
|
|
||||||
* Fixed reported crashes
|
|
||||||
* Localization updates and fixes
|
|
||||||
* Other minor fixes and improvements
|
* Other minor fixes and improvements
|
||||||
|
32
Gemfile.lock
32
Gemfile.lock
@ -8,20 +8,20 @@ GEM
|
|||||||
artifactory (3.0.15)
|
artifactory (3.0.15)
|
||||||
atomos (0.1.3)
|
atomos (0.1.3)
|
||||||
aws-eventstream (1.2.0)
|
aws-eventstream (1.2.0)
|
||||||
aws-partitions (1.769.0)
|
aws-partitions (1.791.0)
|
||||||
aws-sdk-core (3.173.1)
|
aws-sdk-core (3.178.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.651.0)
|
aws-partitions (~> 1, >= 1.651.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
aws-sdk-kms (1.64.0)
|
aws-sdk-kms (1.71.0)
|
||||||
aws-sdk-core (~> 3, >= 3.165.0)
|
aws-sdk-core (~> 3, >= 3.177.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.122.0)
|
aws-sdk-s3 (1.131.0)
|
||||||
aws-sdk-core (~> 3, >= 3.165.0)
|
aws-sdk-core (~> 3, >= 3.177.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.4)
|
aws-sigv4 (~> 1.6)
|
||||||
aws-sigv4 (1.5.2)
|
aws-sigv4 (1.6.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
babosa (1.0.4)
|
babosa (1.0.4)
|
||||||
claide (1.1.0)
|
claide (1.1.0)
|
||||||
@ -30,13 +30,13 @@ GEM
|
|||||||
commander (4.6.0)
|
commander (4.6.0)
|
||||||
highline (~> 2.0.0)
|
highline (~> 2.0.0)
|
||||||
declarative (0.0.20)
|
declarative (0.0.20)
|
||||||
digest-crc (0.6.4)
|
digest-crc (0.6.5)
|
||||||
rake (>= 12.0.0, < 14.0.0)
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
domain_name (0.5.20190701)
|
domain_name (0.5.20190701)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
dotenv (2.8.1)
|
dotenv (2.8.1)
|
||||||
emoji_regex (3.2.3)
|
emoji_regex (3.2.3)
|
||||||
excon (0.99.0)
|
excon (0.100.0)
|
||||||
faraday (1.10.3)
|
faraday (1.10.3)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
faraday-em_synchrony (~> 1.0)
|
faraday-em_synchrony (~> 1.0)
|
||||||
@ -66,7 +66,7 @@ GEM
|
|||||||
faraday_middleware (1.2.0)
|
faraday_middleware (1.2.0)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
fastimage (2.2.7)
|
fastimage (2.2.7)
|
||||||
fastlane (2.213.0)
|
fastlane (2.214.0)
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
addressable (>= 2.8, < 3.0.0)
|
addressable (>= 2.8, < 3.0.0)
|
||||||
artifactory (~> 3.0)
|
artifactory (~> 3.0)
|
||||||
@ -106,9 +106,9 @@ GEM
|
|||||||
xcpretty (~> 0.3.0)
|
xcpretty (~> 0.3.0)
|
||||||
xcpretty-travis-formatter (>= 0.0.3)
|
xcpretty-travis-formatter (>= 0.0.3)
|
||||||
gh_inspector (1.1.3)
|
gh_inspector (1.1.3)
|
||||||
google-apis-androidpublisher_v3 (0.42.0)
|
google-apis-androidpublisher_v3 (0.46.0)
|
||||||
google-apis-core (>= 0.11.0, < 2.a)
|
google-apis-core (>= 0.11.0, < 2.a)
|
||||||
google-apis-core (0.11.0)
|
google-apis-core (0.11.1)
|
||||||
addressable (~> 2.5, >= 2.5.1)
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
googleauth (>= 0.16.2, < 2.a)
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
httpclient (>= 2.8.1, < 3.a)
|
httpclient (>= 2.8.1, < 3.a)
|
||||||
@ -137,7 +137,7 @@ GEM
|
|||||||
google-cloud-core (~> 1.6)
|
google-cloud-core (~> 1.6)
|
||||||
googleauth (>= 0.16.2, < 2.a)
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
googleauth (1.5.2)
|
googleauth (1.7.0)
|
||||||
faraday (>= 0.17.3, < 3.a)
|
faraday (>= 0.17.3, < 3.a)
|
||||||
jwt (>= 1.4, < 3.0)
|
jwt (>= 1.4, < 3.0)
|
||||||
memoist (~> 0.16)
|
memoist (~> 0.16)
|
||||||
@ -150,7 +150,7 @@ GEM
|
|||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.6.3)
|
json (2.6.3)
|
||||||
jwt (2.7.0)
|
jwt (2.7.1)
|
||||||
memoist (0.16.2)
|
memoist (0.16.2)
|
||||||
mini_magick (4.12.0)
|
mini_magick (4.12.0)
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
@ -161,7 +161,7 @@ GEM
|
|||||||
optparse (0.1.1)
|
optparse (0.1.1)
|
||||||
os (1.1.4)
|
os (1.1.4)
|
||||||
plist (3.7.0)
|
plist (3.7.0)
|
||||||
public_suffix (5.0.1)
|
public_suffix (5.0.3)
|
||||||
rake (13.0.6)
|
rake (13.0.6)
|
||||||
representable (3.2.0)
|
representable (3.2.0)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
|
@ -76,8 +76,7 @@ final class InstancesModel: ObservableObject {
|
|||||||
func standardizedURL(_ url: String) -> String {
|
func standardizedURL(_ url: String) -> String {
|
||||||
if url.count > 7, url.last == "/" {
|
if url.count > 7, url.last == "/" {
|
||||||
return String(url.dropLast())
|
return String(url.dropLast())
|
||||||
} else {
|
|
||||||
return url
|
|
||||||
}
|
}
|
||||||
|
return url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,11 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
|
|
||||||
if type == "channel" {
|
if type == "channel" {
|
||||||
return ContentItem(channel: self.extractChannel(from: json))
|
return ContentItem(channel: self.extractChannel(from: json))
|
||||||
} else if type == "playlist" {
|
}
|
||||||
|
if type == "playlist" {
|
||||||
return ContentItem(playlist: self.extractChannelPlaylist(from: json))
|
return ContentItem(playlist: self.extractChannelPlaylist(from: json))
|
||||||
} else if type == "video" {
|
}
|
||||||
|
if type == "video" {
|
||||||
return ContentItem(video: self.extractVideo(from: json))
|
return ContentItem(video: self.extractVideo(from: json))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -724,9 +726,11 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
|
|
||||||
if type == "channel" {
|
if type == "channel" {
|
||||||
return ContentItem(channel: extractChannel(from: json))
|
return ContentItem(channel: extractChannel(from: json))
|
||||||
} else if type == "playlist" {
|
}
|
||||||
|
if type == "playlist" {
|
||||||
return ContentItem(playlist: extractChannelPlaylist(from: json))
|
return ContentItem(playlist: extractChannelPlaylist(from: json))
|
||||||
} else if type == "video" {
|
}
|
||||||
|
if type == "video" {
|
||||||
return ContentItem(video: extractVideo(from: json))
|
return ContentItem(video: extractVideo(from: json))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ final class PeerTubeAPI: Service, ObservableObject, VideosAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func search(_ query: SearchQuery, page _: String?) -> Resource {
|
func search(_ query: SearchQuery, page _: String?) -> Resource {
|
||||||
var resource = resource(baseURL: account.url, path: basePathAppending("search/videos"))
|
resource(baseURL: account.url, path: basePathAppending("search/videos"))
|
||||||
.withParam("search", query.query)
|
.withParam("search", query.query)
|
||||||
// .withParam("sort_by", query.sortBy.parameter)
|
// .withParam("sort_by", query.sortBy.parameter)
|
||||||
// .withParam("type", "all")
|
// .withParam("type", "all")
|
||||||
@ -409,7 +409,7 @@ final class PeerTubeAPI: Service, ObservableObject, VideosAPI {
|
|||||||
// resource = resource.withParam("page", page)
|
// resource = resource.withParam("page", page)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return resource
|
// return resource
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchSuggestions(query: String) -> Resource {
|
func searchSuggestions(query: String) -> Resource {
|
||||||
|
@ -620,6 +620,10 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
|||||||
.dictionaryValue["audioStreams"]?
|
.dictionaryValue["audioStreams"]?
|
||||||
.arrayValue
|
.arrayValue
|
||||||
.filter { $0.dictionaryValue["format"]?.string == "M4A" }
|
.filter { $0.dictionaryValue["format"]?.string == "M4A" }
|
||||||
|
.filter { stream in
|
||||||
|
let type = stream.dictionaryValue["audioTrackType"]?.string
|
||||||
|
return type == nil || type == "ORIGINAL"
|
||||||
|
}
|
||||||
.sorted {
|
.sorted {
|
||||||
$0.dictionaryValue["bitrate"]?.int ?? 0 >
|
$0.dictionaryValue["bitrate"]?.int ?? 0 >
|
||||||
$1.dictionaryValue["bitrate"]?.int ?? 0
|
$1.dictionaryValue["bitrate"]?.int ?? 0
|
||||||
|
@ -18,12 +18,14 @@ struct FeedCacheModel: CacheModel {
|
|||||||
)
|
)
|
||||||
|
|
||||||
func storeFeed(account: Account, videos: [Video]) {
|
func storeFeed(account: Account, videos: [Video]) {
|
||||||
let date = iso8601DateFormatter.string(from: Date())
|
DispatchQueue.global(qos: .background).async {
|
||||||
logger.info("caching feed \(account.feedCacheKey) -- \(date)")
|
let date = iso8601DateFormatter.string(from: Date())
|
||||||
let feedTimeObject: JSON = ["date": date]
|
logger.info("caching feed \(account.feedCacheKey) -- \(date)")
|
||||||
let videosObject: JSON = ["videos": videos.prefix(cacheLimit).map { $0.json.object }]
|
let feedTimeObject: JSON = ["date": date]
|
||||||
try? storage?.setObject(feedTimeObject, forKey: feedTimeCacheKey(account.feedCacheKey))
|
let videosObject: JSON = ["videos": videos.prefix(cacheLimit).map { $0.json.object }]
|
||||||
try? storage?.setObject(videosObject, forKey: account.feedCacheKey)
|
try? storage?.setObject(feedTimeObject, forKey: feedTimeCacheKey(account.feedCacheKey))
|
||||||
|
try? storage?.setObject(videosObject, forKey: account.feedCacheKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func retrieveFeed(account: Account) -> [Video] {
|
func retrieveFeed(account: Account) -> [Video] {
|
||||||
|
@ -85,7 +85,6 @@ final class SubscribedChannelsModel: ObservableObject, CacheModel {
|
|||||||
self.error = nil
|
self.error = nil
|
||||||
if let channels: [Channel] = resource.typedContent() {
|
if let channels: [Channel] = resource.typedContent() {
|
||||||
self.channels = channels
|
self.channels = channels
|
||||||
channels.forEach { ChannelsCacheModel.shared.storeIfMissing($0) }
|
|
||||||
self.storeChannels(account: account, channels: channels)
|
self.storeChannels(account: account, channels: channels)
|
||||||
FeedModel.shared.calculateUnwatchedFeed()
|
FeedModel.shared.calculateUnwatchedFeed()
|
||||||
onSuccess()
|
onSuccess()
|
||||||
@ -105,16 +104,18 @@ final class SubscribedChannelsModel: ObservableObject, CacheModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func storeChannels(account: Account, channels: [Channel]) {
|
func storeChannels(account: Account, channels: [Channel]) {
|
||||||
let date = iso8601DateFormatter.string(from: Date())
|
DispatchQueue.global(qos: .background).async {
|
||||||
logger.info("caching channels \(channelsDateCacheKey(account)) -- \(date)")
|
let date = self.iso8601DateFormatter.string(from: Date())
|
||||||
|
self.logger.info("caching channels \(self.channelsDateCacheKey(account)) -- \(date)")
|
||||||
|
|
||||||
channels.forEach { ChannelsCacheModel.shared.storeIfMissing($0) }
|
channels.forEach { ChannelsCacheModel.shared.storeIfMissing($0) }
|
||||||
|
|
||||||
let dateObject: JSON = ["date": date]
|
let dateObject: JSON = ["date": date]
|
||||||
let channelsObject: JSON = ["channels": channels.map(\.json).map(\.object)]
|
let channelsObject: JSON = ["channels": channels.map(\.json).map(\.object)]
|
||||||
|
|
||||||
try? storage?.setObject(dateObject, forKey: channelsDateCacheKey(account))
|
try? self.storage?.setObject(dateObject, forKey: self.channelsDateCacheKey(account))
|
||||||
try? storage?.setObject(channelsObject, forKey: channelsCacheKey(account))
|
try? self.storage?.setObject(channelsObject, forKey: self.channelsCacheKey(account))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getChannels(account: Account) -> [Channel] {
|
func getChannels(account: Account) -> [Channel] {
|
||||||
|
@ -110,7 +110,7 @@ struct Channel: Identifiable, Hashable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hasData(for contentType: ContentType) -> Bool {
|
func hasData(for contentType: ContentType) -> Bool {
|
||||||
return tabs.contains { $0.contentType == contentType }
|
tabs.contains { $0.contentType == contentType }
|
||||||
}
|
}
|
||||||
|
|
||||||
var cacheKey: String {
|
var cacheKey: String {
|
||||||
|
@ -15,7 +15,7 @@ struct ContentItem: Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func < (lhs: ContentType, rhs: ContentType) -> Bool {
|
static func < (lhs: Self, rhs: Self) -> Bool {
|
||||||
lhs.sortOrder < rhs.sortOrder
|
lhs.sortOrder < rhs.sortOrder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,19 +30,19 @@ struct ContentItem: Identifiable {
|
|||||||
|
|
||||||
var id: String = UUID().uuidString
|
var id: String = UUID().uuidString
|
||||||
|
|
||||||
static func array(of videos: [Video]) -> [ContentItem] {
|
static func array(of videos: [Video]) -> [Self] {
|
||||||
videos.map { Self(video: $0) }
|
videos.map { Self(video: $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func array(of playlists: [ChannelPlaylist]) -> [ContentItem] {
|
static func array(of playlists: [ChannelPlaylist]) -> [Self] {
|
||||||
playlists.map { Self(playlist: $0) }
|
playlists.map { Self(playlist: $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func array(of channels: [Channel]) -> [ContentItem] {
|
static func array(of channels: [Channel]) -> [Self] {
|
||||||
channels.map { Self(channel: $0) }
|
channels.map { Self(channel: $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func < (lhs: ContentItem, rhs: ContentItem) -> Bool {
|
static func < (lhs: Self, rhs: Self) -> Bool {
|
||||||
lhs.contentType < rhs.contentType
|
lhs.contentType < rhs.contentType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ extension Country {
|
|||||||
case .lk: return "Sri Lanka"
|
case .lk: return "Sri Lanka"
|
||||||
case .se: return "Sweden"
|
case .se: return "Sweden"
|
||||||
case .ch: return "Switzerland"
|
case .ch: return "Switzerland"
|
||||||
case .tw: return "Taiwan, Province of China[a]"
|
case .tw: return "Taiwan"
|
||||||
case .tz: return "Tanzania, United Republic of"
|
case .tz: return "Tanzania, United Republic of"
|
||||||
case .th: return "Thailand"
|
case .th: return "Thailand"
|
||||||
case .tn: return "Tunisia"
|
case .tn: return "Tunisia"
|
||||||
|
@ -47,7 +47,7 @@ struct FavoriteItem: Codable, Equatable, Identifiable, Defaults.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func == (lhs: FavoriteItem, rhs: FavoriteItem) -> Bool {
|
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
lhs.section == rhs.section
|
lhs.section == rhs.section
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,11 @@ struct FavoritesModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func toggle(_ item: FavoriteItem) {
|
func toggle(_ item: FavoriteItem) {
|
||||||
contains(item) ? remove(item) : add(item)
|
if contains(item) {
|
||||||
|
remove(item)
|
||||||
|
} else {
|
||||||
|
add(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(_ item: FavoriteItem) {
|
func add(_ item: FavoriteItem) {
|
||||||
|
@ -52,7 +52,6 @@ extension PlayerModel {
|
|||||||
let id = currentVideo.videoID
|
let id = currentVideo.videoID
|
||||||
let time = time ?? backend.currentTime
|
let time = time ?? backend.currentTime
|
||||||
let seconds = time?.seconds ?? 0
|
let seconds = time?.seconds ?? 0
|
||||||
let duration = playerTime.duration.seconds
|
|
||||||
if seconds < 3 {
|
if seconds < 3 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,8 @@ final class InstancesManifest: Service, ObservableObject {
|
|||||||
|
|
||||||
instancesList?.load().onSuccess { response in
|
instancesList?.load().onSuccess { response in
|
||||||
if let instances: [ManifestedInstance] = response.typedContent() {
|
if let instances: [ManifestedInstance] = response.typedContent() {
|
||||||
guard let instance = instances.filter { $0.country == country }.randomElement() else { return }
|
let countryInstances = instances.filter { $0.country == country }
|
||||||
|
guard let instance = countryInstances.randomElement() else { return }
|
||||||
let account = instance.anonymousAccount
|
let account = instance.anonymousAccount
|
||||||
AccountsModel.shared.publicAccount = account
|
AccountsModel.shared.publicAccount = account
|
||||||
if asCurrent {
|
if asCurrent {
|
||||||
|
@ -63,7 +63,7 @@ struct OpenVideosModel {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
func openURLsFromClipboard(removeQueueItems: Bool = false, playbackMode: OpenVideosModel.PlaybackMode = .playNow) {
|
func openURLsFromClipboard(removeQueueItems: Bool = false, playbackMode: Self.PlaybackMode = .playNow) {
|
||||||
if urlsFromClipboard.isEmpty {
|
if urlsFromClipboard.isEmpty {
|
||||||
NavigationModel.shared.alert = Alert(title: Text("Could not find any links to open in your clipboard".localized()))
|
NavigationModel.shared.alert = Alert(title: Text("Could not find any links to open in your clipboard".localized()))
|
||||||
if NavigationModel.shared.presentingOpenVideos {
|
if NavigationModel.shared.presentingOpenVideos {
|
||||||
@ -76,7 +76,7 @@ struct OpenVideosModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openURLs(_ urls: [URL], removeQueueItems: Bool = false, playbackMode: OpenVideosModel.PlaybackMode = .playNow) {
|
func openURLs(_ urls: [URL], removeQueueItems: Bool = false, playbackMode: Self.PlaybackMode = .playNow) {
|
||||||
guard !urls.isEmpty else {
|
guard !urls.isEmpty else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,11 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func togglePlay() {
|
func togglePlay() {
|
||||||
isPlaying ? pause() : play()
|
if isPlaying {
|
||||||
|
pause()
|
||||||
|
} else {
|
||||||
|
play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
@ -414,9 +418,8 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
private func playerItem(_: Stream) -> AVPlayerItem? {
|
private func playerItem(_: Stream) -> AVPlayerItem? {
|
||||||
if let asset {
|
if let asset {
|
||||||
return AVPlayerItem(asset: asset)
|
return AVPlayerItem(asset: asset)
|
||||||
} else {
|
|
||||||
return AVPlayerItem(asset: composition)
|
|
||||||
}
|
}
|
||||||
|
return AVPlayerItem(asset: composition)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func attachMetadata() {
|
private func attachMetadata() {
|
||||||
|
@ -357,7 +357,11 @@ final class MPVBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func togglePlay() {
|
func togglePlay() {
|
||||||
isPlaying ? pause() : play()
|
if isPlaying {
|
||||||
|
pause()
|
||||||
|
} else {
|
||||||
|
play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cancelLoads() {
|
func cancelLoads() {
|
||||||
|
@ -86,7 +86,7 @@ final class MPVClient: ObservableObject {
|
|||||||
]
|
]
|
||||||
|
|
||||||
if mpv_render_context_create(&mpvGL, mpv, ¶ms) < 0 {
|
if mpv_render_context_create(&mpvGL, mpv, ¶ms) < 0 {
|
||||||
puts("failed to initialize mpv GL context")
|
print("failed to initialize mpv GL context")
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,9 +471,8 @@ final class MPVClient: ObservableObject {
|
|||||||
let data = Data(bufPtr)
|
let data = Data(bufPtr)
|
||||||
if let lastIndex = data.lastIndex(where: { $0 != 0 }) {
|
if let lastIndex = data.lastIndex(where: { $0 != 0 }) {
|
||||||
return String(data: data[0 ... lastIndex], encoding: .isoLatin1)!
|
return String(data: data[0 ... lastIndex], encoding: .isoLatin1)!
|
||||||
} else {
|
|
||||||
return String(data: data, encoding: .isoLatin1)!
|
|
||||||
}
|
}
|
||||||
|
return String(data: data, encoding: .isoLatin1)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ final class PlayerControlsModel: ObservableObject {
|
|||||||
var timer: Timer?
|
var timer: Timer?
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
private(set) var reporter = PassthroughSubject<String, Never>()
|
private(set) var reporter = PassthroughSubject<String, Never>() // swiftlint:disable:this private_subject
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var player: PlayerModel! { .shared }
|
var player: PlayerModel! { .shared }
|
||||||
@ -106,7 +106,11 @@ final class PlayerControlsModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func toggle() {
|
func toggle() {
|
||||||
presentingControls ? hide() : show()
|
if presentingControls {
|
||||||
|
hide()
|
||||||
|
} else {
|
||||||
|
show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetTimer() {
|
func resetTimer() {
|
||||||
|
@ -717,7 +717,11 @@ final class PlayerModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func togglePiPAction() {
|
func togglePiPAction() {
|
||||||
(pipController?.isPictureInPictureActive ?? false) ? closePiP() : startPiP()
|
if pipController?.isPictureInPictureActive ?? false {
|
||||||
|
closePiP()
|
||||||
|
} else {
|
||||||
|
startPiP()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -812,12 +816,12 @@ final class PlayerModel: ObservableObject {
|
|||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
self.playerAPI(item.video)?.loadDetails(item, completionHandler: { newItem in
|
self.playerAPI(item.video)?.loadDetails(item, failureHandler: nil) { newItem in
|
||||||
guard newItem.videoID == self.autoplayItem?.videoID else { return }
|
guard newItem.videoID == self.autoplayItem?.videoID else { return }
|
||||||
self.autoplayItem = newItem
|
self.autoplayItem = newItem
|
||||||
self.updateRemoteCommandCenter()
|
self.updateRemoteCommandCenter()
|
||||||
self.controls.objectWillChange.send()
|
self.controls.objectWillChange.send()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,13 +328,13 @@ extension PlayerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
playerAPI(video)?
|
playerAPI(video)?
|
||||||
.loadDetails(item, completionHandler: { [weak self] newItem in
|
.loadDetails(item, failureHandler: nil) { [weak self] newItem in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|
||||||
replaceQueueItem(newItem)
|
replaceQueueItem(newItem)
|
||||||
|
|
||||||
self.logger.info("LOADED queue details: \(videoID)")
|
self.logger.info("LOADED queue details: \(videoID)")
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func videoLoadFailureHandler(_ error: RequestError, video: Video? = nil) {
|
private func videoLoadFailureHandler(_ error: RequestError, video: Video? = nil) {
|
||||||
|
@ -60,7 +60,7 @@ struct Playlist: Identifiable, Equatable, Hashable {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func == (lhs: Playlist, rhs: Playlist) -> Bool {
|
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
lhs.id == rhs.id && lhs.updated == rhs.updated
|
lhs.id == rhs.id && lhs.updated == rhs.updated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,8 @@ struct QualityProfile: Hashable, Identifiable, Defaults.Serializable {
|
|||||||
var formatsDescription: String {
|
var formatsDescription: String {
|
||||||
if formats.count == Format.allCases.count {
|
if formats.count == Format.allCases.count {
|
||||||
return "Any format".localized()
|
return "Any format".localized()
|
||||||
} else if formats.count <= 3 {
|
}
|
||||||
|
if formats.count <= 3 {
|
||||||
return formats.map(\.description).joined(separator: ", ")
|
return formats.map(\.description).joined(separator: ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import Siesta
|
|||||||
final class Store<Data>: ResourceObserver, ObservableObject {
|
final class Store<Data>: ResourceObserver, ObservableObject {
|
||||||
@Published private var all: Data?
|
@Published private var all: Data?
|
||||||
|
|
||||||
var collection: Data { all ?? ([] as! Data) }
|
var collection: Data { all ?? ([item].compactMap { $0 } as! Data) }
|
||||||
var item: Data? { all }
|
var item: Data? { all }
|
||||||
|
|
||||||
init(_ data: Data? = nil) {
|
init(_ data: Data? = nil) {
|
||||||
|
@ -54,11 +54,11 @@ class Stream: Equatable, Hashable, Identifiable {
|
|||||||
return Int(refreshRatePart.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()) ?? -1
|
return Int(refreshRatePart.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()) ?? -1
|
||||||
}
|
}
|
||||||
|
|
||||||
static func from(resolution: String, fps: Int? = nil) -> Resolution {
|
static func from(resolution: String, fps: Int? = nil) -> Self {
|
||||||
allCases.first { $0.rawValue.contains(resolution) && $0.refreshRate == (fps ?? 30) } ?? .unknown
|
allCases.first { $0.rawValue.contains(resolution) && $0.refreshRate == (fps ?? 30) } ?? .unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
static func < (lhs: Resolution, rhs: Resolution) -> Bool {
|
static func < (lhs: Self, rhs: Self) -> Bool {
|
||||||
lhs.height == rhs.height ? (lhs.refreshRate < rhs.refreshRate) : (lhs.height < rhs.height)
|
lhs.height == rhs.height ? (lhs.refreshRate < rhs.refreshRate) : (lhs.height < rhs.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +77,7 @@ class Stream: Equatable, Hashable, Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func < (lhs: Kind, rhs: Kind) -> Bool {
|
static func < (lhs: Self, rhs: Self) -> Bool {
|
||||||
lhs.sortOrder < rhs.sortOrder
|
lhs.sortOrder < rhs.sortOrder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,15 +123,17 @@ class Stream: Equatable, Hashable, Identifiable {
|
|||||||
|
|
||||||
if lowercased.contains("webm") {
|
if lowercased.contains("webm") {
|
||||||
return .webm
|
return .webm
|
||||||
} else if lowercased.contains("avc1") {
|
|
||||||
return .avc1
|
|
||||||
} else if lowercased.contains("av01") {
|
|
||||||
return .av1
|
|
||||||
} else if lowercased.contains("mpeg_4") || lowercased.contains("mp4") {
|
|
||||||
return .mp4
|
|
||||||
} else {
|
|
||||||
return .unknown
|
|
||||||
}
|
}
|
||||||
|
if lowercased.contains("avc1") {
|
||||||
|
return .avc1
|
||||||
|
}
|
||||||
|
if lowercased.contains("av01") {
|
||||||
|
return .av1
|
||||||
|
}
|
||||||
|
if lowercased.contains("mpeg_4") || lowercased.contains("mp4") {
|
||||||
|
return .mp4
|
||||||
|
}
|
||||||
|
return .unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,9 +192,8 @@ class Stream: Equatable, Hashable, Identifiable {
|
|||||||
|
|
||||||
if kind == .hls {
|
if kind == .hls {
|
||||||
return "HLS"
|
return "HLS"
|
||||||
} else {
|
|
||||||
return resolution?.name ?? "?"
|
|
||||||
}
|
}
|
||||||
|
return resolution?.name ?? "?"
|
||||||
}
|
}
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
@ -221,7 +222,8 @@ class Stream: Equatable, Hashable, Identifiable {
|
|||||||
|
|
||||||
if kind == .hls {
|
if kind == .hls {
|
||||||
return hlsURL
|
return hlsURL
|
||||||
} else if videoAssetContainsAudio {
|
}
|
||||||
|
if videoAssetContainsAudio {
|
||||||
return videoAsset.url
|
return videoAsset.url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ struct URLBookmarkModel {
|
|||||||
func saveBookmark(_ url: NSURL) {
|
func saveBookmark(_ url: NSURL) {
|
||||||
guard url.isFileURL else {
|
guard url.isFileURL else {
|
||||||
logger.error("trying to save bookmark for something that is not a file")
|
logger.error("trying to save bookmark for something that is not a file")
|
||||||
logger.error("not a file: \(url.absoluteString)")
|
logger.error("not a file: \(url.absoluteString ?? "unknown")")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ struct Video: Identifiable, Equatable, Hashable {
|
|||||||
dislikes: Int? = nil,
|
dislikes: Int? = nil,
|
||||||
keywords: [String] = [],
|
keywords: [String] = [],
|
||||||
streams: [Stream] = [],
|
streams: [Stream] = [],
|
||||||
related: [Video] = [],
|
related: [Self] = [],
|
||||||
chapters: [Chapter] = [],
|
chapters: [Chapter] = [],
|
||||||
captions: [Captions] = []
|
captions: [Captions] = []
|
||||||
) {
|
) {
|
||||||
@ -116,7 +116,7 @@ struct Video: Identifiable, Equatable, Hashable {
|
|||||||
self.captions = captions
|
self.captions = captions
|
||||||
}
|
}
|
||||||
|
|
||||||
static func local(_ url: URL) -> Video {
|
static func local(_ url: URL) -> Self {
|
||||||
Self(
|
Self(
|
||||||
app: .local,
|
app: .local,
|
||||||
videoID: url.absoluteString,
|
videoID: url.absoluteString,
|
||||||
@ -249,7 +249,7 @@ struct Video: Identifiable, Equatable, Hashable {
|
|||||||
thumbnails.first { $0.quality == quality }?.url
|
thumbnails.first { $0.quality == quality }?.url
|
||||||
}
|
}
|
||||||
|
|
||||||
static func == (lhs: Video, rhs: Video) -> Bool {
|
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
let videoIDIsEqual = lhs.videoID == rhs.videoID
|
let videoIDIsEqual = lhs.videoID == rhs.videoID
|
||||||
|
|
||||||
if !lhs.indexID.isNil, !rhs.indexID.isNil {
|
if !lhs.indexID.isNil, !rhs.indexID.isNil {
|
||||||
|
@ -9,28 +9,26 @@ struct ChannelAvatarView: View {
|
|||||||
@ObservedObject private var accounts = AccountsModel.shared
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@ObservedObject private var subscribedChannels = SubscribedChannelsModel.shared
|
@ObservedObject private var subscribedChannels = SubscribedChannelsModel.shared
|
||||||
|
|
||||||
|
@State private var url: URL?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .bottomTrailing) {
|
ZStack(alignment: .bottomTrailing) {
|
||||||
Group {
|
Group {
|
||||||
Group {
|
Group {
|
||||||
if let url = channel?.thumbnailURLOrCached {
|
if let url {
|
||||||
ThumbnailView(url: url)
|
ThumbnailView(url: url)
|
||||||
} else {
|
} else {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color(white: 0.6)
|
Color("PlaceholderColor")
|
||||||
.opacity(0.5)
|
|
||||||
|
|
||||||
Group {
|
if let video, video.isLocal {
|
||||||
if let video, video.isLocal {
|
Image(systemName: video.localStreamImageSystemName)
|
||||||
Image(systemName: video.localStreamImageSystemName)
|
.foregroundColor(.accentColor)
|
||||||
} else {
|
.font(.system(size: 20))
|
||||||
Image(systemName: "play.rectangle")
|
.contentShape(Rectangle())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
.font(.system(size: 20))
|
|
||||||
.contentShape(Rectangle())
|
|
||||||
}
|
}
|
||||||
|
.onAppear(perform: updateURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
@ -54,6 +52,16 @@ struct ChannelAvatarView: View {
|
|||||||
}
|
}
|
||||||
.imageScale(.small)
|
.imageScale(.small)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateURL() {
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async {
|
||||||
|
if let url = channel?.thumbnailURLOrCached {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.url = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChannelAvatarView_Previews: PreviewProvider {
|
struct ChannelAvatarView_Previews: PreviewProvider {
|
||||||
|
@ -61,7 +61,8 @@ struct ChannelListItem: View {
|
|||||||
private var label: some View {
|
private var label: some View {
|
||||||
HStack(alignment: .top, spacing: 12) {
|
HStack(alignment: .top, spacing: 12) {
|
||||||
VStack {
|
VStack {
|
||||||
ChannelAvatarView(channel: channel)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
|
.id("channel-avatar-\(channel.id)")
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.frame(width: 90, height: 90)
|
.frame(width: 90, height: 90)
|
||||||
#else
|
#else
|
||||||
|
@ -40,7 +40,7 @@ struct ChannelVideosView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let content = VStack {
|
VStack {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
VStack {
|
VStack {
|
||||||
HStack(spacing: 24) {
|
HStack(spacing: 24) {
|
||||||
@ -181,19 +181,12 @@ struct ChannelVideosView: View {
|
|||||||
.navigationTitle(navigationTitle)
|
.navigationTitle(navigationTitle)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return Group {
|
#if os(tvOS)
|
||||||
if #available(macOS 12.0, *) {
|
.background(Color.background(scheme: colorScheme))
|
||||||
content
|
#endif
|
||||||
#if os(tvOS)
|
#if !os(iOS)
|
||||||
.background(Color.background(scheme: colorScheme))
|
.focusScope(focusNamespace)
|
||||||
#endif
|
#endif
|
||||||
#if !os(iOS)
|
|
||||||
.focusScope(focusNamespace)
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var verticalCellsEdgesIgnoringSafeArea: Edge.Set {
|
var verticalCellsEdgesIgnoringSafeArea: Edge.Set {
|
||||||
@ -212,6 +205,7 @@ struct ChannelVideosView: View {
|
|||||||
|
|
||||||
var thumbnail: some View {
|
var thumbnail: some View {
|
||||||
ChannelAvatarView(channel: store.item?.channel)
|
ChannelAvatarView(channel: store.item?.channel)
|
||||||
|
.id("channel-avatar-\(store.item?.channel?.id ?? "")")
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.frame(width: 80, height: 80, alignment: .trailing)
|
.frame(width: 80, height: 80, alignment: .trailing)
|
||||||
#else
|
#else
|
||||||
@ -338,7 +332,8 @@ struct ChannelVideosView: View {
|
|||||||
private var resource: Resource? {
|
private var resource: Resource? {
|
||||||
guard let channel = presentedChannel else { return nil }
|
guard let channel = presentedChannel else { return nil }
|
||||||
|
|
||||||
let data = contentType != .videos ? channel.tabs.first(where: { $0.contentType == contentType })?.data : nil
|
let tabData = channel.tabs.first { $0.contentType == contentType }?.data
|
||||||
|
let data = contentType != .videos ? tabData : nil
|
||||||
let resource = accounts.api.channel(channel.id, contentType: contentType, data: data)
|
let resource = accounts.api.channel(channel.id, contentType: contentType, data: data)
|
||||||
|
|
||||||
if contentType == .videos {
|
if contentType == .videos {
|
||||||
@ -451,7 +446,8 @@ struct ChannelVideosView: View {
|
|||||||
next = next ?? ""
|
next = next ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = contentType != .videos ? channel.tabs.first(where: { $0.contentType == contentType })?.data : nil
|
let tabData = channel.tabs.first { $0.contentType == contentType }?.data
|
||||||
|
let data = contentType != .videos ? tabData : nil
|
||||||
accounts.api.channel(channel.id, contentType: contentType, data: data, page: next).load().onSuccess { response in
|
accounts.api.channel(channel.id, contentType: contentType, data: data, page: next).load().onSuccess { response in
|
||||||
if let page: ChannelPage = response.typedContent() {
|
if let page: ChannelPage = response.typedContent() {
|
||||||
self.page = page
|
self.page = page
|
||||||
|
@ -63,16 +63,9 @@ struct Constants {
|
|||||||
|
|
||||||
static func seekIcon(_ type: String, _ interval: TimeInterval) -> String {
|
static func seekIcon(_ type: String, _ interval: TimeInterval) -> String {
|
||||||
let interval = Int(interval)
|
let interval = Int(interval)
|
||||||
let allVersions = [10, 15, 30, 45, 60, 75, 90]
|
let allVersions = [5, 10, 15, 30, 45, 60, 75, 90]
|
||||||
let iOS15 = [5]
|
|
||||||
let iconName = "go\(type).\(interval)"
|
let iconName = "go\(type).\(interval)"
|
||||||
|
|
||||||
if #available(iOS 15, macOS 12, *) {
|
|
||||||
if iOS15.contains(interval) {
|
|
||||||
return iconName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if allVersions.contains(interval) {
|
if allVersions.contains(interval) {
|
||||||
return iconName
|
return iconName
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,9 @@ extension Defaults.Keys {
|
|||||||
#endif
|
#endif
|
||||||
static let expandVideoDescription = Key<Bool>("expandVideoDescription", default: expandVideoDescriptionDefault)
|
static let expandVideoDescription = Key<Bool>("expandVideoDescription", default: expandVideoDescriptionDefault)
|
||||||
|
|
||||||
|
static let showChannelAvatarInChannelsLists = Key<Bool>("showChannelAvatarInChannelsLists", default: true)
|
||||||
|
static let showChannelAvatarInVideosListing = Key<Bool>("showChannelAvatarInVideosListing", default: true)
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
static let pauseOnHidingPlayerDefault = true
|
static let pauseOnHidingPlayerDefault = true
|
||||||
#else
|
#else
|
||||||
|
@ -34,8 +34,7 @@ struct DocumentsView: View {
|
|||||||
}
|
}
|
||||||
.navigationTitle(directoryLabel)
|
.navigationTitle(directoryLabel)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.navigationBarTitleDisplayMode(RefreshControl.navigationBarTitleDisplayMode)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.backport
|
|
||||||
.refreshable {
|
.refreshable {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
@ -105,12 +105,6 @@ struct FavoriteItemView: View {
|
|||||||
reloadVisibleWatches()
|
reloadVisibleWatches()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
|
||||||
Defaults.observe(.widgetsSettings) { _ in
|
|
||||||
watchModel.watchesChanged()
|
|
||||||
}
|
|
||||||
.tieToLifetime(of: accounts)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var emptyItemsText: String {
|
var emptyItemsText: String {
|
||||||
|
@ -15,14 +15,10 @@ struct AccountViewButton: View {
|
|||||||
} label: {
|
} label: {
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
if !accountPickerDisplaysUsername || !(model.current?.isPublic ?? true) {
|
if !accountPickerDisplaysUsername || !(model.current?.isPublic ?? true) {
|
||||||
if #available(iOS 15, macOS 12, *) {
|
if let name = model.current?.app?.rawValue.capitalized {
|
||||||
if let name = model.current?.app?.rawValue.capitalized {
|
Image(name)
|
||||||
Image(name)
|
.resizable()
|
||||||
.resizable()
|
.frame(width: accountImageSize, height: accountImageSize)
|
||||||
.frame(width: accountImageSize, height: accountImageSize)
|
|
||||||
} else {
|
|
||||||
Image(systemName: "globe")
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Image(systemName: "globe")
|
Image(systemName: "globe")
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ struct AppSidebarPlaylists: View {
|
|||||||
|
|
||||||
if accounts.app.userPlaylistsEndpointIncludesVideos, !playlist.videos.isEmpty {
|
if accounts.app.userPlaylistsEndpointIncludesVideos, !playlist.videos.isEmpty {
|
||||||
label
|
label
|
||||||
.backport
|
|
||||||
.badge(Text("\(playlist.videos.count)"))
|
.badge(Text("\(playlist.videos.count)"))
|
||||||
} else {
|
} else {
|
||||||
label
|
label
|
||||||
|
@ -50,6 +50,8 @@ struct RecentNavigationLink<DestinationContent: View>: View {
|
|||||||
var recents = RecentsModel.shared
|
var recents = RecentsModel.shared
|
||||||
@ObservedObject private var navigation = NavigationModel.shared
|
@ObservedObject private var navigation = NavigationModel.shared
|
||||||
|
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
|
||||||
var recent: RecentItem
|
var recent: RecentItem
|
||||||
var systemImage: String?
|
var systemImage: String?
|
||||||
let destination: DestinationContent
|
let destination: DestinationContent
|
||||||
@ -71,9 +73,10 @@ struct RecentNavigationLink<DestinationContent: View>: View {
|
|||||||
HStack {
|
HStack {
|
||||||
if recent.type == .channel,
|
if recent.type == .channel,
|
||||||
let channel = recent.channel,
|
let channel = recent.channel,
|
||||||
channel.thumbnailURLOrCached != nil
|
showChannelAvatarInChannelsLists
|
||||||
{
|
{
|
||||||
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
|
.id("channel-avatar-\(channel.id)")
|
||||||
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
||||||
|
|
||||||
Text(channel.name)
|
Text(channel.name)
|
||||||
|
@ -8,17 +8,23 @@ struct AppSidebarSubscriptions: View {
|
|||||||
@ObservedObject private var subscriptions = SubscribedChannelsModel.shared
|
@ObservedObject private var subscriptions = SubscribedChannelsModel.shared
|
||||||
|
|
||||||
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
||||||
|
@Default(.keepChannelsWithUnwatchedFeedOnTop) private var keepChannelsWithUnwatchedFeedOnTop
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
|
||||||
|
@State private var channelLinkActive = false
|
||||||
|
@State private var channelForLink: Channel?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Section(header: Text("Subscriptions")) {
|
Section(header: Text("Subscriptions")) {
|
||||||
ForEach(subscriptions.all) { channel in
|
ForEach(channels) { channel in
|
||||||
NavigationLink(tag: TabSelection.channel(channel.id), selection: $navigation.tabSelection) {
|
NavigationLink(tag: TabSelection.channel(channel.id), selection: $navigation.tabSelection) {
|
||||||
LazyView(ChannelVideosView(channel: channel))
|
LazyView(ChannelVideosView(channel: channel))
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
if channel.thumbnailURLOrCached != nil {
|
if showChannelAvatarInChannelsLists {
|
||||||
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
.frame(width: Constants.sidebarChannelThumbnailSize, height: Constants.sidebarChannelThumbnailSize)
|
||||||
|
|
||||||
Text(channel.name)
|
Text(channel.name)
|
||||||
} else {
|
} else {
|
||||||
Label(channel.name, systemImage: RecentsModel.symbolSystemImage(channel.name))
|
Label(channel.name, systemImage: RecentsModel.symbolSystemImage(channel.name))
|
||||||
@ -26,14 +32,10 @@ struct AppSidebarSubscriptions: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.backport
|
.lineLimit(1)
|
||||||
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedByChannelText(channel) : nil)
|
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedByChannelText(channel) : nil)
|
||||||
}
|
}
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
if subscriptions.isSubscribing(channel.id) {
|
|
||||||
toggleWatchedButton(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
Button("Unsubscribe") {
|
Button("Unsubscribe") {
|
||||||
navigation.presentUnsubscribeAlert(channel, subscriptions: subscriptions)
|
navigation.presentUnsubscribeAlert(channel, subscriptions: subscriptions)
|
||||||
}
|
}
|
||||||
@ -43,29 +45,8 @@ struct AppSidebarSubscriptions: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder func toggleWatchedButton(_ channel: Channel) -> some View {
|
var channels: [Channel] {
|
||||||
if feed.canMarkChannelAsWatched(channel.id) {
|
keepChannelsWithUnwatchedFeedOnTop ? subscriptions.allByUnwatchedCount : subscriptions.all
|
||||||
markChannelAsWatchedButton(channel)
|
|
||||||
} else {
|
|
||||||
markChannelAsUnwatchedButton(channel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func markChannelAsWatchedButton(_ channel: Channel) -> some View {
|
|
||||||
Button {
|
|
||||||
feed.markChannelAsWatched(channel.id)
|
|
||||||
} label: {
|
|
||||||
Label("Mark channel feed as watched", systemImage: "checkmark.circle.fill")
|
|
||||||
}
|
|
||||||
.disabled(!feed.canMarkAllFeedAsWatched)
|
|
||||||
}
|
|
||||||
|
|
||||||
func markChannelAsUnwatchedButton(_ channel: Channel) -> some View {
|
|
||||||
Button {
|
|
||||||
feed.markChannelAsUnwatched(channel.id)
|
|
||||||
} label: {
|
|
||||||
Label("Mark channel feed as unwatched", systemImage: "checkmark.circle")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,6 @@ struct AppTabNavigation: View {
|
|||||||
.accessibility(label: Text("Subscriptions"))
|
.accessibility(label: Text("Subscriptions"))
|
||||||
}
|
}
|
||||||
.tag(TabSelection.subscriptions)
|
.tag(TabSelection.subscriptions)
|
||||||
.backport
|
|
||||||
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedText : nil)
|
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedText : nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,10 +131,6 @@ struct ContentView: View {
|
|||||||
|
|
||||||
NavigationModel.shared.presentingOpenVideos = false
|
NavigationModel.shared.presentingOpenVideos = false
|
||||||
}
|
}
|
||||||
.onOpenURL { url in
|
|
||||||
URLBookmarkModel.shared.saveBookmark(url)
|
|
||||||
OpenURLHandler(navigationStyle: navigationStyle).handle(url)
|
|
||||||
}
|
|
||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $navigation.presentingAddToPlaylist) {
|
EmptyView().sheet(isPresented: $navigation.presentingAddToPlaylist) {
|
||||||
AddToPlaylistView(video: navigation.videoToAddToPlaylist)
|
AddToPlaylistView(video: navigation.videoToAddToPlaylist)
|
||||||
@ -173,16 +169,6 @@ struct ContentView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var navigationStyle: NavigationStyle {
|
|
||||||
#if os(iOS)
|
|
||||||
return horizontalSizeClass == .compact ? .tab : .sidebar
|
|
||||||
#elseif os(tvOS)
|
|
||||||
return .tab
|
|
||||||
#else
|
|
||||||
return .sidebar
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder var videoPlayer: some View {
|
@ViewBuilder var videoPlayer: some View {
|
||||||
if player.presentingPlayer {
|
if player.presentingPlayer {
|
||||||
playerView
|
playerView
|
||||||
@ -199,7 +185,6 @@ struct ContentView: View {
|
|||||||
|
|
||||||
var playerView: some View {
|
var playerView: some View {
|
||||||
VideoPlayerView()
|
VideoPlayerView()
|
||||||
.environment(\.navigationStyle, navigationStyle)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,6 @@ struct Sidebar: View {
|
|||||||
Label("Subscriptions", systemImage: "star.circle")
|
Label("Subscriptions", systemImage: "star.circle")
|
||||||
.accessibility(label: Text("Subscriptions"))
|
.accessibility(label: Text("Subscriptions"))
|
||||||
}
|
}
|
||||||
.backport
|
|
||||||
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedText : nil)
|
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedText : nil)
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
playUnwatchedButton
|
playUnwatchedButton
|
||||||
@ -152,7 +151,8 @@ struct Sidebar: View {
|
|||||||
if case .recentlyOpened = selection {
|
if case .recentlyOpened = selection {
|
||||||
scrollView.scrollTo("recentlyOpened")
|
scrollView.scrollTo("recentlyOpened")
|
||||||
return
|
return
|
||||||
} else if case let .playlist(id) = selection {
|
}
|
||||||
|
if case let .playlist(id) = selection {
|
||||||
scrollView.scrollTo(id)
|
scrollView.scrollTo(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ final class AppleAVPlayerViewController: UIViewController {
|
|||||||
infoViewControllers.append(infoViewController([.chapters], title: "Chapters"))
|
infoViewControllers.append(infoViewController([.chapters], title: "Chapters"))
|
||||||
infoViewControllers.append(infoViewController([.comments], title: "Comments"))
|
infoViewControllers.append(infoViewController([.comments], title: "Comments"))
|
||||||
|
|
||||||
var queueSections = [NowPlayingView.ViewSection.playingNext]
|
let queueSections = [NowPlayingView.ViewSection.playingNext]
|
||||||
|
|
||||||
infoViewControllers.append(contentsOf: [
|
infoViewControllers.append(contentsOf: [
|
||||||
infoViewController([.related], title: "Related"),
|
infoViewController([.related], title: "Related"),
|
||||||
|
@ -7,19 +7,8 @@ struct ControlBackgroundModifier: ViewModifier {
|
|||||||
|
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
if enabled {
|
if enabled {
|
||||||
if #available(iOS 15, macOS 12, *) {
|
content
|
||||||
content
|
|
||||||
.background(.thinMaterial)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
#if os(macOS)
|
|
||||||
.background(VisualEffectBlur(material: .hudWindow))
|
|
||||||
#elseif os(iOS)
|
|
||||||
.background(VisualEffectBlur(blurStyle: .systemThinMaterial).edgesIgnoringSafeArea(edgesIgnoringSafeArea))
|
|
||||||
#else
|
|
||||||
.background(.thinMaterial)
|
.background(.thinMaterial)
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,8 @@ struct OpeningStream: View {
|
|||||||
if let selection = player.streamSelection {
|
if let selection = player.streamSelection {
|
||||||
if selection.isLocal {
|
if selection.isLocal {
|
||||||
return "Opening file...".localized()
|
return "Opening file...".localized()
|
||||||
} else {
|
|
||||||
return String(format: "Opening %@ stream...".localized(), selection.shortQuality)
|
|
||||||
}
|
}
|
||||||
|
return String(format: "Opening %@ stream...".localized(), selection.shortQuality)
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Loading streams...".localized()
|
return "Loading streams...".localized()
|
||||||
|
@ -193,8 +193,11 @@ struct PlayerControls: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.onChange(of: model.presentingControls) { newValue in
|
.onChange(of: model.presentingControls) { newValue in
|
||||||
if newValue { focusedField = .play }
|
if newValue {
|
||||||
else { focusedField = nil }
|
focusedField = .play
|
||||||
|
} else {
|
||||||
|
focusedField = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: focusedField) { _ in model.resetTimer() }
|
.onChange(of: focusedField) { _ in model.resetTimer() }
|
||||||
#else
|
#else
|
||||||
@ -252,8 +255,6 @@ struct PlayerControls: View {
|
|||||||
{
|
{
|
||||||
ThumbnailView(url: url)
|
ThumbnailView(url: url)
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
.transition(.opacity)
|
|
||||||
.animation(.default)
|
|
||||||
} else if player.videoForDisplay == nil {
|
} else if player.videoForDisplay == nil {
|
||||||
Color.black
|
Color.black
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ struct TVControls: UIViewRepresentable {
|
|||||||
|
|
||||||
func updateUIView(_: UIView, context _: Context) {}
|
func updateUIView(_: UIView, context _: Context) {}
|
||||||
|
|
||||||
func makeCoordinator() -> TVControls.Coordinator {
|
func makeCoordinator() -> Self.Coordinator {
|
||||||
Coordinator(controlsArea)
|
Coordinator(controlsArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,9 @@ struct TimelineView: View {
|
|||||||
|
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
}
|
}
|
||||||
|
#if os(tvOS)
|
||||||
.frame(maxHeight: 300, alignment: .bottom)
|
.frame(maxHeight: 300, alignment: .bottom)
|
||||||
|
#endif
|
||||||
.offset(x: thumbTooltipOffset)
|
.offset(x: thumbTooltipOffset)
|
||||||
.overlay(GeometryReader { proxy in
|
.overlay(GeometryReader { proxy in
|
||||||
Color.clear
|
Color.clear
|
||||||
@ -114,8 +116,9 @@ struct TimelineView: View {
|
|||||||
tooltipSize = proxy.size
|
tooltipSize = proxy.size
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
#if os(tvOS)
|
||||||
.frame(height: 80)
|
.frame(height: 80)
|
||||||
|
#endif
|
||||||
.opacity(dragging ? 1 : 0)
|
.opacity(dragging ? 1 : 0)
|
||||||
.animation(.easeOut, value: thumbTooltipOffset)
|
.animation(.easeOut, value: thumbTooltipOffset)
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
@ -161,14 +164,6 @@ struct TimelineView: View {
|
|||||||
self.size = size
|
self.size = size
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.frame(maxHeight: playerControlsLayout.timelineHeight)
|
|
||||||
#if !os(tvOS)
|
|
||||||
.gesture(DragGesture(minimumDistance: 0).onEnded { value in
|
|
||||||
let target = (value.location.x / size.width) * units
|
|
||||||
self.playerTime.currentTime = .secondsInDefaultTimescale(target)
|
|
||||||
player.backend.seek(to: target, seekType: .userInteracted)
|
|
||||||
})
|
|
||||||
#endif
|
|
||||||
|
|
||||||
durationView
|
durationView
|
||||||
.shadow(radius: 3)
|
.shadow(radius: 3)
|
||||||
@ -177,8 +172,14 @@ struct TimelineView: View {
|
|||||||
.frame(minWidth: 30, alignment: .trailing)
|
.frame(minWidth: 30, alignment: .trailing)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
|
||||||
.highPriorityGesture(
|
.font(.system(size: playerControlsLayout.timeFontSize).monospacedDigit())
|
||||||
|
.zIndex(2)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
#if !os(tvOS)
|
||||||
|
.gesture(
|
||||||
DragGesture(minimumDistance: 5, coordinateSpace: .global)
|
DragGesture(minimumDistance: 5, coordinateSpace: .global)
|
||||||
.onChanged { value in
|
.onChanged { value in
|
||||||
if !dragging {
|
if !dragging {
|
||||||
@ -210,11 +211,7 @@ struct TimelineView: View {
|
|||||||
controls.resetTimer()
|
controls.resetTimer()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
.font(.system(size: playerControlsLayout.timeFontSize).monospacedDigit())
|
|
||||||
.zIndex(2)
|
|
||||||
.foregroundColor(.white)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder var durationView: some View {
|
@ViewBuilder var durationView: some View {
|
||||||
|
@ -70,17 +70,15 @@ struct PlayerBackendView: View {
|
|||||||
|
|
||||||
if UIDevice.current.userInterfaceIdiom != .pad {
|
if UIDevice.current.userInterfaceIdiom != .pad {
|
||||||
return verticalSizeClass == .compact ? safeAreaModel.safeArea.top : 0
|
return verticalSizeClass == .compact ? safeAreaModel.safeArea.top : 0
|
||||||
} else {
|
|
||||||
return safeAreaModel.safeArea.top.isZero ? safeAreaModel.safeArea.bottom : safeAreaModel.safeArea.top
|
|
||||||
}
|
}
|
||||||
|
return safeAreaModel.safeArea.top.isZero ? safeAreaModel.safeArea.bottom : safeAreaModel.safeArea.top
|
||||||
}
|
}
|
||||||
|
|
||||||
var controlsBottomPadding: Double {
|
var controlsBottomPadding: Double {
|
||||||
if UIDevice.current.userInterfaceIdiom != .pad {
|
if UIDevice.current.userInterfaceIdiom != .pad {
|
||||||
return player.playingFullScreen || verticalSizeClass == .compact ? safeAreaModel.safeArea.bottom : 0
|
return player.playingFullScreen || verticalSizeClass == .compact ? safeAreaModel.safeArea.bottom : 0
|
||||||
} else {
|
|
||||||
return player.playingFullScreen ? safeAreaModel.safeArea.bottom : 0
|
|
||||||
}
|
}
|
||||||
|
return player.playingFullScreen ? safeAreaModel.safeArea.bottom : 0
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -18,8 +18,9 @@ struct RelatedView: View {
|
|||||||
|
|
||||||
Color.clear.padding(.bottom, 50)
|
Color.clear.padding(.bottom, 50)
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
.backport
|
#if os(iOS)
|
||||||
.listRowSeparator(false)
|
.listRowSeparator(.hidden)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,25 +219,17 @@ struct CommentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var commentText: some View {
|
private var commentText: some View {
|
||||||
Group {
|
Text(comment.text)
|
||||||
let text = Text(comment.text)
|
#if !os(tvOS)
|
||||||
#if os(macOS)
|
.textSelection(.enabled)
|
||||||
.font(.system(size: 14))
|
#endif
|
||||||
#elseif os(iOS)
|
#if os(macOS)
|
||||||
.font(.system(size: 15))
|
.font(.system(size: 14))
|
||||||
#endif
|
#elseif os(iOS)
|
||||||
.lineSpacing(3)
|
.font(.system(size: 15))
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
#endif
|
||||||
|
.lineSpacing(3)
|
||||||
if #available(iOS 15.0, macOS 12.0, *) {
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
text
|
|
||||||
#if !os(tvOS)
|
|
||||||
.textSelection(.enabled)
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openChannelAction() {
|
private func openChannelAction() {
|
||||||
|
@ -32,13 +32,8 @@ struct CommentsView: View {
|
|||||||
|
|
||||||
struct CommentsView_Previews: PreviewProvider {
|
struct CommentsView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
|
||||||
CommentsView()
|
|
||||||
.previewInterfaceOrientation(.landscapeRight)
|
|
||||||
.injectFixtureEnvironmentObjects()
|
|
||||||
}
|
|
||||||
|
|
||||||
CommentsView()
|
CommentsView()
|
||||||
|
.previewInterfaceOrientation(.landscapeRight)
|
||||||
.injectFixtureEnvironmentObjects()
|
.injectFixtureEnvironmentObjects()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,15 +79,10 @@ struct InspectorView: View {
|
|||||||
Text(detail.localized())
|
Text(detail.localized())
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
Spacer()
|
Spacer()
|
||||||
let value = Text(value).lineLimit(1)
|
Text(value).lineLimit(1)
|
||||||
if #available(iOS 15.0, macOS 12.0, *) {
|
#if !os(tvOS)
|
||||||
value
|
|
||||||
#if !os(tvOS)
|
|
||||||
.textSelection(.enabled)
|
.textSelection(.enabled)
|
||||||
#endif
|
#endif
|
||||||
} else {
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,9 @@ struct PlayerQueueView: View {
|
|||||||
#endif
|
#endif
|
||||||
Color.clear.padding(.bottom, 50)
|
Color.clear.padding(.bottom, 50)
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
.backport
|
#if os(iOS)
|
||||||
.listRowSeparator(false)
|
.listRowSeparator(.hidden)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
.environment(\.inNavigationView, false)
|
.environment(\.inNavigationView, false)
|
||||||
}
|
}
|
||||||
|
@ -59,23 +59,15 @@ struct VideoDescription: View {
|
|||||||
|
|
||||||
@ViewBuilder var textDescription: some View {
|
@ViewBuilder var textDescription: some View {
|
||||||
#if !os(iOS)
|
#if !os(iOS)
|
||||||
Group {
|
Text(description)
|
||||||
if #available(macOS 12, *) {
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
Text(description)
|
.lineLimit(shouldExpand ? 500 : Self.collapsedLines)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
#if !os(tvOS)
|
||||||
.lineLimit(shouldExpand ? 500 : Self.collapsedLines)
|
.textSelection(.enabled)
|
||||||
#if !os(tvOS)
|
#endif
|
||||||
.textSelection(.enabled)
|
.multilineTextAlignment(.leading)
|
||||||
#endif
|
.font(.system(size: 14))
|
||||||
} else {
|
.lineSpacing(3)
|
||||||
Text(description)
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
.lineLimit(shouldExpand ? 500 : Self.collapsedLines)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.multilineTextAlignment(.leading)
|
|
||||||
.font(.system(size: 14))
|
|
||||||
.lineSpacing(3)
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +169,8 @@ struct VideoDescription: View {
|
|||||||
{
|
{
|
||||||
player.backend.seek(to: Double(time), seekType: .userInteracted)
|
player.backend.seek(to: Double(time), seekType: .userInteracted)
|
||||||
return
|
return
|
||||||
} else if destination != nil {
|
}
|
||||||
|
if destination != nil {
|
||||||
urlToOpen = yatteeURL
|
urlToOpen = yatteeURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ struct VideoDetails: View {
|
|||||||
|
|
||||||
struct ChannelView: View {
|
struct ChannelView: View {
|
||||||
@ObservedObject private var model = PlayerModel.shared
|
@ObservedObject private var model = PlayerModel.shared
|
||||||
|
@Binding var detailsVisibility: Bool
|
||||||
|
|
||||||
var video: Video? { model.videoForDisplay }
|
var video: Video? { model.videoForDisplay }
|
||||||
|
|
||||||
@ -33,14 +34,19 @@ struct VideoDetails: View {
|
|||||||
guard let channel = video?.channel else { return }
|
guard let channel = video?.channel else { return }
|
||||||
NavigationModel.shared.openChannel(channel, navigationStyle: .sidebar)
|
NavigationModel.shared.openChannel(channel, navigationStyle: .sidebar)
|
||||||
} label: {
|
} label: {
|
||||||
ChannelAvatarView(
|
if detailsVisibility {
|
||||||
channel: video?.channel,
|
ChannelAvatarView(
|
||||||
video: video
|
channel: video?.channel,
|
||||||
)
|
video: video
|
||||||
.frame(maxWidth: 40, maxHeight: 40)
|
)
|
||||||
.padding(.trailing, 5)
|
} else {
|
||||||
|
Circle()
|
||||||
|
.foregroundColor(Color(white: 0.6).opacity(0.5))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
.padding(.trailing, 5)
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
HStack {
|
HStack {
|
||||||
@ -56,18 +62,14 @@ struct VideoDetails: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let video, !video.isLocal {
|
if let video, !video.isLocal {
|
||||||
Group {
|
HStack(spacing: 2) {
|
||||||
Text("•")
|
Image(systemName: "person.2.fill")
|
||||||
|
|
||||||
HStack(spacing: 2) {
|
if let channel = model.videoForDisplay?.channel {
|
||||||
Image(systemName: "person.2.fill")
|
if let subscriptions = channel.subscriptionsString {
|
||||||
|
Text(subscriptions)
|
||||||
if let channel = model.videoForDisplay?.channel {
|
} else {
|
||||||
if let subscriptions = channel.subscriptionsString {
|
Text("1234").redacted(reason: .placeholder)
|
||||||
Text(subscriptions)
|
|
||||||
} else {
|
|
||||||
Text("1234").redacted(reason: .placeholder)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,8 +96,6 @@ struct VideoDetails: View {
|
|||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
publishedDateSection
|
publishedDateSection
|
||||||
|
|
||||||
Text("•")
|
|
||||||
|
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
if model.videoBeingOpened != nil || video?.viewsCount != nil {
|
if model.videoBeingOpened != nil || video?.viewsCount != nil {
|
||||||
Image(systemName: "eye")
|
Image(systemName: "eye")
|
||||||
@ -194,7 +194,7 @@ struct VideoDetails: View {
|
|||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
TitleView()
|
TitleView()
|
||||||
if video != nil, !video!.isLocal {
|
if video != nil, !video!.isLocal {
|
||||||
ChannelView()
|
ChannelView(detailsVisibility: $detailsVisibility)
|
||||||
.layoutPriority(1)
|
.layoutPriority(1)
|
||||||
.padding(.bottom, 6)
|
.padding(.bottom, 6)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ struct VideoPlayerSizeModifier: ViewModifier {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var ratio: CGFloat? {
|
var ratio: CGFloat? { // swiftlint:disable:this no_cgfloat
|
||||||
fullScreen ? detailsHiddenInFullScreen ? nil : usedAspectRatio : usedAspectRatio
|
fullScreen ? detailsHiddenInFullScreen ? nil : usedAspectRatio : usedAspectRatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,9 +57,9 @@ struct VideoPlayerSizeModifier: ViewModifier {
|
|||||||
guard !fullScreen else {
|
guard !fullScreen else {
|
||||||
if detailsHiddenInFullScreen {
|
if detailsHiddenInFullScreen {
|
||||||
return geometry.size.height
|
return geometry.size.height
|
||||||
} else {
|
|
||||||
return geometry.size.width / usedAspectRatio
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return geometry.size.width / usedAspectRatio
|
||||||
}
|
}
|
||||||
|
|
||||||
return max(geometry.size.height - VideoPlayerView.defaultMinimumHeightLeft, 0)
|
return max(geometry.size.height - VideoPlayerView.defaultMinimumHeightLeft, 0)
|
||||||
|
@ -274,7 +274,11 @@ struct VideoPlayerView: View {
|
|||||||
)
|
)
|
||||||
.onHover { hovering in
|
.onHover { hovering in
|
||||||
hoveringPlayer = hovering
|
hoveringPlayer = hovering
|
||||||
hovering ? player.controls.show() : player.controls.hide()
|
if hovering {
|
||||||
|
player.controls.show()
|
||||||
|
} else {
|
||||||
|
player.controls.hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.gesture(player.controls.presentingOverlays ? nil : playerDragGesture)
|
.gesture(player.controls.presentingOverlays ? nil : playerDragGesture)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ -290,9 +294,6 @@ struct VideoPlayerView: View {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.background(Color.black)
|
|
||||||
|
|
||||||
if !detailsHiddenInFullScreen {
|
if !detailsHiddenInFullScreen {
|
||||||
VideoDetails(
|
VideoDetails(
|
||||||
video: player.videoForDisplay,
|
video: player.videoForDisplay,
|
||||||
|
@ -91,13 +91,6 @@ struct PlaylistsView: View {
|
|||||||
loadResource()
|
loadResource()
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.refreshControl { refreshControl in
|
|
||||||
model.load(force: true) {
|
|
||||||
model.reloadPlaylists.toggle()
|
|
||||||
refreshControl.endRefreshing()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.backport
|
|
||||||
.refreshable {
|
.refreshable {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
model.load(force: true) { model.reloadPlaylists.toggle() }
|
model.load(force: true) { model.reloadPlaylists.toggle() }
|
||||||
|
@ -2,7 +2,6 @@ import Introspect
|
|||||||
import Repeat
|
import Repeat
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@available(iOS 15.0, macOS 12, *)
|
|
||||||
struct FocusableSearchTextField: View {
|
struct FocusableSearchTextField: View {
|
||||||
@ObservedObject private var state = SearchModel.shared
|
@ObservedObject private var state = SearchModel.shared
|
||||||
|
|
||||||
|
@ -95,11 +95,7 @@ struct SearchView: View {
|
|||||||
filtersMenu
|
filtersMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
if #available(macOS 12, *) {
|
FocusableSearchTextField()
|
||||||
FocusableSearchTextField()
|
|
||||||
} else {
|
|
||||||
SearchTextField()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -179,11 +175,7 @@ struct SearchView: View {
|
|||||||
searchMenu
|
searchMenu
|
||||||
}
|
}
|
||||||
ToolbarItem(placement: .principal) {
|
ToolbarItem(placement: .principal) {
|
||||||
if #available(iOS 15, *) {
|
FocusableSearchTextField()
|
||||||
FocusableSearchTextField()
|
|
||||||
} else {
|
|
||||||
SearchTextField()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
@ -47,16 +47,16 @@ struct AccountValidationStatus: View {
|
|||||||
var validationStatusSystemImage: String {
|
var validationStatusSystemImage: String {
|
||||||
if isValidating {
|
if isValidating {
|
||||||
return "bolt.horizontal.fill"
|
return "bolt.horizontal.fill"
|
||||||
} else {
|
|
||||||
return isValid ? "checkmark.circle.fill" : "xmark.circle.fill"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isValid ? "checkmark.circle.fill" : "xmark.circle.fill"
|
||||||
}
|
}
|
||||||
|
|
||||||
var validationStatusColor: Color {
|
var validationStatusColor: Color {
|
||||||
if isValidating {
|
if isValidating {
|
||||||
return .accentColor
|
return .accentColor
|
||||||
} else {
|
|
||||||
return isValid ? .green : .red
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isValid ? .green : .red
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ struct BrowsingSettings: View {
|
|||||||
@Default(.playerButtonIsExpanded) private var playerButtonIsExpanded
|
@Default(.playerButtonIsExpanded) private var playerButtonIsExpanded
|
||||||
@Default(.playerBarMaxWidth) private var playerBarMaxWidth
|
@Default(.playerBarMaxWidth) private var playerBarMaxWidth
|
||||||
@Default(.expandChannelDescription) private var expandChannelDescription
|
@Default(.expandChannelDescription) private var expandChannelDescription
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
@Default(.showChannelAvatarInVideosListing) private var showChannelAvatarInVideosListing
|
||||||
|
|
||||||
@ObservedObject private var accounts = AccountsModel.shared
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
|
|
||||||
@ -186,6 +188,9 @@ struct BrowsingSettings: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toggle("Keep channels with unwatched videos on top of subscriptions list", isOn: $keepChannelsWithUnwatchedFeedOnTop)
|
Toggle("Keep channels with unwatched videos on top of subscriptions list", isOn: $keepChannelsWithUnwatchedFeedOnTop)
|
||||||
|
|
||||||
|
Toggle("Show channel avatars in channels lists", isOn: $showChannelAvatarInChannelsLists)
|
||||||
|
Toggle("Show channel avatars in videos lists", isOn: $showChannelAvatarInVideosListing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ struct QualityProfileForm: View {
|
|||||||
|
|
||||||
@ViewBuilder var formatsPicker: some View {
|
@ViewBuilder var formatsPicker: some View {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
let list = ForEach(QualityProfile.Format.allCases, id: \.self) { format in
|
ForEach(QualityProfile.Format.allCases, id: \.self) { format in
|
||||||
MultiselectRow(
|
MultiselectRow(
|
||||||
title: format.description,
|
title: format.description,
|
||||||
selected: isFormatSelected(format),
|
selected: isFormatSelected(format),
|
||||||
@ -209,16 +209,8 @@ struct QualityProfileForm: View {
|
|||||||
toggleFormat(format, value: value)
|
toggleFormat(format, value: value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
|
|
||||||
Group {
|
|
||||||
if #available(macOS 12.0, *) {
|
|
||||||
list
|
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
|
||||||
} else {
|
|
||||||
list
|
|
||||||
.listStyle(.inset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer()
|
Spacer()
|
||||||
#else
|
#else
|
||||||
ForEach(QualityProfile.Format.allCases, id: \.self) { format in
|
ForEach(QualityProfile.Format.allCases, id: \.self) { format in
|
||||||
|
@ -175,24 +175,14 @@ struct QualitySettings: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if #available(macOS 12.0, *) {
|
#if os(macOS)
|
||||||
#if os(macOS)
|
List {
|
||||||
List {
|
|
||||||
list
|
|
||||||
}
|
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
|
||||||
#else
|
|
||||||
list
|
list
|
||||||
#endif
|
}
|
||||||
} else {
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
#if os(macOS)
|
#else
|
||||||
List {
|
list
|
||||||
list
|
#endif
|
||||||
}
|
|
||||||
#else
|
|
||||||
list
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ struct SettingsView: View {
|
|||||||
private var windowHeight: Double {
|
private var windowHeight: Double {
|
||||||
switch selection {
|
switch selection {
|
||||||
case .browsing:
|
case .browsing:
|
||||||
return 720
|
return 800
|
||||||
case .player:
|
case .player:
|
||||||
return 480
|
return 480
|
||||||
case .controls:
|
case .controls:
|
||||||
|
@ -50,15 +50,8 @@ struct SponsorBlockSettings: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Group {
|
list
|
||||||
if #available(macOS 12.0, *) {
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
list
|
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
|
||||||
} else {
|
|
||||||
list
|
|
||||||
.listStyle(.inset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer()
|
Spacer()
|
||||||
#else
|
#else
|
||||||
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
ForEach(SponsorBlockAPI.categories, id: \.self) { category in
|
||||||
|
@ -12,6 +12,7 @@ struct ChannelsView: View {
|
|||||||
@Default(.showCacheStatus) private var showCacheStatus
|
@Default(.showCacheStatus) private var showCacheStatus
|
||||||
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
@Default(.showUnwatchedFeedBadges) private var showUnwatchedFeedBadges
|
||||||
@Default(.keepChannelsWithUnwatchedFeedOnTop) private var keepChannelsWithUnwatchedFeedOnTop
|
@Default(.keepChannelsWithUnwatchedFeedOnTop) private var keepChannelsWithUnwatchedFeedOnTop
|
||||||
|
@Default(.showChannelAvatarInChannelsLists) private var showChannelAvatarInChannelsLists
|
||||||
|
|
||||||
@State private var channelLinkActive = false
|
@State private var channelLinkActive = false
|
||||||
@State private var channelForLink: Channel?
|
@State private var channelForLink: Channel?
|
||||||
@ -21,10 +22,9 @@ struct ChannelsView: View {
|
|||||||
Section(header: header) {
|
Section(header: header) {
|
||||||
ForEach(channels) { channel in
|
ForEach(channels) { channel in
|
||||||
let label = HStack {
|
let label = HStack {
|
||||||
if let url = channel.thumbnailURLOrCached {
|
if showChannelAvatarInChannelsLists {
|
||||||
ThumbnailView(url: url)
|
ChannelAvatarView(channel: channel, subscribedBadge: false)
|
||||||
.frame(width: 35, height: 35)
|
.frame(width: 35, height: 35)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 35))
|
|
||||||
} else {
|
} else {
|
||||||
Image(systemName: RecentsModel.symbolSystemImage(channel.name))
|
Image(systemName: RecentsModel.symbolSystemImage(channel.name))
|
||||||
.imageScale(.large)
|
.imageScale(.large)
|
||||||
@ -34,8 +34,9 @@ struct ChannelsView: View {
|
|||||||
Text(channel.name)
|
Text(channel.name)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
}
|
}
|
||||||
.backport
|
#if !os(tvOS)
|
||||||
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedByChannelText(channel) : nil)
|
.badge(showUnwatchedFeedBadges ? feedCount.unwatchedByChannelText(channel) : nil)
|
||||||
|
#endif
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
@ -73,8 +74,9 @@ struct ChannelsView: View {
|
|||||||
|
|
||||||
Color.clear.padding(.bottom, 50)
|
Color.clear.padding(.bottom, 50)
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
.backport
|
#if os(iOS)
|
||||||
.listRowSeparator(false)
|
.listRowSeparator(.hidden)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
@ -89,12 +91,6 @@ struct ChannelsView: View {
|
|||||||
subscriptions.load(force: true)
|
subscriptions.load(force: true)
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.refreshControl { refreshControl in
|
|
||||||
subscriptions.load(force: true) {
|
|
||||||
refreshControl.endRefreshing()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.backport
|
|
||||||
.refreshable {
|
.refreshable {
|
||||||
await subscriptions.load(force: true)
|
await subscriptions.load(force: true)
|
||||||
}
|
}
|
||||||
|
@ -22,18 +22,12 @@ struct FeedView: View {
|
|||||||
feed.loadResources()
|
feed.loadResources()
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.refreshControl { refreshControl in
|
|
||||||
feed.loadResources(force: true) {
|
|
||||||
refreshControl.endRefreshing()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.backport
|
|
||||||
.refreshable {
|
.refreshable {
|
||||||
await feed.loadResources(force: true)
|
await feed.loadResources(force: true)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.background(
|
.background(
|
||||||
Button("Refresh") {
|
Button("Refresh") {
|
||||||
feed.loadResources(force: true)
|
feed.loadResources(force: true)
|
||||||
}
|
}
|
||||||
@ -42,8 +36,8 @@ struct FeedView: View {
|
|||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||||
feed.loadResources()
|
feed.loadResources()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,7 @@ struct TrendingCountry: View {
|
|||||||
VStack {
|
VStack {
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
HStack {
|
HStack {
|
||||||
if #available(iOS 15.0, macOS 12.0, *) {
|
TextField("Country", text: $query, prompt: Text(Self.prompt))
|
||||||
TextField("Country", text: $query, prompt: Text(Self.prompt))
|
|
||||||
} else {
|
|
||||||
TextField(Self.prompt, text: $query)
|
|
||||||
}
|
|
||||||
|
|
||||||
Button("Done") { selectCountryAndDismiss() }
|
Button("Done") { selectCountryAndDismiss() }
|
||||||
.keyboardShortcut(.defaultAction)
|
.keyboardShortcut(.defaultAction)
|
||||||
@ -57,12 +53,8 @@ struct TrendingCountry: View {
|
|||||||
|
|
||||||
return Group {
|
return Group {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
if #available(macOS 12.0, *) {
|
list
|
||||||
list
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
|
||||||
} else {
|
|
||||||
list
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
list
|
list
|
||||||
#endif
|
#endif
|
||||||
|
@ -95,12 +95,7 @@ struct TrendingView: View {
|
|||||||
.navigationTitle("Trending")
|
.navigationTitle("Trending")
|
||||||
#endif
|
#endif
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.refreshControl { refreshControl in
|
|
||||||
resource.load().onCompletion { _ in
|
|
||||||
refreshControl.endRefreshing()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.backport
|
|
||||||
.refreshable {
|
.refreshable {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
resource.load()
|
resource.load()
|
||||||
|
@ -41,9 +41,11 @@ struct URLParser {
|
|||||||
|
|
||||||
if hasAnyOfPrefixes(path, Self.prefixes[.playlist]!) || queryItemValue("v") == "playlist" {
|
if hasAnyOfPrefixes(path, Self.prefixes[.playlist]!) || queryItemValue("v") == "playlist" {
|
||||||
return .playlist
|
return .playlist
|
||||||
} else if hasAnyOfPrefixes(path, Self.prefixes[.channel]!) {
|
}
|
||||||
|
if hasAnyOfPrefixes(path, Self.prefixes[.channel]!) {
|
||||||
return .channel
|
return .channel
|
||||||
} else if hasAnyOfPrefixes(path, Self.prefixes[.search]!) {
|
}
|
||||||
|
if hasAnyOfPrefixes(path, Self.prefixes[.search]!) {
|
||||||
return .search
|
return .search
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ListView: View {
|
struct ListView: View {
|
||||||
|
@ -48,23 +48,19 @@ struct ThumbnailView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder var asyncImageIfAvailable: some View {
|
@ViewBuilder var asyncImageIfAvailable: some View {
|
||||||
if #available(iOS 15, macOS 12, *) {
|
CachedAsyncImage(url: url, urlCache: BaseCacheModel.imageCache, transaction: Transaction(animation: .default)) { phase in
|
||||||
CachedAsyncImage(url: url, urlCache: BaseCacheModel.imageCache) { phase in
|
switch phase {
|
||||||
switch phase {
|
case let .success(image):
|
||||||
case let .success(image):
|
image
|
||||||
image
|
.resizable()
|
||||||
.resizable()
|
case .failure:
|
||||||
case .failure:
|
placeholder.onAppear {
|
||||||
placeholder.onAppear {
|
guard let url else { return }
|
||||||
guard let url else { return }
|
thumbnails.insertUnloadable(url)
|
||||||
thumbnails.insertUnloadable(url)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
placeholder
|
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
placeholder
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
webImage
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ struct VideoBanner: View {
|
|||||||
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
||||||
@Default(.timeOnThumbnail) private var timeOnThumbnail
|
@Default(.timeOnThumbnail) private var timeOnThumbnail
|
||||||
@Default(.roundedThumbnails) private var roundedThumbnails
|
@Default(.roundedThumbnails) private var roundedThumbnails
|
||||||
|
@Default(.showChannelAvatarInVideosListing) private var showChannelAvatarInVideosListing
|
||||||
|
|
||||||
@Environment(\.inChannelView) private var inChannelView
|
@Environment(\.inChannelView) private var inChannelView
|
||||||
@Environment(\.inNavigationView) private var inNavigationView
|
@Environment(\.inNavigationView) private var inNavigationView
|
||||||
@ -85,10 +86,9 @@ struct VideoBanner: View {
|
|||||||
if !inChannelView, !video.isLocal || video.localStreamIsRemoteURL {
|
if !inChannelView, !video.isLocal || video.localStreamIsRemoteURL {
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
||||||
if let url = video.channel.thumbnailURLOrCached, video != .fixture {
|
if video != .fixture, showChannelAvatarInVideosListing {
|
||||||
ThumbnailView(url: url)
|
ChannelAvatarView(channel: video.channel)
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channelLabel
|
channelLabel
|
||||||
@ -253,11 +253,11 @@ struct VideoBanner: View {
|
|||||||
private var timeLabel: String? {
|
private var timeLabel: String? {
|
||||||
if let watch, let watchStoppedAtLabel, let videoDurationLabel, !watch.finished {
|
if let watch, let watchStoppedAtLabel, let videoDurationLabel, !watch.finished {
|
||||||
return "\(watchStoppedAtLabel) / \(videoDurationLabel)"
|
return "\(watchStoppedAtLabel) / \(videoDurationLabel)"
|
||||||
} else if let videoDurationLabel {
|
|
||||||
return videoDurationLabel
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
if let videoDurationLabel {
|
||||||
|
return videoDurationLabel
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder private var timeView: some View {
|
@ViewBuilder private var timeView: some View {
|
||||||
|
@ -24,6 +24,7 @@ struct VideoCell: View {
|
|||||||
@Default(.watchedVideoStyle) private var watchedVideoStyle
|
@Default(.watchedVideoStyle) private var watchedVideoStyle
|
||||||
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
@Default(.watchedVideoBadgeColor) private var watchedVideoBadgeColor
|
||||||
@Default(.watchedVideoPlayNowBehavior) private var watchedVideoPlayNowBehavior
|
@Default(.watchedVideoPlayNowBehavior) private var watchedVideoPlayNowBehavior
|
||||||
|
@Default(.showChannelAvatarInVideosListing) private var showChannelAvatarInVideosListing
|
||||||
|
|
||||||
private var navigation: NavigationModel { .shared }
|
private var navigation: NavigationModel { .shared }
|
||||||
private var player: PlayerModel { .shared }
|
private var player: PlayerModel { .shared }
|
||||||
@ -161,17 +162,22 @@ struct VideoCell: View {
|
|||||||
|
|
||||||
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
||||||
if !inChannelView,
|
if !inChannelView,
|
||||||
let url = video.channel.thumbnailURLOrCached,
|
showChannelAvatarInVideosListing,
|
||||||
video != .fixture
|
video != .fixture
|
||||||
{
|
{
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
ThumbnailView(url: url)
|
if showChannelAvatarInVideosListing {
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
ChannelAvatarView(channel: video.channel)
|
||||||
.clipShape(Circle())
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
|
} else {
|
||||||
|
channelLabel(badge: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !channelOnThumbnail, !inChannelView {
|
if !channelOnThumbnail,
|
||||||
|
!inChannelView
|
||||||
|
{
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
channelLabel(badge: false)
|
channelLabel(badge: false)
|
||||||
}
|
}
|
||||||
@ -264,12 +270,9 @@ struct VideoCell: View {
|
|||||||
if !channelOnThumbnail, !inChannelView {
|
if !channelOnThumbnail, !inChannelView {
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
HStack(spacing: Constants.channelDetailsStackSpacing) {
|
||||||
if let url = video.channel.thumbnailURLOrCached,
|
if video != .fixture, showChannelAvatarInVideosListing {
|
||||||
video != .fixture
|
ChannelAvatarView(channel: video.channel)
|
||||||
{
|
|
||||||
ThumbnailView(url: url)
|
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channelLabel(badge: false)
|
channelLabel(badge: false)
|
||||||
@ -295,9 +298,8 @@ struct VideoCell: View {
|
|||||||
video != .fixture
|
video != .fixture
|
||||||
{
|
{
|
||||||
ChannelLinkView(channel: video.channel) {
|
ChannelLinkView(channel: video.channel) {
|
||||||
ThumbnailView(url: url)
|
ChannelAvatarView(channel: video.channel)
|
||||||
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
.frame(width: Constants.channelThumbnailSize, height: Constants.channelThumbnailSize)
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import SwiftUI
|
|||||||
struct AccentButton: View {
|
struct AccentButton: View {
|
||||||
var text: String?
|
var text: String?
|
||||||
var imageSystemName: String?
|
var imageSystemName: String?
|
||||||
var maxWidth: CGFloat? = .infinity
|
var maxWidth: CGFloat? = .infinity // swiftlint:disable:this no_cgfloat
|
||||||
var bold = true
|
var bold = true
|
||||||
var verticalPadding = 10.0
|
var verticalPadding = 10.0
|
||||||
var horizontalPadding = 10.0
|
var horizontalPadding = 10.0
|
||||||
|
@ -167,6 +167,7 @@ struct ControlsBar: View {
|
|||||||
channel: model.videoForDisplay?.channel,
|
channel: model.videoForDisplay?.channel,
|
||||||
video: model.videoForDisplay
|
video: model.videoForDisplay
|
||||||
)
|
)
|
||||||
|
.id("channel-avatar-\(model.videoForDisplay?.id ?? "")")
|
||||||
.frame(width: barHeight - 10, height: barHeight - 10)
|
.frame(width: barHeight - 10, height: barHeight - 10)
|
||||||
}
|
}
|
||||||
.contextMenu { contextMenu }
|
.contextMenu { contextMenu }
|
||||||
@ -176,12 +177,13 @@ struct ControlsBar: View {
|
|||||||
channel: model.videoForDisplay?.channel,
|
channel: model.videoForDisplay?.channel,
|
||||||
video: model.videoForDisplay
|
video: model.videoForDisplay
|
||||||
)
|
)
|
||||||
|
.id("channel-avatar-\(model.videoForDisplay?.id ?? "")")
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.highPriorityGesture(playerButtonDoubleTapGesture != .nothing ? doubleTapGesture : nil)
|
.highPriorityGesture(playerButtonDoubleTapGesture != .nothing ? doubleTapGesture : nil)
|
||||||
.gesture(playerButtonSingleTapGesture != .nothing ? singleTapGesture : nil)
|
.gesture(playerButtonSingleTapGesture != .nothing ? singleTapGesture : nil)
|
||||||
#endif
|
#endif
|
||||||
.frame(width: barHeight - 10, height: barHeight - 10)
|
.frame(width: barHeight - 10, height: barHeight - 10)
|
||||||
.contextMenu { contextMenu }
|
.contextMenu { contextMenu }
|
||||||
}
|
}
|
||||||
|
|
||||||
if expansionState == .full {
|
if expansionState == .full {
|
||||||
|
@ -8,7 +8,7 @@ struct OpenSettingsButton: View {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let button = Button {
|
Button {
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ -20,13 +20,7 @@ struct OpenSettingsButton: View {
|
|||||||
Label("Open Settings", systemImage: "gearshape.2")
|
Label("Open Settings", systemImage: "gearshape.2")
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
|
||||||
button
|
|
||||||
.buttonStyle(.borderedProminent)
|
|
||||||
} else {
|
|
||||||
button
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,14 +47,6 @@ struct PopularView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.refreshControl { refreshControl in
|
|
||||||
resource?.load().onCompletion { _ in
|
|
||||||
refreshControl.endRefreshing()
|
|
||||||
}
|
|
||||||
.onFailure { self.error = $0 }
|
|
||||||
.onSuccess { _ in self.error = nil }
|
|
||||||
}
|
|
||||||
.backport
|
|
||||||
.refreshable {
|
.refreshable {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
resource?.load()
|
resource?.load()
|
||||||
@ -62,7 +54,7 @@ struct PopularView: View {
|
|||||||
.onSuccess { _ in self.error = nil }
|
.onSuccess { _ in self.error = nil }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(RefreshControl.navigationBarTitleDisplayMode)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
#endif
|
#endif
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
@ -281,11 +281,7 @@ struct VideoContextMenuView: View {
|
|||||||
let label = Label("Remove…", systemImage: "trash.fill")
|
let label = Label("Remove…", systemImage: "trash.fill")
|
||||||
.foregroundColor(Color("AppRedColor"))
|
.foregroundColor(Color("AppRedColor"))
|
||||||
|
|
||||||
if #available(iOS 15, macOS 12, *) {
|
Button(role: .destructive, action: action) { label }
|
||||||
Button(role: .destructive, action: action) { label }
|
|
||||||
} else {
|
|
||||||
Button(action: action) { label }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ struct YatteeApp: App {
|
|||||||
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||||
#elseif os(iOS)
|
#elseif os(iOS)
|
||||||
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||||
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@State private var configured = false
|
@State private var configured = false
|
||||||
@ -55,6 +56,7 @@ struct YatteeApp: App {
|
|||||||
ContentView()
|
ContentView()
|
||||||
.onAppear(perform: configure)
|
.onAppear(perform: configure)
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
|
.environment(\.navigationStyle, navigationStyle)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.background(
|
.background(
|
||||||
HostingWindowFinder { window in
|
HostingWindowFinder { window in
|
||||||
@ -76,6 +78,12 @@ struct YatteeApp: App {
|
|||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"]))
|
.handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"]))
|
||||||
#endif
|
#endif
|
||||||
|
#if !os(tvOS)
|
||||||
|
.onOpenURL { url in
|
||||||
|
URLBookmarkModel.shared.saveBookmark(url)
|
||||||
|
OpenURLHandler(navigationStyle: navigationStyle).handle(url)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.handlesExternalEvents(matching: Set(["*"]))
|
.handlesExternalEvents(matching: Set(["*"]))
|
||||||
@ -98,7 +106,7 @@ struct YatteeApp: App {
|
|||||||
HostingWindowFinder { window in
|
HostingWindowFinder { window in
|
||||||
Windows.playerWindow = window
|
Windows.playerWindow = window
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
NotificationCenter.default.addObserver( // swiftlint:disable:this discarded_notification_center_observer
|
||||||
forName: NSWindow.willExitFullScreenNotification,
|
forName: NSWindow.willExitFullScreenNotification,
|
||||||
object: window,
|
object: window,
|
||||||
queue: OperationQueue.main
|
queue: OperationQueue.main
|
||||||
@ -114,6 +122,10 @@ struct YatteeApp: App {
|
|||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environment(\.navigationStyle, .sidebar)
|
.environment(\.navigationStyle, .sidebar)
|
||||||
.handlesExternalEvents(preferring: Set(["player", "*"]), allowing: Set(["player", "*"]))
|
.handlesExternalEvents(preferring: Set(["player", "*"]), allowing: Set(["player", "*"]))
|
||||||
|
.onOpenURL { url in
|
||||||
|
URLBookmarkModel.shared.saveBookmark(url)
|
||||||
|
OpenURLHandler(navigationStyle: navigationStyle).handle(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.handlesExternalEvents(matching: Set(["player", "*"]))
|
.handlesExternalEvents(matching: Set(["player", "*"]))
|
||||||
|
|
||||||
@ -200,4 +212,14 @@ struct YatteeApp: App {
|
|||||||
|
|
||||||
Defaults[.homeHistoryItems] = -1
|
Defaults[.homeHistoryItems] = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var navigationStyle: NavigationStyle {
|
||||||
|
#if os(iOS)
|
||||||
|
return horizontalSizeClass == .compact ? .tab : .sidebar
|
||||||
|
#elseif os(tvOS)
|
||||||
|
return .tab
|
||||||
|
#else
|
||||||
|
return .sidebar
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,3 +593,5 @@
|
|||||||
"Show video context menu options to force selected backend" = "Show video context menu options to force selected backend";
|
"Show video context menu options to force selected backend" = "Show video context menu options to force selected backend";
|
||||||
"Play Now in MPV" = "Play Now in MPV";
|
"Play Now in MPV" = "Play Now in MPV";
|
||||||
"Play Now in AVPlayer" = "Play Now in AVPlayer";
|
"Play Now in AVPlayer" = "Play Now in AVPlayer";
|
||||||
|
"Show channel avatars in videos lists" = "Show channel avatars in videos lists";
|
||||||
|
"Show channel avatars in channels lists" = "Show channel avatars in channels lists";
|
||||||
|
@ -177,7 +177,7 @@
|
|||||||
"When partially watched video is played" = "一部視聴済みの動画の再生時";
|
"When partially watched video is played" = "一部視聴済みの動画の再生時";
|
||||||
|
|
||||||
/* Selected video was played on given date */
|
/* Selected video was played on given date */
|
||||||
"Watched %@" = "視聴日 %@";
|
"Watched %@" = "前回の視聴 %@";
|
||||||
"Welcome" = "ようこそ";
|
"Welcome" = "ようこそ";
|
||||||
"Yattee" = "Yattee";
|
"Yattee" = "Yattee";
|
||||||
"Yattee %@ (build %@)" = "Yattee %@ (ビルド %@)";
|
"Yattee %@ (build %@)" = "Yattee %@ (ビルド %@)";
|
||||||
@ -531,7 +531,7 @@
|
|||||||
"Switch to public locations" = "公開された場所に切り替え";
|
"Switch to public locations" = "公開された場所に切り替え";
|
||||||
"Explicit reminders to like, subscribe or interact with them on any paid or free platform(s) (e.g. click on a video)." = "有料/無料のプラットフォームかを問わず、いいね、登録などを明示的に操作を促す(例: 動画をクリック)。";
|
"Explicit reminders to like, subscribe or interact with them on any paid or free platform(s) (e.g. click on a video)." = "有料/無料のプラットフォームかを問わず、いいね、登録などを明示的に操作を促す(例: 動画をクリック)。";
|
||||||
"Proxy videos" = "動画閲覧にプロキシ使用";
|
"Proxy videos" = "動画閲覧にプロキシ使用";
|
||||||
"Sections" = "表示する部分";
|
"Sections" = "表示するボタン";
|
||||||
"System controls show buttons for %@" = "システム制御「%@」用のボタンを表示";
|
"System controls show buttons for %@" = "システム制御「%@」用のボタンを表示";
|
||||||
"You need to create an instance and accounts\nto access %@ section" = "%@ セクションの利用には\nインスタンスとアカウントの作成が必要";
|
"You need to create an instance and accounts\nto access %@ section" = "%@ セクションの利用には\nインスタンスとアカウントの作成が必要";
|
||||||
"You need to select an account\nto access %@ section" = "%@ セクションの利用には\nアカウントの選択が必要";
|
"You need to select an account\nto access %@ section" = "%@ セクションの利用には\nアカウントの選択が必要";
|
||||||
|
@ -439,7 +439,7 @@
|
|||||||
"Format" = "";
|
"Format" = "";
|
||||||
"Verified" = "";
|
"Verified" = "";
|
||||||
"Show icons and text when space permits" = "";
|
"Show icons and text when space permits" = "";
|
||||||
"Could not extract video ID" = "";
|
"Could not extract video ID" = "Kunne ikke pakke ut video-ID";
|
||||||
"Open Files" = "";
|
"Open Files" = "";
|
||||||
"Driver" = "";
|
"Driver" = "";
|
||||||
"Show Open Videos quick actions" = "";
|
"Show Open Videos quick actions" = "";
|
||||||
@ -456,34 +456,34 @@
|
|||||||
"FPS" = "";
|
"FPS" = "";
|
||||||
"Inspector visibility" = "";
|
"Inspector visibility" = "";
|
||||||
"Show Documents" = "";
|
"Show Documents" = "";
|
||||||
"Open logs in Finder" = "";
|
"Open logs in Finder" = "Åpne loggføring i Finder";
|
||||||
"Documents" = "";
|
"Documents" = "";
|
||||||
"Could not update your token." = "";
|
"Could not update your token." = "Kunne ikke oppdatere symbolet ditt.";
|
||||||
"Remove…" = "";
|
"Remove…" = "";
|
||||||
"Hide" = "";
|
"Hide" = "";
|
||||||
"Actions buttons" = "";
|
"Actions buttons" = "";
|
||||||
"Audio" = "";
|
"Audio" = "";
|
||||||
"Could not extract SID from received cookies: %@" = "";
|
"Could not extract SID from received cookies: %@" = "Kunne ikke hente ut SID fra mottatte informasjonskapsler: %@";
|
||||||
"Playback Mode" = "";
|
"Playback Mode" = "";
|
||||||
"Clear Queue before opening" = "";
|
"Clear Queue before opening" = "";
|
||||||
"Could not create share link" = "";
|
"Could not create share link" = "Kunne ikke opprette delingslenke";
|
||||||
"Could not refresh Playlists" = "";
|
"Could not refresh Playlists" = "";
|
||||||
"Could not refresh Subscriptions" = "";
|
"Could not refresh Subscriptions" = "Kunne ikke gjenoppfriske abonnementer";
|
||||||
"Translations" = "";
|
"Translations" = "";
|
||||||
"This URL could not be opened" = "";
|
"This URL could not be opened" = "";
|
||||||
"For custom locations you can configure Frontend URL in Locations settings" = "";
|
"For custom locations you can configure Frontend URL in Locations settings" = "";
|
||||||
"Could not refresh Trending" = "";
|
"Could not refresh Trending" = "";
|
||||||
"If you want this app to be available in your language, join translation project." = "";
|
"If you want this app to be available in your language, join translation project." = "";
|
||||||
"This video could not be opened" = "";
|
"This video could not be opened" = "Kunne ikke åpne videoen";
|
||||||
"Could not open channel" = "";
|
"Could not open channel" = "Kunne ikke åpne kanal";
|
||||||
"Could not open playlist" = "";
|
"Could not open playlist" = "Kunne ikke åpne spilleliste";
|
||||||
"Could not load streams" = "";
|
"Could not load streams" = "Kunne ikke laste inn strømmer";
|
||||||
"Could not open video" = "";
|
"Could not open video" = "Kunne ikke åpne video";
|
||||||
"Could not extract channel information" = "";
|
"Could not extract channel information" = "Kunne ikke hente kanalinfo";
|
||||||
"Could not load video" = "";
|
"Could not load video" = "Kunne ikke laste inn video";
|
||||||
"Could not extract playlist ID" = "";
|
"Could not extract playlist ID" = "Kunne ikke hente ut spilleliste-ID";
|
||||||
"Could not refresh Popular" = "";
|
"Could not refresh Popular" = "";
|
||||||
"Channel could not be found" = "";
|
"Channel could not be found" = "Fant ikke kanalen";
|
||||||
"Live Streams" = "";
|
"Live Streams" = "";
|
||||||
"Channel" = "";
|
"Channel" = "";
|
||||||
"No documents" = "";
|
"No documents" = "";
|
||||||
@ -499,4 +499,4 @@
|
|||||||
"Playback history is empty" = "";
|
"Playback history is empty" = "";
|
||||||
"Copy%@link" = "";
|
"Copy%@link" = "";
|
||||||
"Share%@link" = "";
|
"Share%@link" = "";
|
||||||
"Share Logs..." = "";
|
"Share Logs..." = "Del logger …";
|
||||||
|
@ -596,3 +596,5 @@
|
|||||||
"Play Now in MPV" = "Odtwórz teraz w MPV";
|
"Play Now in MPV" = "Odtwórz teraz w MPV";
|
||||||
"Keep channels with unwatched videos on top of subscriptions list" = "Kanały z nieobejrzanymi filmami na górze listy subskrypcji";
|
"Keep channels with unwatched videos on top of subscriptions list" = "Kanały z nieobejrzanymi filmami na górze listy subskrypcji";
|
||||||
"Show video context menu options to force selected backend" = "Pokaż opcje menu kontekstowego wideo, aby wymusić wybrany silnik";
|
"Show video context menu options to force selected backend" = "Pokaż opcje menu kontekstowego wideo, aby wymusić wybrany silnik";
|
||||||
|
"Show channel avatars in videos lists" = "Pokaż awatary kanałów na listach wideo";
|
||||||
|
"Show channel avatars in channels lists" = "Pokaż awatary kanałów na listach kanałów";
|
||||||
|
@ -540,3 +540,58 @@
|
|||||||
"Show unwatched feed badges" = "Mostrar ícone de feed não visto";
|
"Show unwatched feed badges" = "Mostrar ícone de feed não visto";
|
||||||
"Gesture: fowards" = "Gesto: para frente";
|
"Gesture: fowards" = "Gesto: para frente";
|
||||||
"Controls Buttons" = "Botões de Controle";
|
"Controls Buttons" = "Botões de Controle";
|
||||||
|
"Show video context menu options to force selected backend" = "Mostrar opções do menu contextual do vídeo para forçar o backend selecionado";
|
||||||
|
"Play Now in AVPlayer" = "Tocar Agora no AVPlayer";
|
||||||
|
"Play Now in MPV" = "Tocar Agora em MPV";
|
||||||
|
"Enter account credentials to connect..." = "Insira as credenciais da conta para conectar…";
|
||||||
|
"Show scroll to top button in comments" = "Mostrar botão de voltar ao topo nos comentários";
|
||||||
|
"Cells" = "Células";
|
||||||
|
"Mark all as unwatched" = "Marcar todos como não vistos";
|
||||||
|
"Queue - shuffled" = "Fila - embaralhado";
|
||||||
|
"Fullscreen" = "Ecrã inteiro";
|
||||||
|
"Lock" = "Travar";
|
||||||
|
"Description" = "Descrição";
|
||||||
|
"Loop one" = "Um em loop";
|
||||||
|
"Enter location address to connect..." = "Insira o endereço da localização para conectar…";
|
||||||
|
"Seek" = "Vasculhar";
|
||||||
|
"Keep channels with unwatched videos on top of subscriptions list" = "Manter canais com vídeos não vistos no topo da lista de inscrições";
|
||||||
|
"Opened File" = "Ficheiro Aberto";
|
||||||
|
"File Extension" = "Extensão do Ficheiro";
|
||||||
|
"Opening file..." = "A abrir ficheiro…";
|
||||||
|
"Close video and player on end" = "Fechar vídeo e player ao final";
|
||||||
|
"Use system controls with AVPlayer" = "Usar controles do sistema com o AVPlayer";
|
||||||
|
"Public account" = "Conta pública";
|
||||||
|
"Your Accounts" = "As suas Contas";
|
||||||
|
"Browse without account" = "Navegar sem uma conta";
|
||||||
|
"Rotate when entering fullscreen on landscape video" = "Girar quando entrar no modo ecrã inteiro em vídeo em paisagem";
|
||||||
|
"Landscape left" = "Paisagem à esquerda";
|
||||||
|
"Landscape right" = "Paisagem à direita";
|
||||||
|
"No rotation" = "Sem rotação";
|
||||||
|
"Available" = "Disponível";
|
||||||
|
"Startup section" = "Secção ao iniciar";
|
||||||
|
"Home Settings" = "Ajustes da ecrã de Início";
|
||||||
|
"Watched: hidden" = "Assistidos: ocultos";
|
||||||
|
"Watched: visible" = "Assistidos: visíveis";
|
||||||
|
"Disable filters" = "Desativar filtros";
|
||||||
|
"(watched and shorts hidden)" = "(assistidos e shorts ocultos)";
|
||||||
|
"No videos to show" = "Nenhum vídeo para mostrar";
|
||||||
|
"(watched hidden)" = "(assistidos ocultos)";
|
||||||
|
"(shorts hidden)" = "(shorts ocultos)";
|
||||||
|
"Limit" = "Limite";
|
||||||
|
"Are you sure you want to remove %@ from Favorites?" = "Tem certeza que deseja remover %@ dos Favoritos?";
|
||||||
|
"List" = "Lista";
|
||||||
|
"Toggle size" = "Alternar tamanho";
|
||||||
|
"Toggle player" = "Alternar player";
|
||||||
|
"Do nothing" = "Fazer nada";
|
||||||
|
"Show Next in Queue" = "Mostrar Próximo na Fila";
|
||||||
|
"Show toggle watch status button" = "Mostrar botão de mudar estado de assistir";
|
||||||
|
"Feed" = "Feed";
|
||||||
|
"Next in Queue" = "Próximo na Fila";
|
||||||
|
"Open channel" = "Abrir canal";
|
||||||
|
"Inspector" = "Inspetor";
|
||||||
|
"Open video description expanded" = "Abrir descrição do vídeo expandida";
|
||||||
|
"Mark all as watched" = "Marcar todos como vistos";
|
||||||
|
"Playback Settings" = "Configurações de Playback";
|
||||||
|
"Replay" = "Replay";
|
||||||
|
"Autoplay next" = "Tocar automaticamente próximo";
|
||||||
|
"Stream" = "Stream";
|
||||||
|
@ -502,3 +502,96 @@
|
|||||||
"Shorts" = "短视频";
|
"Shorts" = "短视频";
|
||||||
"Verified" = "已验证";
|
"Verified" = "已验证";
|
||||||
"Channel" = "频道";
|
"Channel" = "频道";
|
||||||
|
"Open expanded" = "展开";
|
||||||
|
"Mark channel feed as watched" = "关注频道 Feed";
|
||||||
|
"Short videos: visible" = "短视频:可见";
|
||||||
|
"Player Bar" = "播放栏";
|
||||||
|
"Short videos: hidden" = "短视频:隐藏";
|
||||||
|
"Mark channel feed as unwatched" = "取消关注频道 Feed";
|
||||||
|
"Play all unwatched" = "观看所有未观看视频";
|
||||||
|
"Double tap gesture" = "双击手势";
|
||||||
|
"Tap and hold channel thumbnail to open context menu with more actions" = "点击并按住频道缩略图以打开包含更多操作的上下文菜单";
|
||||||
|
"Always show controls buttons" = "始终显示控制按钮";
|
||||||
|
"Show video context menu options to force selected backend" = "显示视频内容目录选项来强制选择的后端";
|
||||||
|
"Gesture: backwards" = "手势:向后";
|
||||||
|
"Maximum width expanded" = "最大宽度展开";
|
||||||
|
"Clear all" = "清除所有APP缓存";
|
||||||
|
"Total size: %@" = "总大小:%@";
|
||||||
|
"Gesture settings control skipping interval for double tap gesture on left/right side of the player. Changing system controls settings requires restart." = "手势设置控制玩家左右两侧双击手势的跳过间隔。更改系统控制设置需要重新启动。";
|
||||||
|
"Play next item" = "播放下一个";
|
||||||
|
"Subscribe/Unsubscribe" = "关注/取消关注";
|
||||||
|
"Autoplay next" = "自动播放下一个";
|
||||||
|
"Enter location address to connect..." = "输入链接地址以连接...";
|
||||||
|
"Keep channels with unwatched videos on top of subscriptions list" = "保留频道,并且未观看视频放在关注列表最上面";
|
||||||
|
"Play Now in AVPlayer" = "在 AVPlayer 中播放当前项目";
|
||||||
|
"Play Now in MPV" = "在 MPV 中播放当前项目";
|
||||||
|
"Seek" = "探索";
|
||||||
|
"Enter account credentials to connect..." = "输入账户凭据来连接...";
|
||||||
|
"Show scroll to top button in comments" = "在评论中显示“滚动到顶部”按钮";
|
||||||
|
"Opened File" = "打开的文件";
|
||||||
|
"File Extension" = "文件扩展";
|
||||||
|
"Opening file..." = "打开文件中...";
|
||||||
|
"Single tap gesture" = "单击手势";
|
||||||
|
"Right click channel thumbnail to open context menu with more actions" = "右键单击频道缩略图以打开具有更多操作的上下文菜单";
|
||||||
|
"Show unwatched feed badges" = "显示未观看的 Feed 标志";
|
||||||
|
"Seeking" = "探索";
|
||||||
|
"Gesture: fowards" = "手势:向前";
|
||||||
|
"System controls" = "系统控制";
|
||||||
|
"Controls button: backwards" = "控制按钮:向后";
|
||||||
|
"Controls button: forwards" = "控制按钮:向前";
|
||||||
|
"Hide player" = "隐藏播放器";
|
||||||
|
"Gesture settings control skipping interval for double click on left/right side of the player. Changing system controls settings requires restart." = "手势设置控制双击播放器左/右的跳跃间隔。更改系统控制设置需要重新启动。";
|
||||||
|
"Gesture settings control skipping interval for remote arrow buttons (for 2nd generation Siri Remote or newer). Changing system controls settings requires restart." = "手势设置控制远程箭头按钮的跳过间隔(用于第二代 Siri Remote 或更新版本)。更改系统控制设置需要重新启动。";
|
||||||
|
"Controls Buttons" = "控制按钮";
|
||||||
|
"Actions Buttons" = "动作按钮";
|
||||||
|
"Lock orientation" = "锁定屏幕方向";
|
||||||
|
"Music Mode" = "音乐模式";
|
||||||
|
"Close video" = "关闭视频";
|
||||||
|
"Cache" = "缓存";
|
||||||
|
"Show cache status" = "显示缓存状态";
|
||||||
|
"Maximum feed items" = "最大 Feed 项目";
|
||||||
|
"Open channels with description expanded" = "打开描述展开的频道";
|
||||||
|
"Are you sure you want to clear cache?" = "你确定要清除缓存吗?";
|
||||||
|
"Close video and player on end" = "在播放结束时关闭播放器和视频";
|
||||||
|
"Use system controls with AVPlayer" = "使用 AVPlayer 与系统控制按钮";
|
||||||
|
"Public account" = "公共账号";
|
||||||
|
"Your Accounts" = "你的账号";
|
||||||
|
"Browse without account" = "匿名浏览";
|
||||||
|
"Rotate when entering fullscreen on landscape video" = "当观看全景视频,进入全屏时旋转";
|
||||||
|
"Landscape left" = "全景视频左边";
|
||||||
|
"Landscape right" = "全景视频右边";
|
||||||
|
"No rotation" = "不旋转";
|
||||||
|
"Available" = "可用";
|
||||||
|
"Startup section" = "启动部分";
|
||||||
|
"Watched: hidden" = "观看过:隐藏";
|
||||||
|
"Watched: visible" = "观看后:显示";
|
||||||
|
"Disable filters" = "禁用过滤器";
|
||||||
|
"Home Settings" = "主页设置";
|
||||||
|
"(watched and shorts hidden)" = "(观看后与短视频隐藏)";
|
||||||
|
"No videos to show" = "没有可以显示的视频";
|
||||||
|
"(watched hidden)" = "(已观看已隐藏)";
|
||||||
|
"(shorts hidden)" = "(短视频已隐藏)";
|
||||||
|
"Limit" = "限制";
|
||||||
|
"Are you sure you want to remove %@ from Favorites?" = "你确定要从收藏夹中删除 %@ 吗?";
|
||||||
|
"List" = "列表";
|
||||||
|
"Cells" = "Cells";
|
||||||
|
"Toggle size" = "总大小";
|
||||||
|
"Toggle player" = "切换播放器";
|
||||||
|
"Do nothing" = "什么也不做(*^_^*)";
|
||||||
|
"Show Next in Queue" = "在队列中显示下一个";
|
||||||
|
"Show toggle watch status button" = "显示“切换观看状态”按钮";
|
||||||
|
"Feed" = "Feed";
|
||||||
|
"Next in Queue" = "队列中下一个";
|
||||||
|
"Open channel" = "打开频道";
|
||||||
|
"Inspector" = "检查器";
|
||||||
|
"Open video description expanded" = "打开描述展开的视频";
|
||||||
|
"Mark all as unwatched" = "标记所有未看过的";
|
||||||
|
"Mark all as watched" = "标记所有看过的";
|
||||||
|
"Queue - shuffled" = "队列 - 随机";
|
||||||
|
"Playback Settings" = "回放设置";
|
||||||
|
"Replay" = "重新播放";
|
||||||
|
"Fullscreen" = "全屏";
|
||||||
|
"Lock" = "锁定";
|
||||||
|
"Description" = "描述";
|
||||||
|
"Loop one" = "单个循环";
|
||||||
|
"Stream" = "流播放";
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// UIResponder+Extensions.swift
|
|
||||||
// SwiftUI_Pull_to_Refresh
|
|
||||||
//
|
|
||||||
// Created by Geri Borbás on 21/09/2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
extension UIResponder {
|
|
||||||
var parentViewController: UIViewController? {
|
|
||||||
next as? UIViewController ?? next?.parentViewController
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
//
|
|
||||||
// UIView+Extensions.swift
|
|
||||||
// SwiftUI_Pull_to_Refresh
|
|
||||||
//
|
|
||||||
// Created by Geri Borbás on 19/09/2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
extension UIView {
|
|
||||||
/// Returs frame in screen coordinates.
|
|
||||||
var globalFrame: CGRect {
|
|
||||||
if let window {
|
|
||||||
return convert(bounds, to: window.screen.coordinateSpace)
|
|
||||||
} else {
|
|
||||||
return .zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns with all the instances of the given view type in the view hierarchy.
|
|
||||||
func viewsInHierarchy<ViewType: UIView>() -> [ViewType]? {
|
|
||||||
var views: [ViewType] = []
|
|
||||||
viewsInHierarchy(views: &views)
|
|
||||||
return views.isEmpty ? nil : views
|
|
||||||
}
|
|
||||||
|
|
||||||
private func viewsInHierarchy<ViewType: UIView>(views: inout [ViewType]) {
|
|
||||||
subviews.forEach { eachSubView in
|
|
||||||
if let matchingView = eachSubView as? ViewType {
|
|
||||||
views.append(matchingView)
|
|
||||||
}
|
|
||||||
eachSubView.viewsInHierarchy(views: &views)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Search ancestral view hierarcy for the given view type.
|
|
||||||
func searchViewAnchestorsFor<ViewType: UIView>(
|
|
||||||
_ onViewFound: (ViewType) -> Void
|
|
||||||
) {
|
|
||||||
if let matchingView = superview as? ViewType {
|
|
||||||
onViewFound(matchingView)
|
|
||||||
} else {
|
|
||||||
superview?.searchViewAnchestorsFor(onViewFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Search ancestral view hierarcy for the given view type.
|
|
||||||
func searchViewAnchestorsFor<ViewType: UIView>() -> ViewType? {
|
|
||||||
if let matchingView = superview as? ViewType {
|
|
||||||
return matchingView
|
|
||||||
} else {
|
|
||||||
return superview?.searchViewAnchestorsFor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printViewHierarchyInformation(_ level: Int = 0) {
|
|
||||||
printViewInformation(level)
|
|
||||||
subviews.forEach { $0.printViewHierarchyInformation(level + 1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
func printViewInformation(_ level: Int) {
|
|
||||||
let leadingWhitespace = String(repeating: " ", count: level)
|
|
||||||
let className = "\(Self.self)"
|
|
||||||
let superclassName = "\(superclass!)"
|
|
||||||
let frame = "\(self.frame)"
|
|
||||||
let id = (accessibilityIdentifier == nil) ? "" : " `\(accessibilityIdentifier!)`"
|
|
||||||
print("\(leadingWhitespace)\(className): \(superclassName)\(id) \(frame)")
|
|
||||||
}
|
|
||||||
}
|
|
56
Vendor/RefreshControl/RefreshControl.swift
vendored
56
Vendor/RefreshControl/RefreshControl.swift
vendored
@ -1,56 +0,0 @@
|
|||||||
//
|
|
||||||
// RefreshControl.swift
|
|
||||||
// SwiftUI_Pull_to_Refresh
|
|
||||||
//
|
|
||||||
// Created by Geri Borbás on 18/09/2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
final class RefreshControl: ObservableObject {
|
|
||||||
static var navigationBarTitleDisplayMode: NavigationBarItem.TitleDisplayMode {
|
|
||||||
if #available(iOS 15.0, *) {
|
|
||||||
return .automatic
|
|
||||||
}
|
|
||||||
|
|
||||||
return .inline
|
|
||||||
}
|
|
||||||
|
|
||||||
let onValueChanged: (_ refreshControl: UIRefreshControl) -> Void
|
|
||||||
|
|
||||||
internal init(onValueChanged: @escaping ((UIRefreshControl) -> Void)) {
|
|
||||||
self.onValueChanged = onValueChanged
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a `UIRefreshControl` to the `UIScrollView` provided.
|
|
||||||
func add(to scrollView: UIScrollView) {
|
|
||||||
scrollView.refreshControl = UIRefreshControl().withTarget(
|
|
||||||
self,
|
|
||||||
action: #selector(onValueChangedAction),
|
|
||||||
for: .valueChanged
|
|
||||||
)
|
|
||||||
.testable(as: "RefreshControl")
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func onValueChangedAction(sender: UIRefreshControl) {
|
|
||||||
onValueChanged(sender)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UIRefreshControl {
|
|
||||||
/// Convinience method to assign target action inline.
|
|
||||||
func withTarget(_ target: Any?, action: Selector, for controlEvents: UIControl.Event) -> UIRefreshControl {
|
|
||||||
addTarget(target, action: action, for: controlEvents)
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convinience method to match refresh control for UI testing.
|
|
||||||
func testable(as id: String) -> UIRefreshControl {
|
|
||||||
isAccessibilityElement = true
|
|
||||||
accessibilityIdentifier = id
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
//
|
|
||||||
// RefreshControlModifier.swift
|
|
||||||
// SwiftUI_Pull_to_Refresh
|
|
||||||
//
|
|
||||||
// Created by Geri Borbás on 18/09/2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct RefreshControlModifier: ViewModifier {
|
|
||||||
@State private var geometryReaderFrame: CGRect = .zero
|
|
||||||
let refreshControl: RefreshControl
|
|
||||||
|
|
||||||
internal init(onValueChanged: @escaping (UIRefreshControl) -> Void) {
|
|
||||||
refreshControl = RefreshControl(onValueChanged: onValueChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
|
||||||
return content
|
|
||||||
} else {
|
|
||||||
return content
|
|
||||||
.background(
|
|
||||||
GeometryReader { geometry in
|
|
||||||
ScrollViewMatcher(
|
|
||||||
onResolve: { scrollView in
|
|
||||||
refreshControl.add(to: scrollView)
|
|
||||||
},
|
|
||||||
geometryReaderFrame: $geometryReaderFrame
|
|
||||||
)
|
|
||||||
.preference(key: FramePreferenceKey.self, value: geometry.frame(in: .global))
|
|
||||||
.onPreferenceChange(FramePreferenceKey.self) { frame in
|
|
||||||
self.geometryReaderFrame = frame
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension View {
|
|
||||||
func refreshControl(onValueChanged: @escaping (_ refreshControl: UIRefreshControl) -> Void) -> some View {
|
|
||||||
modifier(RefreshControlModifier(onValueChanged: onValueChanged))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
//
|
|
||||||
// FramePreferenceKey.swift
|
|
||||||
// SwiftUI_Pull_to_Refresh
|
|
||||||
//
|
|
||||||
// Created by Geri Borbás on 21/09/2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct FramePreferenceKey: PreferenceKey {
|
|
||||||
typealias Value = CGRect
|
|
||||||
static var defaultValue = CGRect.zero
|
|
||||||
|
|
||||||
static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
|
|
||||||
value = nextValue()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
//
|
|
||||||
// ScrollViewMatcher.swift
|
|
||||||
// SwiftUI_Pull_to_Refresh
|
|
||||||
//
|
|
||||||
// Created by Geri Borbás on 17/09/2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
final class ScrollViewMatcher: UIViewControllerRepresentable {
|
|
||||||
let onMatch: (UIScrollView) -> Void
|
|
||||||
@Binding var geometryReaderFrame: CGRect
|
|
||||||
|
|
||||||
init(onResolve: @escaping (UIScrollView) -> Void, geometryReaderFrame: Binding<CGRect>) {
|
|
||||||
onMatch = onResolve
|
|
||||||
_geometryReaderFrame = geometryReaderFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeUIViewController(context _: Context) -> ScrollViewMatcherViewController {
|
|
||||||
ScrollViewMatcherViewController(onResolve: onMatch, geometryReaderFrame: geometryReaderFrame)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIViewController(_ viewController: ScrollViewMatcherViewController, context _: Context) {
|
|
||||||
viewController.geometryReaderFrame = geometryReaderFrame
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class ScrollViewMatcherViewController: UIViewController {
|
|
||||||
let onMatch: (UIScrollView) -> Void
|
|
||||||
private var scrollView: UIScrollView? {
|
|
||||||
didSet {
|
|
||||||
if oldValue != scrollView,
|
|
||||||
let scrollView
|
|
||||||
{
|
|
||||||
onMatch(scrollView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var geometryReaderFrame: CGRect {
|
|
||||||
didSet {
|
|
||||||
match()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(onResolve: @escaping (UIScrollView) -> Void, geometryReaderFrame: CGRect, debug _: Bool = false) {
|
|
||||||
onMatch = onResolve
|
|
||||||
self.geometryReaderFrame = geometryReaderFrame
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(*, unavailable)
|
|
||||||
required init?(coder _: NSCoder) {
|
|
||||||
fatalError("Use init(onMatch:) to instantiate ScrollViewMatcherViewController.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func match() {
|
|
||||||
// matchUsingHierarchy()
|
|
||||||
matchUsingGeometry()
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchUsingHierarchy() {
|
|
||||||
if parent != nil {
|
|
||||||
// Lookup view ancestry for any `UIScrollView`.
|
|
||||||
view.searchViewAnchestorsFor { (scrollView: UIScrollView) in
|
|
||||||
self.scrollView = scrollView
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchUsingGeometry() {
|
|
||||||
if let parent {
|
|
||||||
if let scrollViewsInHierarchy: [UIScrollView] = parent.view.viewsInHierarchy() {
|
|
||||||
// Return first match if only a single scroll view is found in the hierarchy.
|
|
||||||
if scrollViewsInHierarchy.count == 1,
|
|
||||||
let firstScrollViewInHierarchy = scrollViewsInHierarchy.first
|
|
||||||
{
|
|
||||||
scrollView = firstScrollViewInHierarchy
|
|
||||||
|
|
||||||
// Filter by frame origins if multiple matches found.
|
|
||||||
} else {
|
|
||||||
if let firstMatchingFrameOrigin = scrollViewsInHierarchy.filter({
|
|
||||||
$0.globalFrame.origin.close(to: geometryReaderFrame.origin)
|
|
||||||
}).first {
|
|
||||||
scrollView = firstMatchingFrameOrigin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func didMove(toParent parent: UIViewController?) {
|
|
||||||
super.didMove(toParent: parent)
|
|
||||||
match()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CGPoint {
|
|
||||||
/// Returns `true` if this point is close the other point (considering a ~1 pt tolerance).
|
|
||||||
func close(to point: CGPoint) -> Bool {
|
|
||||||
let inset = Double(1)
|
|
||||||
let rect = CGRect(x: x - inset, y: y - inset, width: inset * 2, height: inset * 2)
|
|
||||||
return rect.contains(point)
|
|
||||||
}
|
|
||||||
}
|
|
@ -170,9 +170,7 @@
|
|||||||
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
3722AEBC274DA396005EA4D6 /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
|
||||||
3722AEBE274DA401005EA4D6 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
3722AEBE274DA401005EA4D6 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||||
3726386E2948A4B80043702D /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
|
||||||
37270F1C28E06E3E00856150 /* String+Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37270F1B28E06E3E00856150 /* String+Localizable.swift */; };
|
37270F1C28E06E3E00856150 /* String+Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37270F1B28E06E3E00856150 /* String+Localizable.swift */; };
|
||||||
37270F1D28E06E3E00856150 /* String+Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37270F1B28E06E3E00856150 /* String+Localizable.swift */; };
|
37270F1D28E06E3E00856150 /* String+Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37270F1B28E06E3E00856150 /* String+Localizable.swift */; };
|
||||||
37270F1E28E06E3E00856150 /* String+Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37270F1B28E06E3E00856150 /* String+Localizable.swift */; };
|
37270F1E28E06E3E00856150 /* String+Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37270F1B28E06E3E00856150 /* String+Localizable.swift */; };
|
||||||
@ -324,7 +322,6 @@
|
|||||||
37579D5E27864F5F00FD0B98 /* Help.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37579D5C27864F5F00FD0B98 /* Help.swift */; };
|
37579D5E27864F5F00FD0B98 /* Help.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37579D5C27864F5F00FD0B98 /* Help.swift */; };
|
||||||
37579D5F27864F5F00FD0B98 /* Help.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37579D5C27864F5F00FD0B98 /* Help.swift */; };
|
37579D5F27864F5F00FD0B98 /* Help.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37579D5C27864F5F00FD0B98 /* Help.swift */; };
|
||||||
3758638A2721B0A9000CB14E /* ChannelCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743B86727216D3600261544 /* ChannelCell.swift */; };
|
3758638A2721B0A9000CB14E /* ChannelCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743B86727216D3600261544 /* ChannelCell.swift */; };
|
||||||
3759234628C26C7B00C052EC /* Refreshable+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3759234528C26C7B00C052EC /* Refreshable+Backport.swift */; };
|
|
||||||
37599F30272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
37599F30272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
||||||
37599F31272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
37599F31272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
||||||
37599F32272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
37599F32272B42810087F250 /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37599F2F272B42810087F250 /* FavoriteItem.swift */; };
|
||||||
@ -500,9 +497,6 @@
|
|||||||
377ABC48286E5887009C986F /* Sequence+Unique.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377ABC47286E5887009C986F /* Sequence+Unique.swift */; };
|
377ABC48286E5887009C986F /* Sequence+Unique.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377ABC47286E5887009C986F /* Sequence+Unique.swift */; };
|
||||||
377ABC49286E5887009C986F /* Sequence+Unique.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377ABC47286E5887009C986F /* Sequence+Unique.swift */; };
|
377ABC49286E5887009C986F /* Sequence+Unique.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377ABC47286E5887009C986F /* Sequence+Unique.swift */; };
|
||||||
377ABC4A286E5887009C986F /* Sequence+Unique.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377ABC47286E5887009C986F /* Sequence+Unique.swift */; };
|
377ABC4A286E5887009C986F /* Sequence+Unique.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377ABC47286E5887009C986F /* Sequence+Unique.swift */; };
|
||||||
377E17142928265900894889 /* ListRowSeparator+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377E17132928265900894889 /* ListRowSeparator+Backport.swift */; };
|
|
||||||
377E17152928265900894889 /* ListRowSeparator+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377E17132928265900894889 /* ListRowSeparator+Backport.swift */; };
|
|
||||||
377E17162928265900894889 /* ListRowSeparator+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377E17132928265900894889 /* ListRowSeparator+Backport.swift */; };
|
|
||||||
377F9F74294403770043F856 /* Cache in Frameworks */ = {isa = PBXBuildFile; productRef = 377F9F73294403770043F856 /* Cache */; };
|
377F9F74294403770043F856 /* Cache in Frameworks */ = {isa = PBXBuildFile; productRef = 377F9F73294403770043F856 /* Cache */; };
|
||||||
377F9F76294403880043F856 /* Cache in Frameworks */ = {isa = PBXBuildFile; productRef = 377F9F75294403880043F856 /* Cache */; };
|
377F9F76294403880043F856 /* Cache in Frameworks */ = {isa = PBXBuildFile; productRef = 377F9F75294403880043F856 /* Cache */; };
|
||||||
377F9F7B294403F20043F856 /* VideosCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377F9F7A294403F20043F856 /* VideosCacheModel.swift */; };
|
377F9F7B294403F20043F856 /* VideosCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377F9F7A294403F20043F856 /* VideosCacheModel.swift */; };
|
||||||
@ -546,12 +540,8 @@
|
|||||||
3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
||||||
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
||||||
3788AC2926F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
3788AC2926F6840700F6BAA9 /* FavoriteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3788AC2626F6840700F6BAA9 /* FavoriteItemView.swift */; };
|
||||||
378AE93A274EDFAF006A4EE1 /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
|
||||||
378AE93C274EDFB2006A4EE1 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
378AE93C274EDFB2006A4EE1 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||||
378AE93D274EDFB3006A4EE1 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
378AE93D274EDFB3006A4EE1 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||||
378AE93E274EDFB4006A4EE1 /* Tint+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */; };
|
|
||||||
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */; };
|
|
||||||
378AE940274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */; };
|
|
||||||
378AE943274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
378AE943274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
||||||
378AE944274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
378AE944274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
||||||
378AE945274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
378AE945274EF00A006A4EE1 /* Color+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378AE942274EF00A006A4EE1 /* Color+Background.swift */; };
|
||||||
@ -836,14 +826,6 @@
|
|||||||
37DD9DA32785BBC900539416 /* NoCommentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DA22785BBC900539416 /* NoCommentsView.swift */; };
|
37DD9DA32785BBC900539416 /* NoCommentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DA22785BBC900539416 /* NoCommentsView.swift */; };
|
||||||
37DD9DA42785BBC900539416 /* NoCommentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DA22785BBC900539416 /* NoCommentsView.swift */; };
|
37DD9DA42785BBC900539416 /* NoCommentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DA22785BBC900539416 /* NoCommentsView.swift */; };
|
||||||
37DD9DA52785BBC900539416 /* NoCommentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DA22785BBC900539416 /* NoCommentsView.swift */; };
|
37DD9DA52785BBC900539416 /* NoCommentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DA22785BBC900539416 /* NoCommentsView.swift */; };
|
||||||
37DD9DB12785D58D00539416 /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DAF2785D58D00539416 /* RefreshControl.swift */; };
|
|
||||||
37DD9DB42785D58D00539416 /* RefreshControlModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DB02785D58D00539416 /* RefreshControlModifier.swift */; };
|
|
||||||
37DD9DBA2785D60300539416 /* FramePreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DB82785D60200539416 /* FramePreferenceKey.swift */; };
|
|
||||||
37DD9DBB2785D60300539416 /* FramePreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DB82785D60200539416 /* FramePreferenceKey.swift */; };
|
|
||||||
37DD9DBC2785D60300539416 /* FramePreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DB82785D60200539416 /* FramePreferenceKey.swift */; };
|
|
||||||
37DD9DBD2785D60300539416 /* ScrollViewMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DB92785D60200539416 /* ScrollViewMatcher.swift */; };
|
|
||||||
37DD9DC62785D63A00539416 /* UIResponder+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DC22785D63A00539416 /* UIResponder+Extensions.swift */; };
|
|
||||||
37DD9DCB2785E28C00539416 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD9DC12785D63A00539416 /* UIView+Extensions.swift */; };
|
|
||||||
37E04C0F275940FB00172673 /* VerticalScrollingFix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E04C0E275940FB00172673 /* VerticalScrollingFix.swift */; };
|
37E04C0F275940FB00172673 /* VerticalScrollingFix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E04C0E275940FB00172673 /* VerticalScrollingFix.swift */; };
|
||||||
37E084AC2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */; };
|
37E084AC2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */; };
|
||||||
37E084AD2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */; };
|
37E084AD2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */; };
|
||||||
@ -1083,9 +1065,7 @@
|
|||||||
371CC76F29468BDC00979C1A /* SettingsButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButtons.swift; sourceTree = "<group>"; };
|
371CC76F29468BDC00979C1A /* SettingsButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButtons.swift; sourceTree = "<group>"; };
|
||||||
371CC7732946963000979C1A /* ListingStyleButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingStyleButtons.swift; sourceTree = "<group>"; };
|
371CC7732946963000979C1A /* ListingStyleButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingStyleButtons.swift; sourceTree = "<group>"; };
|
||||||
371F2F19269B43D300E4A7AB /* NavigationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModel.swift; sourceTree = "<group>"; };
|
371F2F19269B43D300E4A7AB /* NavigationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModel.swift; sourceTree = "<group>"; };
|
||||||
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Badge+Backport.swift"; sourceTree = "<group>"; };
|
|
||||||
3722AEBD274DA401005EA4D6 /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
3722AEBD274DA401005EA4D6 /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
||||||
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tint+Backport.swift"; sourceTree = "<group>"; };
|
|
||||||
37270F1B28E06E3E00856150 /* String+Localizable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localizable.swift"; sourceTree = "<group>"; };
|
37270F1B28E06E3E00856150 /* String+Localizable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localizable.swift"; sourceTree = "<group>"; };
|
||||||
3727B74727872A500021C15E /* VisualEffectBlur-macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-macOS.swift"; sourceTree = "<group>"; };
|
3727B74727872A500021C15E /* VisualEffectBlur-macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-macOS.swift"; sourceTree = "<group>"; };
|
||||||
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-iOS.swift"; sourceTree = "<group>"; };
|
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-iOS.swift"; sourceTree = "<group>"; };
|
||||||
@ -1146,7 +1126,6 @@
|
|||||||
3756C2A52861131100E4B059 /* NetworkState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkState.swift; sourceTree = "<group>"; };
|
3756C2A52861131100E4B059 /* NetworkState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkState.swift; sourceTree = "<group>"; };
|
||||||
3756C2A92861151C00E4B059 /* NetworkStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkStateModel.swift; sourceTree = "<group>"; };
|
3756C2A92861151C00E4B059 /* NetworkStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkStateModel.swift; sourceTree = "<group>"; };
|
||||||
37579D5C27864F5F00FD0B98 /* Help.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Help.swift; sourceTree = "<group>"; };
|
37579D5C27864F5F00FD0B98 /* Help.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Help.swift; sourceTree = "<group>"; };
|
||||||
3759234528C26C7B00C052EC /* Refreshable+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Refreshable+Backport.swift"; sourceTree = "<group>"; };
|
|
||||||
37599F2F272B42810087F250 /* FavoriteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteItem.swift; sourceTree = "<group>"; };
|
37599F2F272B42810087F250 /* FavoriteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteItem.swift; sourceTree = "<group>"; };
|
||||||
37599F33272B44000087F250 /* FavoritesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesModel.swift; sourceTree = "<group>"; };
|
37599F33272B44000087F250 /* FavoritesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesModel.swift; sourceTree = "<group>"; };
|
||||||
37599F37272B4D740087F250 /* FavoriteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteButton.swift; sourceTree = "<group>"; };
|
37599F37272B4D740087F250 /* FavoriteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteButton.swift; sourceTree = "<group>"; };
|
||||||
@ -1207,7 +1186,6 @@
|
|||||||
377ABC3F286E4AD5009C986F /* InstancesManifest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstancesManifest.swift; sourceTree = "<group>"; };
|
377ABC3F286E4AD5009C986F /* InstancesManifest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstancesManifest.swift; sourceTree = "<group>"; };
|
||||||
377ABC43286E4B74009C986F /* ManifestedInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManifestedInstance.swift; sourceTree = "<group>"; };
|
377ABC43286E4B74009C986F /* ManifestedInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManifestedInstance.swift; sourceTree = "<group>"; };
|
||||||
377ABC47286E5887009C986F /* Sequence+Unique.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sequence+Unique.swift"; sourceTree = "<group>"; };
|
377ABC47286E5887009C986F /* Sequence+Unique.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sequence+Unique.swift"; sourceTree = "<group>"; };
|
||||||
377E17132928265900894889 /* ListRowSeparator+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ListRowSeparator+Backport.swift"; sourceTree = "<group>"; };
|
|
||||||
377F9F7A294403F20043F856 /* VideosCacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosCacheModel.swift; sourceTree = "<group>"; };
|
377F9F7A294403F20043F856 /* VideosCacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosCacheModel.swift; sourceTree = "<group>"; };
|
||||||
377F9F7E2944175F0043F856 /* FeedCacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedCacheModel.swift; sourceTree = "<group>"; };
|
377F9F7E2944175F0043F856 /* FeedCacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedCacheModel.swift; sourceTree = "<group>"; };
|
||||||
377FF88A291A60310028EB0B /* OpenVideosModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenVideosModel.swift; sourceTree = "<group>"; };
|
377FF88A291A60310028EB0B /* OpenVideosModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenVideosModel.swift; sourceTree = "<group>"; };
|
||||||
@ -1344,12 +1322,6 @@
|
|||||||
37DCD3162A191A180059A470 /* AVPlayerViewController+FullScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVPlayerViewController+FullScreen.swift"; sourceTree = "<group>"; };
|
37DCD3162A191A180059A470 /* AVPlayerViewController+FullScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVPlayerViewController+FullScreen.swift"; sourceTree = "<group>"; };
|
||||||
37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStreams.swift; sourceTree = "<group>"; };
|
37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStreams.swift; sourceTree = "<group>"; };
|
||||||
37DD9DA22785BBC900539416 /* NoCommentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCommentsView.swift; sourceTree = "<group>"; };
|
37DD9DA22785BBC900539416 /* NoCommentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCommentsView.swift; sourceTree = "<group>"; };
|
||||||
37DD9DAF2785D58D00539416 /* RefreshControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshControl.swift; sourceTree = "<group>"; };
|
|
||||||
37DD9DB02785D58D00539416 /* RefreshControlModifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshControlModifier.swift; sourceTree = "<group>"; };
|
|
||||||
37DD9DB82785D60200539416 /* FramePreferenceKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FramePreferenceKey.swift; sourceTree = "<group>"; };
|
|
||||||
37DD9DB92785D60200539416 /* ScrollViewMatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewMatcher.swift; sourceTree = "<group>"; };
|
|
||||||
37DD9DC12785D63A00539416 /* UIView+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = "<group>"; };
|
|
||||||
37DD9DC22785D63A00539416 /* UIResponder+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIResponder+Extensions.swift"; sourceTree = "<group>"; };
|
|
||||||
37E04C0E275940FB00172673 /* VerticalScrollingFix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalScrollingFix.swift; sourceTree = "<group>"; };
|
37E04C0E275940FB00172673 /* VerticalScrollingFix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalScrollingFix.swift; sourceTree = "<group>"; };
|
||||||
37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsNavigationLink.swift; sourceTree = "<group>"; };
|
37E084AB2753D95F00039B7D /* AccountsNavigationLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsNavigationLink.swift; sourceTree = "<group>"; };
|
||||||
37E64DD026D597EB00C71877 /* SubscribedChannelsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribedChannelsModel.swift; sourceTree = "<group>"; };
|
37E64DD026D597EB00C71877 /* SubscribedChannelsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribedChannelsModel.swift; sourceTree = "<group>"; };
|
||||||
@ -1681,13 +1653,9 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
3722AEBD274DA401005EA4D6 /* Backport.swift */,
|
3722AEBD274DA401005EA4D6 /* Backport.swift */,
|
||||||
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */,
|
|
||||||
377E17132928265900894889 /* ListRowSeparator+Backport.swift */,
|
|
||||||
37136CAB286273060095C0CF /* PersistentSystemOverlays+Backport.swift */,
|
37136CAB286273060095C0CF /* PersistentSystemOverlays+Backport.swift */,
|
||||||
3759234528C26C7B00C052EC /* Refreshable+Backport.swift */,
|
|
||||||
37E80F3F287B472300561799 /* ScrollContentBackground+Backport.swift */,
|
37E80F3F287B472300561799 /* ScrollContentBackground+Backport.swift */,
|
||||||
376E331128AD3B320070E30C /* ScrollDismissesKeyboard+Backport.swift */,
|
376E331128AD3B320070E30C /* ScrollDismissesKeyboard+Backport.swift */,
|
||||||
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */,
|
|
||||||
37B7CFE82A19603B001B0564 /* ToolbarBackground+Backport.swift */,
|
37B7CFE82A19603B001B0564 /* ToolbarBackground+Backport.swift */,
|
||||||
37B7CFEA2A1960EC001B0564 /* ToolbarColorScheme+Backport.swift */,
|
37B7CFEA2A1960EC001B0564 /* ToolbarColorScheme+Backport.swift */,
|
||||||
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */,
|
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */,
|
||||||
@ -2171,35 +2139,6 @@
|
|||||||
path = Model;
|
path = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
37DD9DAE2785D58D00539416 /* RefreshControl */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
37DD9DC02785D63A00539416 /* Extensions */,
|
|
||||||
37DD9DB72785D60200539416 /* ScrollViewMatcher */,
|
|
||||||
37DD9DAF2785D58D00539416 /* RefreshControl.swift */,
|
|
||||||
37DD9DB02785D58D00539416 /* RefreshControlModifier.swift */,
|
|
||||||
);
|
|
||||||
path = RefreshControl;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
37DD9DB72785D60200539416 /* ScrollViewMatcher */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
37DD9DB82785D60200539416 /* FramePreferenceKey.swift */,
|
|
||||||
37DD9DB92785D60200539416 /* ScrollViewMatcher.swift */,
|
|
||||||
);
|
|
||||||
path = ScrollViewMatcher;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
37DD9DC02785D63A00539416 /* Extensions */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
37DD9DC22785D63A00539416 /* UIResponder+Extensions.swift */,
|
|
||||||
37DD9DC12785D63A00539416 /* UIView+Extensions.swift */,
|
|
||||||
);
|
|
||||||
path = Extensions;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
37DD9DCC2785EE6F00539416 /* Vendor */ = {
|
37DD9DCC2785EE6F00539416 /* Vendor */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -2507,7 +2446,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1410;
|
LastSwiftUpdateCheck = 1500;
|
||||||
LastUpgradeCheck = 1410;
|
LastUpgradeCheck = 1410;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
37095E7E291DC85400301883 = {
|
37095E7E291DC85400301883 = {
|
||||||
@ -2849,12 +2788,10 @@
|
|||||||
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
||||||
37D2E0D428B67EFC00F64D52 /* Delay.swift in Sources */,
|
37D2E0D428B67EFC00F64D52 /* Delay.swift in Sources */,
|
||||||
3776925229463C310055EC18 /* PlaylistsCacheModel.swift in Sources */,
|
3776925229463C310055EC18 /* PlaylistsCacheModel.swift in Sources */,
|
||||||
3759234628C26C7B00C052EC /* Refreshable+Backport.swift in Sources */,
|
|
||||||
374924ED2921669B0017D862 /* PreferenceKeys.swift in Sources */,
|
374924ED2921669B0017D862 /* PreferenceKeys.swift in Sources */,
|
||||||
37130A5B277657090033018A /* Yattee.xcdatamodeld in Sources */,
|
37130A5B277657090033018A /* Yattee.xcdatamodeld in Sources */,
|
||||||
37152EEA26EFEB95004FB96D /* LazyView.swift in Sources */,
|
37152EEA26EFEB95004FB96D /* LazyView.swift in Sources */,
|
||||||
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
3761ABFD26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
||||||
37DD9DCB2785E28C00539416 /* UIView+Extensions.swift in Sources */,
|
|
||||||
377FF88F291A99580028EB0B /* HistoryView.swift in Sources */,
|
377FF88F291A99580028EB0B /* HistoryView.swift in Sources */,
|
||||||
3782B94F27553A6700990149 /* SearchSuggestions.swift in Sources */,
|
3782B94F27553A6700990149 /* SearchSuggestions.swift in Sources */,
|
||||||
378E50FF26FE8EEE00F49626 /* AccountViewButton.swift in Sources */,
|
378E50FF26FE8EEE00F49626 /* AccountViewButton.swift in Sources */,
|
||||||
@ -2890,7 +2827,6 @@
|
|||||||
37B81AF926D2C9A700675966 /* VideoPlayerSizeModifier.swift in Sources */,
|
37B81AF926D2C9A700675966 /* VideoPlayerSizeModifier.swift in Sources */,
|
||||||
37C0698227260B2100F7F6CB /* ThumbnailsModel.swift in Sources */,
|
37C0698227260B2100F7F6CB /* ThumbnailsModel.swift in Sources */,
|
||||||
37BC50A82778A84700510953 /* HistorySettings.swift in Sources */,
|
37BC50A82778A84700510953 /* HistorySettings.swift in Sources */,
|
||||||
37DD9DB12785D58D00539416 /* RefreshControl.swift in Sources */,
|
|
||||||
37BDFF1F29488117000C6404 /* ChannelPlaylistListItem.swift in Sources */,
|
37BDFF1F29488117000C6404 /* ChannelPlaylistListItem.swift in Sources */,
|
||||||
371CC76C29466F5A00979C1A /* AccountsViewModel.swift in Sources */,
|
371CC76C29466F5A00979C1A /* AccountsViewModel.swift in Sources */,
|
||||||
37B4E805277D0AB4004BF56A /* Orientation.swift in Sources */,
|
37B4E805277D0AB4004BF56A /* Orientation.swift in Sources */,
|
||||||
@ -2905,7 +2841,6 @@
|
|||||||
378AE943274EF00A006A4EE1 /* Color+Background.swift in Sources */,
|
378AE943274EF00A006A4EE1 /* Color+Background.swift in Sources */,
|
||||||
37F4AE7226828F0900BD60EA /* VerticalCells.swift in Sources */,
|
37F4AE7226828F0900BD60EA /* VerticalCells.swift in Sources */,
|
||||||
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
376578852685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||||
3722AEBC274DA396005EA4D6 /* Badge+Backport.swift in Sources */,
|
|
||||||
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
3748186626A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||||
37599F34272B44000087F250 /* FavoritesModel.swift in Sources */,
|
37599F34272B44000087F250 /* FavoritesModel.swift in Sources */,
|
||||||
3717407D2949D40800FDDBC7 /* ChannelLinkView.swift in Sources */,
|
3717407D2949D40800FDDBC7 /* ChannelLinkView.swift in Sources */,
|
||||||
@ -2918,10 +2853,8 @@
|
|||||||
3751B4B227836902000B7DF4 /* SearchPage.swift in Sources */,
|
3751B4B227836902000B7DF4 /* SearchPage.swift in Sources */,
|
||||||
37CC3F4C270CFE1700608308 /* PlayerQueueView.swift in Sources */,
|
37CC3F4C270CFE1700608308 /* PlayerQueueView.swift in Sources */,
|
||||||
37FFC440272734C3009FFD26 /* Throttle.swift in Sources */,
|
37FFC440272734C3009FFD26 /* Throttle.swift in Sources */,
|
||||||
37DD9DB42785D58D00539416 /* RefreshControlModifier.swift in Sources */,
|
|
||||||
3709528A29283E14001ECA40 /* NoDocumentsView.swift in Sources */,
|
3709528A29283E14001ECA40 /* NoDocumentsView.swift in Sources */,
|
||||||
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||||
378AE940274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
|
|
||||||
376BE50927347B5F009AD608 /* SettingsHeader.swift in Sources */,
|
376BE50927347B5F009AD608 /* SettingsHeader.swift in Sources */,
|
||||||
376527BB285F60F700102284 /* PlayerTimeModel.swift in Sources */,
|
376527BB285F60F700102284 /* PlayerTimeModel.swift in Sources */,
|
||||||
37270F1C28E06E3E00856150 /* String+Localizable.swift in Sources */,
|
37270F1C28E06E3E00856150 /* String+Localizable.swift in Sources */,
|
||||||
@ -2969,7 +2902,6 @@
|
|||||||
37BC50AC2778BCBA00510953 /* HistoryModel.swift in Sources */,
|
37BC50AC2778BCBA00510953 /* HistoryModel.swift in Sources */,
|
||||||
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
37AAF29026740715007FC770 /* Channel.swift in Sources */,
|
||||||
37F5C7E02A1E2AF300927B73 /* ListView.swift in Sources */,
|
37F5C7E02A1E2AF300927B73 /* ListView.swift in Sources */,
|
||||||
37DD9DBA2785D60300539416 /* FramePreferenceKey.swift in Sources */,
|
|
||||||
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
3748186A26A764FB0084E870 /* Thumbnail+Fixtures.swift in Sources */,
|
||||||
37B81AFF26D2CA3700675966 /* VideoDetails.swift in Sources */,
|
37B81AFF26D2CA3700675966 /* VideoDetails.swift in Sources */,
|
||||||
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */,
|
377FC7E5267A084E00A6BBAF /* SearchView.swift in Sources */,
|
||||||
@ -3018,7 +2950,6 @@
|
|||||||
37DCD3152A18F7630059A470 /* SafeAreaModel.swift in Sources */,
|
37DCD3152A18F7630059A470 /* SafeAreaModel.swift in Sources */,
|
||||||
37D526DE2720AC4400ED2F5E /* VideosAPI.swift in Sources */,
|
37D526DE2720AC4400ED2F5E /* VideosAPI.swift in Sources */,
|
||||||
37484C2526FC83E000287258 /* InstanceForm.swift in Sources */,
|
37484C2526FC83E000287258 /* InstanceForm.swift in Sources */,
|
||||||
37DD9DBD2785D60300539416 /* ScrollViewMatcher.swift in Sources */,
|
|
||||||
37B767DB2677C3CA0098BAA8 /* PlayerModel.swift in Sources */,
|
37B767DB2677C3CA0098BAA8 /* PlayerModel.swift in Sources */,
|
||||||
371CC7742946963000979C1A /* ListingStyleButtons.swift in Sources */,
|
371CC7742946963000979C1A /* ListingStyleButtons.swift in Sources */,
|
||||||
3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
|
3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
|
||||||
@ -3027,10 +2958,8 @@
|
|||||||
373031F528383A89000CFD59 /* PiPDelegate.swift in Sources */,
|
373031F528383A89000CFD59 /* PiPDelegate.swift in Sources */,
|
||||||
37F5E8BA291BEF69006C15F5 /* BaseCacheModel.swift in Sources */,
|
37F5E8BA291BEF69006C15F5 /* BaseCacheModel.swift in Sources */,
|
||||||
371AC09F294D13AA0085989E /* UnwatchedFeedCountModel.swift in Sources */,
|
371AC09F294D13AA0085989E /* UnwatchedFeedCountModel.swift in Sources */,
|
||||||
37DD9DC62785D63A00539416 /* UIResponder+Extensions.swift in Sources */,
|
|
||||||
370015A928BBAE7F000149FD /* ProgressBar.swift in Sources */,
|
370015A928BBAE7F000149FD /* ProgressBar.swift in Sources */,
|
||||||
37C3A24927235FAA0087A57A /* ChannelPlaylistCell.swift in Sources */,
|
37C3A24927235FAA0087A57A /* ChannelPlaylistCell.swift in Sources */,
|
||||||
377E17142928265900894889 /* ListRowSeparator+Backport.swift in Sources */,
|
|
||||||
373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
||||||
37F7AB4D28A9361F00FB46B5 /* UIDevice+Cellular.swift in Sources */,
|
37F7AB4D28A9361F00FB46B5 /* UIDevice+Cellular.swift in Sources */,
|
||||||
37141673267A8E10006CA35D /* Country.swift in Sources */,
|
37141673267A8E10006CA35D /* Country.swift in Sources */,
|
||||||
@ -3111,7 +3040,6 @@
|
|||||||
374710062755291C00CE0F87 /* SearchTextField.swift in Sources */,
|
374710062755291C00CE0F87 /* SearchTextField.swift in Sources */,
|
||||||
37B7CFEC2A197844001B0564 /* AppleAVPlayerView.swift in Sources */,
|
37B7CFEC2A197844001B0564 /* AppleAVPlayerView.swift in Sources */,
|
||||||
37F0F4EB286F397E00C06C2E /* SettingsModel.swift in Sources */,
|
37F0F4EB286F397E00C06C2E /* SettingsModel.swift in Sources */,
|
||||||
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
|
|
||||||
379ACB4D2A1F8A4100E01914 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
|
379ACB4D2A1F8A4100E01914 /* NSManagedObjectContext+ExecuteAndMergeChanges.swift in Sources */,
|
||||||
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
|
||||||
37737786276F9858000521C1 /* Windows.swift in Sources */,
|
37737786276F9858000521C1 /* Windows.swift in Sources */,
|
||||||
@ -3163,7 +3091,6 @@
|
|||||||
3784CDE327772EE40055BBF2 /* Watch.swift in Sources */,
|
3784CDE327772EE40055BBF2 /* Watch.swift in Sources */,
|
||||||
371AC0B7294D1D6E0085989E /* PlayingIndicatorView.swift in Sources */,
|
371AC0B7294D1D6E0085989E /* PlayingIndicatorView.swift in Sources */,
|
||||||
37E80F3D287B107F00561799 /* VideoDetailsOverlay.swift in Sources */,
|
37E80F3D287B107F00561799 /* VideoDetailsOverlay.swift in Sources */,
|
||||||
37DD9DBB2785D60300539416 /* FramePreferenceKey.swift in Sources */,
|
|
||||||
375DFB5926F9DA010013F468 /* InstancesModel.swift in Sources */,
|
375DFB5926F9DA010013F468 /* InstancesModel.swift in Sources */,
|
||||||
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||||
37D2E0D128B67DBC00F64D52 /* AnimationCompletionObserverModifier.swift in Sources */,
|
37D2E0D128B67DBC00F64D52 /* AnimationCompletionObserverModifier.swift in Sources */,
|
||||||
@ -3193,7 +3120,6 @@
|
|||||||
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD870267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
|
3788AC2826F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
|
||||||
377FF88C291A60310028EB0B /* OpenVideosModel.swift in Sources */,
|
377FF88C291A60310028EB0B /* OpenVideosModel.swift in Sources */,
|
||||||
378AE93A274EDFAF006A4EE1 /* Badge+Backport.swift in Sources */,
|
|
||||||
37599F35272B44000087F250 /* FavoritesModel.swift in Sources */,
|
37599F35272B44000087F250 /* FavoritesModel.swift in Sources */,
|
||||||
376527BC285F60F700102284 /* PlayerTimeModel.swift in Sources */,
|
376527BC285F60F700102284 /* PlayerTimeModel.swift in Sources */,
|
||||||
37F64FE526FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
|
37F64FE526FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
|
||||||
@ -3255,7 +3181,6 @@
|
|||||||
3748186F26A769D60084E870 /* DetailBadge.swift in Sources */,
|
3748186F26A769D60084E870 /* DetailBadge.swift in Sources */,
|
||||||
3744A96128B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */,
|
3744A96128B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */,
|
||||||
372915E72687E3B900F5A35B /* Defaults.swift in Sources */,
|
372915E72687E3B900F5A35B /* Defaults.swift in Sources */,
|
||||||
377E17152928265900894889 /* ListRowSeparator+Backport.swift in Sources */,
|
|
||||||
371CC76929466ED000979C1A /* AccountsView.swift in Sources */,
|
371CC76929466ED000979C1A /* AccountsView.swift in Sources */,
|
||||||
37C3A242272359900087A57A /* Double+Format.swift in Sources */,
|
37C3A242272359900087A57A /* Double+Format.swift in Sources */,
|
||||||
37B795912771DAE0001CF27B /* OpenURLHandler.swift in Sources */,
|
37B795912771DAE0001CF27B /* OpenURLHandler.swift in Sources */,
|
||||||
@ -3442,7 +3367,6 @@
|
|||||||
375EC95F289EEEE000751258 /* QualityProfile.swift in Sources */,
|
375EC95F289EEEE000751258 /* QualityProfile.swift in Sources */,
|
||||||
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
37EAD871267B9ED100D9E01B /* Segment.swift in Sources */,
|
||||||
373C8FE6275B955100CB5936 /* CommentsPage.swift in Sources */,
|
373C8FE6275B955100CB5936 /* CommentsPage.swift in Sources */,
|
||||||
37DD9DBC2785D60300539416 /* FramePreferenceKey.swift in Sources */,
|
|
||||||
375EC974289F2ABF00751258 /* MultiselectRow.swift in Sources */,
|
375EC974289F2ABF00751258 /* MultiselectRow.swift in Sources */,
|
||||||
37EBD8C827AF26B300F1C24B /* AVPlayerBackend.swift in Sources */,
|
37EBD8C827AF26B300F1C24B /* AVPlayerBackend.swift in Sources */,
|
||||||
378E9C3E2945565500B2D696 /* SubscriptionsView.swift in Sources */,
|
378E9C3E2945565500B2D696 /* SubscriptionsView.swift in Sources */,
|
||||||
@ -3496,7 +3420,6 @@
|
|||||||
376BE50D27349108009AD608 /* BrowsingSettings.swift in Sources */,
|
376BE50D27349108009AD608 /* BrowsingSettings.swift in Sources */,
|
||||||
37CFB48728AFE2510070024C /* VideoDescription.swift in Sources */,
|
37CFB48728AFE2510070024C /* VideoDescription.swift in Sources */,
|
||||||
37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */,
|
37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */,
|
||||||
378AE93E274EDFB4006A4EE1 /* Tint+Backport.swift in Sources */,
|
|
||||||
37FFC442272734C3009FFD26 /* Throttle.swift in Sources */,
|
37FFC442272734C3009FFD26 /* Throttle.swift in Sources */,
|
||||||
377FF88D291A60310028EB0B /* OpenVideosModel.swift in Sources */,
|
377FF88D291A60310028EB0B /* OpenVideosModel.swift in Sources */,
|
||||||
37F4AD2828613B81004D0F66 /* Color+Debug.swift in Sources */,
|
37F4AD2828613B81004D0F66 /* Color+Debug.swift in Sources */,
|
||||||
@ -3637,7 +3560,6 @@
|
|||||||
37D9BA0829507F69002586BD /* PlayerControlsSettings.swift in Sources */,
|
37D9BA0829507F69002586BD /* PlayerControlsSettings.swift in Sources */,
|
||||||
37599F32272B42810087F250 /* FavoriteItem.swift in Sources */,
|
37599F32272B42810087F250 /* FavoriteItem.swift in Sources */,
|
||||||
37E8B0EE27B326C00024006F /* TimelineView.swift in Sources */,
|
37E8B0EE27B326C00024006F /* TimelineView.swift in Sources */,
|
||||||
3726386E2948A4B80043702D /* Badge+Backport.swift in Sources */,
|
|
||||||
37141675267A8E10006CA35D /* Country.swift in Sources */,
|
37141675267A8E10006CA35D /* Country.swift in Sources */,
|
||||||
370F500C27CC1821001B35DC /* MPVViewController.swift in Sources */,
|
370F500C27CC1821001B35DC /* MPVViewController.swift in Sources */,
|
||||||
3782B9542755667600990149 /* String+Format.swift in Sources */,
|
3782B9542755667600990149 /* String+Format.swift in Sources */,
|
||||||
@ -3674,7 +3596,6 @@
|
|||||||
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
|
||||||
37C3A24F272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
37C3A24F272360470087A57A /* ChannelPlaylist+Fixtures.swift in Sources */,
|
||||||
3718B9A02921A9620003DB2E /* VideoDetailsOverlay.swift in Sources */,
|
3718B9A02921A9620003DB2E /* VideoDetailsOverlay.swift in Sources */,
|
||||||
377E17162928265900894889 /* ListRowSeparator+Backport.swift in Sources */,
|
|
||||||
37FB28432721B22200A57617 /* ContentItem.swift in Sources */,
|
37FB28432721B22200A57617 /* ContentItem.swift in Sources */,
|
||||||
37D2E0D228B67DBC00F64D52 /* AnimationCompletionObserverModifier.swift in Sources */,
|
37D2E0D228B67DBC00F64D52 /* AnimationCompletionObserverModifier.swift in Sources */,
|
||||||
37AAF2A226741C97007FC770 /* FeedView.swift in Sources */,
|
37AAF2A226741C97007FC770 /* FeedView.swift in Sources */,
|
||||||
@ -3755,7 +3676,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
|
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
|
||||||
@ -3766,7 +3687,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.app.Open-in-Yattee";
|
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.app.Open-in-Yattee";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -3786,7 +3707,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
@ -3798,7 +3719,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.app.Open-in-Yattee";
|
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.app.Open-in-Yattee";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -3817,11 +3738,11 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "net.arekf.Shared-Tests";
|
PRODUCT_BUNDLE_IDENTIFIER = "net.arekf.Shared-Tests";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
@ -3837,11 +3758,11 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "net.arekf.Shared-Tests";
|
PRODUCT_BUNDLE_IDENTIFIER = "net.arekf.Shared-Tests";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
@ -3997,7 +3918,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
|
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
@ -4015,13 +3936,13 @@
|
|||||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
||||||
INFOPLIST_KEY_UIStatusBarHidden = NO;
|
INFOPLIST_KEY_UIStatusBarHidden = NO;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-lstdc++",
|
"-lstdc++",
|
||||||
"-Wl,-no_compact_unwind",
|
"-Wl,-no_compact_unwind",
|
||||||
@ -4050,7 +3971,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
|
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
|
||||||
@ -4065,13 +3986,13 @@
|
|||||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
||||||
INFOPLIST_KEY_UIStatusBarHidden = NO;
|
INFOPLIST_KEY_UIStatusBarHidden = NO;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-lstdc++",
|
"-lstdc++",
|
||||||
"-Wl,-no_compact_unwind",
|
"-Wl,-no_compact_unwind",
|
||||||
@ -4102,7 +4023,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@ -4120,8 +4041,8 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Vendor/mpv/macOS/lib",
|
"$(PROJECT_DIR)/Vendor/mpv/macOS/lib",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
OTHER_LDFLAGS = "-Wl,-no_compact_unwind";
|
OTHER_LDFLAGS = "-Wl,-no_compact_unwind";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = Yattee;
|
PRODUCT_NAME = Yattee;
|
||||||
@ -4144,7 +4065,7 @@
|
|||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
@ -4163,8 +4084,8 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Vendor/mpv/macOS/lib",
|
"$(PROJECT_DIR)/Vendor/mpv/macOS/lib",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
OTHER_LDFLAGS = "-Wl,-no_compact_unwind";
|
OTHER_LDFLAGS = "-Wl,-no_compact_unwind";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.app;
|
||||||
PRODUCT_NAME = Yattee;
|
PRODUCT_NAME = Yattee;
|
||||||
@ -4182,7 +4103,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@ -4190,7 +4111,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-iOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-iOS";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -4206,7 +4127,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@ -4214,7 +4135,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-iOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-iOS";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -4232,7 +4153,7 @@
|
|||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@ -4241,7 +4162,7 @@
|
|||||||
"@loader_path/../Frameworks",
|
"@loader_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-macOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-macOS";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
@ -4257,7 +4178,7 @@
|
|||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@ -4266,7 +4187,7 @@
|
|||||||
"@loader_path/../Frameworks",
|
"@loader_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-macOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "stream.yattee.Tests-macOS";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
@ -4283,7 +4204,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -4299,7 +4220,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-Wl,-no_compact_unwind",
|
"-Wl,-no_compact_unwind",
|
||||||
"-lstdc++",
|
"-lstdc++",
|
||||||
@ -4323,7 +4244,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@ -4340,7 +4261,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"-Wl,-no_compact_unwind",
|
"-Wl,-no_compact_unwind",
|
||||||
"-lstdc++",
|
"-lstdc++",
|
||||||
@ -4364,14 +4285,14 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.YatteeUITests;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.YatteeUITests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = appletvos;
|
SDKROOT = appletvos;
|
||||||
@ -4388,14 +4309,14 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 155;
|
CURRENT_PROJECT_VERSION = 157;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.4.5;
|
MARKETING_VERSION = 1.5;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.YatteeUITests;
|
PRODUCT_BUNDLE_IDENTIFIER = stream.yattee.YatteeUITests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = appletvos;
|
SDKROOT = appletvos;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user