mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Implement trending view actions across platforms
This commit is contained in:
parent
3a780b3d2c
commit
64ff1afa70
@ -1,27 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct TrendingCountrySelectionView: View {
|
|
||||||
@State private var query: String = ""
|
|
||||||
|
|
||||||
@ObservedObject private var store = Store<[Country]>()
|
|
||||||
@Binding var selectedCountry: Country
|
|
||||||
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ScrollView(.vertical) {
|
|
||||||
ForEach(store.collection) { country in
|
|
||||||
Button(country.name) {
|
|
||||||
selectedCountry = country
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(width: 800)
|
|
||||||
}
|
|
||||||
.searchable(text: $query, prompt: Text("Country name or two letter code"))
|
|
||||||
.onChange(of: query) { newQuery in
|
|
||||||
store.replace(Country.search(newQuery))
|
|
||||||
}
|
|
||||||
.background(.thinMaterial)
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,7 @@ import AVKit
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
|
||||||
struct Video: Identifiable {
|
struct Video: Identifiable, Equatable {
|
||||||
let id: String
|
let id: String
|
||||||
var title: String
|
var title: String
|
||||||
var thumbnails: [Thumbnail]
|
var thumbnails: [Thumbnail]
|
||||||
@ -161,12 +161,10 @@ struct Video: Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static let options = [AVURLAssetPreferPreciseDurationAndTimingKey: false]
|
|
||||||
|
|
||||||
private static func extractFormatStreams(from streams: [JSON]) -> [Stream] {
|
private static func extractFormatStreams(from streams: [JSON]) -> [Stream] {
|
||||||
streams.map {
|
streams.map {
|
||||||
SingleAssetStream(
|
SingleAssetStream(
|
||||||
avAsset: AVURLAsset(url: InvidiousAPI.proxyURLForAsset($0["url"].stringValue)!, options: options),
|
avAsset: AVURLAsset(url: InvidiousAPI.proxyURLForAsset($0["url"].stringValue)!),
|
||||||
resolution: Stream.Resolution.from(resolution: $0["resolution"].stringValue)!,
|
resolution: Stream.Resolution.from(resolution: $0["resolution"].stringValue)!,
|
||||||
kind: .stream,
|
kind: .stream,
|
||||||
encoding: $0["encoding"].stringValue
|
encoding: $0["encoding"].stringValue
|
||||||
@ -184,12 +182,16 @@ struct Video: Identifiable {
|
|||||||
|
|
||||||
return videoAssetsURLs.map {
|
return videoAssetsURLs.map {
|
||||||
Stream(
|
Stream(
|
||||||
audioAsset: AVURLAsset(url: InvidiousAPI.proxyURLForAsset(audioAssetURL!["url"].stringValue)!, options: options),
|
audioAsset: AVURLAsset(url: InvidiousAPI.proxyURLForAsset(audioAssetURL!["url"].stringValue)!),
|
||||||
videoAsset: AVURLAsset(url: InvidiousAPI.proxyURLForAsset($0["url"].stringValue)!, options: options),
|
videoAsset: AVURLAsset(url: InvidiousAPI.proxyURLForAsset($0["url"].stringValue)!),
|
||||||
resolution: Stream.Resolution.from(resolution: $0["resolution"].stringValue)!,
|
resolution: Stream.Resolution.from(resolution: $0["resolution"].stringValue)!,
|
||||||
kind: .adaptive,
|
kind: .adaptive,
|
||||||
encoding: $0["encoding"].stringValue
|
encoding: $0["encoding"].stringValue
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func == (lhs: Video, rhs: Video) -> Bool {
|
||||||
|
lhs.id == rhs.id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
3705B180267B4DFB00704544 /* TrendingCountrySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */; };
|
3705B180267B4DFB00704544 /* TrendingCountrySelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelection.swift */; };
|
||||||
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; };
|
3705B182267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; };
|
||||||
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; };
|
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; };
|
||||||
3705B184267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; };
|
3705B184267B4E4900704544 /* TrendingCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B181267B4E4900704544 /* TrendingCategory.swift */; };
|
||||||
@ -129,7 +129,7 @@
|
|||||||
37BD07BC2698AB60003EBB87 /* AppSidebarNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */; };
|
37BD07BC2698AB60003EBB87 /* AppSidebarNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */; };
|
||||||
37BD07BE2698AC96003EBB87 /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07BD2698AC96003EBB87 /* Defaults */; };
|
37BD07BE2698AC96003EBB87 /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07BD2698AC96003EBB87 /* Defaults */; };
|
||||||
37BD07C02698AC97003EBB87 /* Siesta in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07BF2698AC97003EBB87 /* Siesta */; };
|
37BD07C02698AC97003EBB87 /* Siesta in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07BF2698AC97003EBB87 /* Siesta */; };
|
||||||
37BD07C12698AD3B003EBB87 /* TrendingCountrySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */; };
|
37BD07C12698AD3B003EBB87 /* TrendingCountrySelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelection.swift */; };
|
||||||
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07B42698AA4D003EBB87 /* ContentView.swift */; };
|
37BD07C32698AD4F003EBB87 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BD07B42698AA4D003EBB87 /* ContentView.swift */; };
|
||||||
37BD07C72698B27B003EBB87 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07C62698B27B003EBB87 /* Introspect */; };
|
37BD07C72698B27B003EBB87 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 37BD07C62698B27B003EBB87 /* Introspect */; };
|
||||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
|
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* AppTabNavigation.swift */; };
|
||||||
@ -148,7 +148,7 @@
|
|||||||
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; };
|
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; };
|
||||||
37C7A1D6267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; };
|
37C7A1D6267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; };
|
||||||
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; };
|
37C7A1D7267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1D4267BFD9D0010EAD6 /* SponsorBlockSegment.swift */; };
|
||||||
37C7A1DA267CACF50010EAD6 /* TrendingCountrySelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */; };
|
37C7A1DA267CACF50010EAD6 /* TrendingCountrySelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3705B17F267B4DFB00704544 /* TrendingCountrySelection.swift */; };
|
||||||
37C7A1DC267CE9D90010EAD6 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1DB267CE9D90010EAD6 /* Profile.swift */; };
|
37C7A1DC267CE9D90010EAD6 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1DB267CE9D90010EAD6 /* Profile.swift */; };
|
||||||
37C7A1DD267CE9D90010EAD6 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1DB267CE9D90010EAD6 /* Profile.swift */; };
|
37C7A1DD267CE9D90010EAD6 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1DB267CE9D90010EAD6 /* Profile.swift */; };
|
||||||
37C7A1DE267CE9D90010EAD6 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1DB267CE9D90010EAD6 /* Profile.swift */; };
|
37C7A1DE267CE9D90010EAD6 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7A1DB267CE9D90010EAD6 /* Profile.swift */; };
|
||||||
@ -210,7 +210,7 @@
|
|||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCountrySelectionView.swift; sourceTree = "<group>"; };
|
3705B17F267B4DFB00704544 /* TrendingCountrySelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCountrySelection.swift; sourceTree = "<group>"; };
|
||||||
3705B181267B4E4900704544 /* TrendingCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCategory.swift; sourceTree = "<group>"; };
|
3705B181267B4E4900704544 /* TrendingCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCategory.swift; sourceTree = "<group>"; };
|
||||||
3711403E26B206A6005B3555 /* SearchState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchState.swift; sourceTree = "<group>"; };
|
3711403E26B206A6005B3555 /* SearchState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchState.swift; sourceTree = "<group>"; };
|
||||||
371231832683E62F0000B307 /* VideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosView.swift; sourceTree = "<group>"; };
|
371231832683E62F0000B307 /* VideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosView.swift; sourceTree = "<group>"; };
|
||||||
@ -412,6 +412,7 @@
|
|||||||
37AAF27F26737550007FC770 /* SearchView.swift */,
|
37AAF27F26737550007FC770 /* SearchView.swift */,
|
||||||
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
|
||||||
37AAF2932674086B007FC770 /* TabSelection.swift */,
|
37AAF2932674086B007FC770 /* TabSelection.swift */,
|
||||||
|
3705B17F267B4DFB00704544 /* TrendingCountrySelection.swift */,
|
||||||
3714166E267A8ACC006CA35D /* TrendingView.swift */,
|
3714166E267A8ACC006CA35D /* TrendingView.swift */,
|
||||||
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
|
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
|
||||||
37AAF29926740A01007FC770 /* VideosListView.swift */,
|
37AAF29926740A01007FC770 /* VideosListView.swift */,
|
||||||
@ -462,7 +463,6 @@
|
|||||||
37B76E95268747C900CE5671 /* OptionsView.swift */,
|
37B76E95268747C900CE5671 /* OptionsView.swift */,
|
||||||
373CFAEA26975CBF003CB2C6 /* PlaylistFormView.swift */,
|
373CFAEA26975CBF003CB2C6 /* PlaylistFormView.swift */,
|
||||||
373CFAC52696617C003CB2C6 /* SearchOptionsView.swift */,
|
373CFAC52696617C003CB2C6 /* SearchOptionsView.swift */,
|
||||||
3705B17F267B4DFB00704544 /* TrendingCountrySelectionView.swift */,
|
|
||||||
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */,
|
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */,
|
||||||
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
|
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
|
||||||
37B17DA3268A285E006AEE9B /* VideoDetailsView.swift */,
|
37B17DA3268A285E006AEE9B /* VideoDetailsView.swift */,
|
||||||
@ -758,7 +758,7 @@
|
|||||||
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
37BD07C82698B71C003EBB87 /* AppTabNavigation.swift in Sources */,
|
||||||
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
37EAD86B267B9C5600D9E01B /* SponsorBlockAPI.swift in Sources */,
|
||||||
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
37BD07B52698AA4D003EBB87 /* ContentView.swift in Sources */,
|
||||||
37C7A1DA267CACF50010EAD6 /* TrendingCountrySelectionView.swift in Sources */,
|
37C7A1DA267CACF50010EAD6 /* TrendingCountrySelection.swift in Sources */,
|
||||||
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
|
||||||
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
37BE0BD626A1D4A90092E2DB /* PlayerViewController.swift in Sources */,
|
||||||
3711403F26B206A6005B3555 /* SearchState.swift in Sources */,
|
3711403F26B206A6005B3555 /* SearchState.swift in Sources */,
|
||||||
@ -851,7 +851,7 @@
|
|||||||
377FC7DE267A082100A6BBAF /* VideosListView.swift in Sources */,
|
377FC7DE267A082100A6BBAF /* VideosListView.swift in Sources */,
|
||||||
37D4B19826717E1500C925CA /* Video.swift in Sources */,
|
37D4B19826717E1500C925CA /* Video.swift in Sources */,
|
||||||
37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */,
|
37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */,
|
||||||
37BD07C12698AD3B003EBB87 /* TrendingCountrySelectionView.swift in Sources */,
|
37BD07C12698AD3B003EBB87 /* TrendingCountrySelection.swift in Sources */,
|
||||||
3711404026B206A6005B3555 /* SearchState.swift in Sources */,
|
3711404026B206A6005B3555 /* SearchState.swift in Sources */,
|
||||||
37BE0BD026A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
37BE0BD026A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
|
||||||
373CFAEC26975CBF003CB2C6 /* PlaylistFormView.swift in Sources */,
|
373CFAEC26975CBF003CB2C6 /* PlaylistFormView.swift in Sources */,
|
||||||
@ -925,7 +925,7 @@
|
|||||||
3711404126B206A6005B3555 /* SearchState.swift in Sources */,
|
3711404126B206A6005B3555 /* SearchState.swift in Sources */,
|
||||||
379775952689365600DD52A8 /* Array+Next.swift in Sources */,
|
379775952689365600DD52A8 /* Array+Next.swift in Sources */,
|
||||||
37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */,
|
37AAF28A2673AB89007FC770 /* ChannelView.swift in Sources */,
|
||||||
3705B180267B4DFB00704544 /* TrendingCountrySelectionView.swift in Sources */,
|
3705B180267B4DFB00704544 /* TrendingCountrySelection.swift in Sources */,
|
||||||
373CFACD26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
373CFACD26966264003CB2C6 /* SearchQuery.swift in Sources */,
|
||||||
37141675267A8E10006CA35D /* Country.swift in Sources */,
|
37141675267A8E10006CA35D /* Country.swift in Sources */,
|
||||||
373CFAC42696616C003CB2C6 /* CoverSectionRowView.swift in Sources */,
|
373CFAC42696616C003CB2C6 /* CoverSectionRowView.swift in Sources */,
|
||||||
|
@ -31,9 +31,10 @@ struct AppSidebarNavigation: View {
|
|||||||
var content: some View {
|
var content: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
sidebar
|
sidebar
|
||||||
|
.frame(minWidth: 180)
|
||||||
|
|
||||||
Text("Select section")
|
Text("Select section")
|
||||||
.frame(maxWidth: 600)
|
|
||||||
Text("Select video")
|
Text("Select video")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,512 +1,234 @@
|
|||||||
// swiftlint:disable switch_case_on_newline
|
// swiftlint:disable switch_case_on_newline
|
||||||
|
|
||||||
enum Country: String, CaseIterable, Identifiable {
|
enum Country: String, CaseIterable, Identifiable, Hashable {
|
||||||
var id: String {
|
var id: String {
|
||||||
rawValue
|
rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
case af = "AF"
|
func hash(into hasher: inout Hasher) {
|
||||||
case ax = "AX"
|
hasher.combine(id)
|
||||||
case al = "AL"
|
}
|
||||||
|
|
||||||
case dz = "DZ"
|
case dz = "DZ"
|
||||||
case `as` = "AS"
|
|
||||||
case ad = "AD"
|
|
||||||
case ao = "AO"
|
|
||||||
case ai = "AI"
|
|
||||||
case aq = "AQ"
|
|
||||||
case ag = "AG"
|
|
||||||
case ar = "AR"
|
case ar = "AR"
|
||||||
case am = "AM"
|
|
||||||
case aw = "AW"
|
|
||||||
case au = "AU"
|
case au = "AU"
|
||||||
case at = "AT"
|
case at = "AT"
|
||||||
case az = "AZ"
|
case az = "AZ"
|
||||||
case bs = "BS"
|
|
||||||
case bh = "BH"
|
case bh = "BH"
|
||||||
case bd = "BD"
|
case bd = "BD"
|
||||||
case bb = "BB"
|
|
||||||
case by = "BY"
|
case by = "BY"
|
||||||
case be = "BE"
|
case be = "BE"
|
||||||
case bz = "BZ"
|
|
||||||
case bj = "BJ"
|
|
||||||
case bm = "BM"
|
|
||||||
case bt = "BT"
|
|
||||||
case bo = "BO"
|
case bo = "BO"
|
||||||
case bq = "BQ"
|
|
||||||
case ba = "BA"
|
case ba = "BA"
|
||||||
case bw = "BW"
|
|
||||||
case bv = "BV"
|
|
||||||
case br = "BR"
|
case br = "BR"
|
||||||
case io = "IO"
|
|
||||||
case bn = "BN"
|
|
||||||
case bg = "BG"
|
case bg = "BG"
|
||||||
case bf = "BF"
|
|
||||||
case bi = "BI"
|
|
||||||
case cv = "CV"
|
|
||||||
case kh = "KH"
|
|
||||||
case cm = "CM"
|
|
||||||
case ca = "CA"
|
case ca = "CA"
|
||||||
case ky = "KY"
|
|
||||||
case cf = "CF"
|
|
||||||
case td = "TD"
|
|
||||||
case cl = "CL"
|
case cl = "CL"
|
||||||
case cn = "CN"
|
|
||||||
case cx = "CX"
|
|
||||||
case cc = "CC"
|
|
||||||
case co = "CO"
|
case co = "CO"
|
||||||
case km = "KM"
|
|
||||||
case cg = "CG"
|
|
||||||
case cd = "CD"
|
|
||||||
case ck = "CK"
|
|
||||||
case cr = "CR"
|
case cr = "CR"
|
||||||
case ci = "CI"
|
|
||||||
case hr = "HR"
|
case hr = "HR"
|
||||||
case cu = "CU"
|
|
||||||
case cw = "CW"
|
|
||||||
case cy = "CY"
|
case cy = "CY"
|
||||||
case cz = "CZ"
|
case cz = "CZ"
|
||||||
case dk = "DK"
|
case dk = "DK"
|
||||||
case dj = "DJ"
|
|
||||||
case dm = "DM"
|
|
||||||
case `do` = "DO"
|
case `do` = "DO"
|
||||||
case ec = "EC"
|
case ec = "EC"
|
||||||
case eg = "EG"
|
case eg = "EG"
|
||||||
case sv = "SV"
|
case sv = "SV"
|
||||||
case gq = "GQ"
|
|
||||||
case er = "ER"
|
|
||||||
case ee = "EE"
|
case ee = "EE"
|
||||||
case et = "ET"
|
|
||||||
case fk = "FK"
|
|
||||||
case fo = "FO"
|
|
||||||
case fj = "FJ"
|
|
||||||
case fi = "FI"
|
case fi = "FI"
|
||||||
case fr = "FR"
|
case fr = "FR"
|
||||||
case gf = "GF"
|
|
||||||
case pf = "PF"
|
|
||||||
case tf = "TF"
|
|
||||||
case ga = "GA"
|
|
||||||
case gm = "GM"
|
|
||||||
case ge = "GE"
|
case ge = "GE"
|
||||||
case de = "DE"
|
case de = "DE"
|
||||||
case gh = "GH"
|
case gh = "GH"
|
||||||
case gi = "GI"
|
|
||||||
case gr = "GR"
|
case gr = "GR"
|
||||||
case gl = "GL"
|
|
||||||
case gd = "GD"
|
|
||||||
case gp = "GP"
|
|
||||||
case gu = "GU"
|
|
||||||
case gt = "GT"
|
case gt = "GT"
|
||||||
case gg = "GG"
|
|
||||||
case gn = "GN"
|
|
||||||
case gw = "GW"
|
|
||||||
case gy = "GY"
|
|
||||||
case ht = "HT"
|
|
||||||
case hm = "HM"
|
|
||||||
case va = "VA"
|
|
||||||
case hn = "HN"
|
case hn = "HN"
|
||||||
case hk = "HK"
|
case hk = "HK"
|
||||||
case hu = "HU"
|
case hu = "HU"
|
||||||
case `is` = "IS"
|
case `is` = "IS"
|
||||||
case `in` = "IN"
|
case `in` = "IN"
|
||||||
case id = "ID"
|
case id = "ID"
|
||||||
case ir = "IR"
|
|
||||||
case iq = "IQ"
|
case iq = "IQ"
|
||||||
case ie = "IE"
|
case ie = "IE"
|
||||||
case im = "IM"
|
|
||||||
case il = "IL"
|
case il = "IL"
|
||||||
case it = "IT"
|
case it = "IT"
|
||||||
case jm = "JM"
|
case jm = "JM"
|
||||||
case jp = "JP"
|
case jp = "JP"
|
||||||
case je = "JE"
|
|
||||||
case jo = "JO"
|
case jo = "JO"
|
||||||
case kz = "KZ"
|
case kz = "KZ"
|
||||||
case ke = "KE"
|
case ke = "KE"
|
||||||
case ki = "KI"
|
|
||||||
case kp = "KP"
|
|
||||||
case kr = "KR"
|
case kr = "KR"
|
||||||
case kw = "KW"
|
case kw = "KW"
|
||||||
case kg = "KG"
|
|
||||||
case la = "LA"
|
|
||||||
case lv = "LV"
|
case lv = "LV"
|
||||||
case lb = "LB"
|
case lb = "LB"
|
||||||
case ls = "LS"
|
|
||||||
case lr = "LR"
|
|
||||||
case ly = "LY"
|
case ly = "LY"
|
||||||
case li = "LI"
|
case li = "LI"
|
||||||
case lt = "LT"
|
case lt = "LT"
|
||||||
case lu = "LU"
|
case lu = "LU"
|
||||||
case mo = "MO"
|
|
||||||
case mk = "MK"
|
case mk = "MK"
|
||||||
case mg = "MG"
|
|
||||||
case mw = "MW"
|
|
||||||
case my = "MY"
|
case my = "MY"
|
||||||
case mv = "MV"
|
|
||||||
case ml = "ML"
|
|
||||||
case mt = "MT"
|
case mt = "MT"
|
||||||
case mh = "MH"
|
|
||||||
case mq = "MQ"
|
|
||||||
case mr = "MR"
|
|
||||||
case mu = "MU"
|
|
||||||
case yt = "YT"
|
|
||||||
case mx = "MX"
|
case mx = "MX"
|
||||||
case fm = "FM"
|
|
||||||
case md = "MD"
|
|
||||||
case mc = "MC"
|
|
||||||
case mn = "MN"
|
|
||||||
case me = "ME"
|
case me = "ME"
|
||||||
case ms = "MS"
|
|
||||||
case ma = "MA"
|
case ma = "MA"
|
||||||
case mz = "MZ"
|
|
||||||
case mm = "MM"
|
|
||||||
case na = "NA"
|
|
||||||
case nr = "NR"
|
|
||||||
case np = "NP"
|
case np = "NP"
|
||||||
case nl = "NL"
|
case nl = "NL"
|
||||||
case nc = "NC"
|
|
||||||
case nz = "NZ"
|
case nz = "NZ"
|
||||||
case ni = "NI"
|
case ni = "NI"
|
||||||
case ne = "NE"
|
|
||||||
case ng = "NG"
|
case ng = "NG"
|
||||||
case nu = "NU"
|
|
||||||
case nf = "NF"
|
|
||||||
case mp = "MP"
|
|
||||||
case no = "NO"
|
case no = "NO"
|
||||||
case om = "OM"
|
case om = "OM"
|
||||||
case pk = "PK"
|
case pk = "PK"
|
||||||
case pw = "PW"
|
|
||||||
case ps = "PS"
|
|
||||||
case pa = "PA"
|
case pa = "PA"
|
||||||
case pg = "PG"
|
case pg = "PG"
|
||||||
case py = "PY"
|
case py = "PY"
|
||||||
case pe = "PE"
|
case pe = "PE"
|
||||||
case ph = "PH"
|
case ph = "PH"
|
||||||
case pn = "PN"
|
|
||||||
case pl = "PL"
|
case pl = "PL"
|
||||||
case pt = "PT"
|
case pt = "PT"
|
||||||
case pr = "PR"
|
case pr = "PR"
|
||||||
case qa = "QA"
|
case qa = "QA"
|
||||||
case re = "RE"
|
|
||||||
case ro = "RO"
|
case ro = "RO"
|
||||||
case ru = "RU"
|
case ru = "RU"
|
||||||
case rw = "RW"
|
|
||||||
case bl = "BL"
|
|
||||||
case sh = "SH"
|
|
||||||
case kn = "KN"
|
|
||||||
case lc = "LC"
|
|
||||||
case mf = "MF"
|
|
||||||
case pm = "PM"
|
|
||||||
case vc = "VC"
|
|
||||||
case ws = "WS"
|
|
||||||
case sm = "SM"
|
|
||||||
case st = "ST"
|
|
||||||
case sa = "SA"
|
case sa = "SA"
|
||||||
case sn = "SN"
|
case sn = "SN"
|
||||||
case rs = "RS"
|
case rs = "RS"
|
||||||
case sc = "SC"
|
|
||||||
case sl = "SL"
|
|
||||||
case sg = "SG"
|
case sg = "SG"
|
||||||
case sx = "SX"
|
|
||||||
case sk = "SK"
|
case sk = "SK"
|
||||||
case si = "SI"
|
case si = "SI"
|
||||||
case sb = "SB"
|
|
||||||
case so = "SO"
|
|
||||||
case za = "ZA"
|
case za = "ZA"
|
||||||
case gs = "GS"
|
|
||||||
case ss = "SS"
|
|
||||||
case es = "ES"
|
case es = "ES"
|
||||||
case lk = "LK"
|
case lk = "LK"
|
||||||
case sd = "SD"
|
|
||||||
case sr = "SR"
|
|
||||||
case sj = "SJ"
|
|
||||||
case sz = "SZ"
|
|
||||||
case se = "SE"
|
case se = "SE"
|
||||||
case ch = "CH"
|
case ch = "CH"
|
||||||
case sy = "SY"
|
|
||||||
case tw = "TW"
|
case tw = "TW"
|
||||||
case tj = "TJ"
|
|
||||||
case tz = "TZ"
|
case tz = "TZ"
|
||||||
case th = "TH"
|
case th = "TH"
|
||||||
case tl = "TL"
|
|
||||||
case tg = "TG"
|
|
||||||
case tk = "TK"
|
|
||||||
case to = "TO"
|
|
||||||
case tt = "TT"
|
|
||||||
case tn = "TN"
|
case tn = "TN"
|
||||||
case tr = "TR"
|
case tr = "TR"
|
||||||
case tm = "TM"
|
|
||||||
case tc = "TC"
|
|
||||||
case tv = "TV"
|
|
||||||
case ug = "UG"
|
case ug = "UG"
|
||||||
case ua = "UA"
|
case ua = "UA"
|
||||||
case ae = "AE"
|
case ae = "AE"
|
||||||
case gb = "GB"
|
case gb = "GB"
|
||||||
case us = "US"
|
case us = "US"
|
||||||
case um = "UM"
|
|
||||||
case uy = "UY"
|
case uy = "UY"
|
||||||
case uz = "UZ"
|
|
||||||
case vu = "VU"
|
|
||||||
case ve = "VE"
|
case ve = "VE"
|
||||||
case vn = "VN"
|
case vn = "VN"
|
||||||
case vg = "VG"
|
|
||||||
case vi = "VI"
|
case vi = "VI"
|
||||||
case wf = "WF"
|
|
||||||
case eh = "EH"
|
|
||||||
case ye = "YE"
|
case ye = "YE"
|
||||||
case zm = "ZM"
|
|
||||||
case zw = "ZW"
|
case zw = "ZW"
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Country {
|
extension Country {
|
||||||
var name: String {
|
var name: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .af: return "Afghanistan"
|
|
||||||
case .ax: return "Åland Islands"
|
|
||||||
case .al: return "Albania"
|
|
||||||
case .dz: return "Algeria"
|
case .dz: return "Algeria"
|
||||||
case .as: return "American Samoa"
|
|
||||||
case .ad: return "Andorra"
|
|
||||||
case .ao: return "Angola"
|
|
||||||
case .ai: return "Anguilla"
|
|
||||||
case .aq: return "Antarctica"
|
|
||||||
case .ag: return "Antigua and Barbuda"
|
|
||||||
case .ar: return "Argentina"
|
case .ar: return "Argentina"
|
||||||
case .am: return "Armenia"
|
|
||||||
case .aw: return "Aruba"
|
|
||||||
case .au: return "Australia"
|
case .au: return "Australia"
|
||||||
case .at: return "Austria"
|
case .at: return "Austria"
|
||||||
case .az: return "Azerbaijan"
|
case .az: return "Azerbaijan"
|
||||||
case .bs: return "Bahamas"
|
|
||||||
case .bh: return "Bahrain"
|
case .bh: return "Bahrain"
|
||||||
case .bd: return "Bangladesh"
|
case .bd: return "Bangladesh"
|
||||||
case .bb: return "Barbados"
|
|
||||||
case .by: return "Belarus"
|
case .by: return "Belarus"
|
||||||
case .be: return "Belgium"
|
case .be: return "Belgium"
|
||||||
case .bz: return "Belize"
|
|
||||||
case .bj: return "Benin"
|
|
||||||
case .bm: return "Bermuda"
|
|
||||||
case .bt: return "Bhutan"
|
|
||||||
case .bo: return "Bolivia (Plurinational State of)"
|
case .bo: return "Bolivia (Plurinational State of)"
|
||||||
case .bq: return "Bonaire, Sint Eustatius and Saba"
|
|
||||||
case .ba: return "Bosnia and Herzegovina"
|
case .ba: return "Bosnia and Herzegovina"
|
||||||
case .bw: return "Botswana"
|
|
||||||
case .bv: return "Bouvet Island"
|
|
||||||
case .br: return "Brazil"
|
case .br: return "Brazil"
|
||||||
case .io: return "British Indian Ocean Territory"
|
|
||||||
case .bn: return "Brunei Darussalam"
|
|
||||||
case .bg: return "Bulgaria"
|
case .bg: return "Bulgaria"
|
||||||
case .bf: return "Burkina Faso"
|
|
||||||
case .bi: return "Burundi"
|
|
||||||
case .cv: return "Cabo Verde"
|
|
||||||
case .kh: return "Cambodia"
|
|
||||||
case .cm: return "Cameroon"
|
|
||||||
case .ca: return "Canada"
|
case .ca: return "Canada"
|
||||||
case .ky: return "Cayman Islands"
|
|
||||||
case .cf: return "Central African Republic"
|
|
||||||
case .td: return "Chad"
|
|
||||||
case .cl: return "Chile"
|
case .cl: return "Chile"
|
||||||
case .cn: return "China"
|
|
||||||
case .cx: return "Christmas Island"
|
|
||||||
case .cc: return "Cocos (Keeling) Islands"
|
|
||||||
case .co: return "Colombia"
|
case .co: return "Colombia"
|
||||||
case .km: return "Comoros"
|
|
||||||
case .cg: return "Congo"
|
|
||||||
case .cd: return "Congo (Democratic Republic of the)"
|
|
||||||
case .ck: return "Cook Islands"
|
|
||||||
case .cr: return "Costa Rica"
|
case .cr: return "Costa Rica"
|
||||||
case .ci: return "Côte d'Ivoire"
|
|
||||||
case .hr: return "Croatia"
|
case .hr: return "Croatia"
|
||||||
case .cu: return "Cuba"
|
|
||||||
case .cw: return "Curaçao"
|
|
||||||
case .cy: return "Cyprus"
|
case .cy: return "Cyprus"
|
||||||
case .cz: return "Czechia"
|
case .cz: return "Czechia"
|
||||||
case .dk: return "Denmark"
|
case .dk: return "Denmark"
|
||||||
case .dj: return "Djibouti"
|
|
||||||
case .dm: return "Dominica"
|
|
||||||
case .do: return "Dominican Republic"
|
case .do: return "Dominican Republic"
|
||||||
case .ec: return "Ecuador"
|
case .ec: return "Ecuador"
|
||||||
case .eg: return "Egypt"
|
case .eg: return "Egypt"
|
||||||
case .sv: return "El Salvador"
|
case .sv: return "El Salvador"
|
||||||
case .gq: return "Equatorial Guinea"
|
|
||||||
case .er: return "Eritrea"
|
|
||||||
case .ee: return "Estonia"
|
case .ee: return "Estonia"
|
||||||
case .et: return "Ethiopia"
|
|
||||||
case .fk: return "Falkland Islands (Malvinas)"
|
|
||||||
case .fo: return "Faroe Islands"
|
|
||||||
case .fj: return "Fiji"
|
|
||||||
case .fi: return "Finland"
|
case .fi: return "Finland"
|
||||||
case .fr: return "France"
|
case .fr: return "France"
|
||||||
case .gf: return "French Guiana"
|
|
||||||
case .pf: return "French Polynesia"
|
|
||||||
case .tf: return "French Southern Territories"
|
|
||||||
case .ga: return "Gabon"
|
|
||||||
case .gm: return "Gambia"
|
|
||||||
case .ge: return "Georgia"
|
case .ge: return "Georgia"
|
||||||
case .de: return "Germany"
|
case .de: return "Germany"
|
||||||
case .gh: return "Ghana"
|
case .gh: return "Ghana"
|
||||||
case .gi: return "Gibraltar"
|
|
||||||
case .gr: return "Greece"
|
case .gr: return "Greece"
|
||||||
case .gl: return "Greenland"
|
|
||||||
case .gd: return "Grenada"
|
|
||||||
case .gp: return "Guadeloupe"
|
|
||||||
case .gu: return "Guam"
|
|
||||||
case .gt: return "Guatemala"
|
case .gt: return "Guatemala"
|
||||||
case .gg: return "Guernsey"
|
|
||||||
case .gn: return "Guinea"
|
|
||||||
case .gw: return "Guinea-Bissau"
|
|
||||||
case .gy: return "Guyana"
|
|
||||||
case .ht: return "Haiti"
|
|
||||||
case .hm: return "Heard Island and McDonald Islands"
|
|
||||||
case .va: return "Holy See"
|
|
||||||
case .hn: return "Honduras"
|
case .hn: return "Honduras"
|
||||||
case .hk: return "Hong Kong"
|
case .hk: return "Hong Kong"
|
||||||
case .hu: return "Hungary"
|
case .hu: return "Hungary"
|
||||||
case .is: return "Iceland"
|
case .is: return "Iceland"
|
||||||
case .in: return "India"
|
case .in: return "India"
|
||||||
case .id: return "Indonesia"
|
case .id: return "Indonesia"
|
||||||
case .ir: return "Iran (Islamic Republic of)"
|
|
||||||
case .iq: return "Iraq"
|
case .iq: return "Iraq"
|
||||||
case .ie: return "Ireland"
|
case .ie: return "Ireland"
|
||||||
case .im: return "Isle of Man"
|
|
||||||
case .il: return "Israel"
|
case .il: return "Israel"
|
||||||
case .it: return "Italy"
|
case .it: return "Italy"
|
||||||
case .jm: return "Jamaica"
|
case .jm: return "Jamaica"
|
||||||
case .jp: return "Japan"
|
case .jp: return "Japan"
|
||||||
case .je: return "Jersey"
|
|
||||||
case .jo: return "Jordan"
|
case .jo: return "Jordan"
|
||||||
case .kz: return "Kazakhstan"
|
case .kz: return "Kazakhstan"
|
||||||
case .ke: return "Kenya"
|
case .ke: return "Kenya"
|
||||||
case .ki: return "Kiribati"
|
|
||||||
case .kp: return "Korea (Democratic People's Republic of)"
|
|
||||||
case .kr: return "Korea (Republic of)"
|
case .kr: return "Korea (Republic of)"
|
||||||
case .kw: return "Kuwait"
|
case .kw: return "Kuwait"
|
||||||
case .kg: return "Kyrgyzstan"
|
|
||||||
case .la: return "Lao People's Democratic Republic"
|
|
||||||
case .lv: return "Latvia"
|
case .lv: return "Latvia"
|
||||||
case .lb: return "Lebanon"
|
case .lb: return "Lebanon"
|
||||||
case .ls: return "Lesotho"
|
|
||||||
case .lr: return "Liberia"
|
|
||||||
case .ly: return "Libya"
|
case .ly: return "Libya"
|
||||||
case .li: return "Liechtenstein"
|
case .li: return "Liechtenstein"
|
||||||
case .lt: return "Lithuania"
|
case .lt: return "Lithuania"
|
||||||
case .lu: return "Luxembourg"
|
case .lu: return "Luxembourg"
|
||||||
case .mo: return "Macao"
|
|
||||||
case .mk: return "Macedonia (the former Yugoslav Republic of)"
|
case .mk: return "Macedonia (the former Yugoslav Republic of)"
|
||||||
case .mg: return "Madagascar"
|
|
||||||
case .mw: return "Malawi"
|
|
||||||
case .my: return "Malaysia"
|
case .my: return "Malaysia"
|
||||||
case .mv: return "Maldives"
|
|
||||||
case .ml: return "Mali"
|
|
||||||
case .mt: return "Malta"
|
case .mt: return "Malta"
|
||||||
case .mh: return "Marshall Islands"
|
|
||||||
case .mq: return "Martinique"
|
|
||||||
case .mr: return "Mauritania"
|
|
||||||
case .mu: return "Mauritius"
|
|
||||||
case .yt: return "Mayotte"
|
|
||||||
case .mx: return "Mexico"
|
case .mx: return "Mexico"
|
||||||
case .fm: return "Micronesia (Federated States of)"
|
|
||||||
case .md: return "Moldova (Republic of)"
|
|
||||||
case .mc: return "Monaco"
|
|
||||||
case .mn: return "Mongolia"
|
|
||||||
case .me: return "Montenegro"
|
case .me: return "Montenegro"
|
||||||
case .ms: return "Montserrat"
|
|
||||||
case .ma: return "Morocco"
|
case .ma: return "Morocco"
|
||||||
case .mz: return "Mozambique"
|
|
||||||
case .mm: return "Myanmar"
|
|
||||||
case .na: return "Namibia"
|
|
||||||
case .nr: return "Nauru"
|
|
||||||
case .np: return "Nepal"
|
case .np: return "Nepal"
|
||||||
case .nl: return "Netherlands"
|
case .nl: return "Netherlands"
|
||||||
case .nc: return "New Caledonia"
|
|
||||||
case .nz: return "New Zealand"
|
case .nz: return "New Zealand"
|
||||||
case .ni: return "Nicaragua"
|
case .ni: return "Nicaragua"
|
||||||
case .ne: return "Niger"
|
|
||||||
case .ng: return "Nigeria"
|
case .ng: return "Nigeria"
|
||||||
case .nu: return "Niue"
|
|
||||||
case .nf: return "Norfolk Island"
|
|
||||||
case .mp: return "Northern Mariana Islands"
|
|
||||||
case .no: return "Norway"
|
case .no: return "Norway"
|
||||||
case .om: return "Oman"
|
case .om: return "Oman"
|
||||||
case .pk: return "Pakistan"
|
case .pk: return "Pakistan"
|
||||||
case .pw: return "Palau"
|
|
||||||
case .ps: return "Palestine, State of"
|
|
||||||
case .pa: return "Panama"
|
case .pa: return "Panama"
|
||||||
case .pg: return "Papua New Guinea"
|
case .pg: return "Papua New Guinea"
|
||||||
case .py: return "Paraguay"
|
case .py: return "Paraguay"
|
||||||
case .pe: return "Peru"
|
case .pe: return "Peru"
|
||||||
case .ph: return "Philippines"
|
case .ph: return "Philippines"
|
||||||
case .pn: return "Pitcairn"
|
|
||||||
case .pl: return "Poland"
|
case .pl: return "Poland"
|
||||||
case .pt: return "Portugal"
|
case .pt: return "Portugal"
|
||||||
case .pr: return "Puerto Rico"
|
case .pr: return "Puerto Rico"
|
||||||
case .qa: return "Qatar"
|
case .qa: return "Qatar"
|
||||||
case .re: return "Réunion"
|
|
||||||
case .ro: return "Romania"
|
case .ro: return "Romania"
|
||||||
case .ru: return "Russian Federation"
|
case .ru: return "Russian Federation"
|
||||||
case .rw: return "Rwanda"
|
|
||||||
case .bl: return "Saint Barthélemy"
|
|
||||||
case .sh: return "Saint Helena, Ascension and Tristan da Cunha"
|
|
||||||
case .kn: return "Saint Kitts and Nevis"
|
|
||||||
case .lc: return "Saint Lucia"
|
|
||||||
case .mf: return "Saint Martin (French part)"
|
|
||||||
case .pm: return "Saint Pierre and Miquelon"
|
|
||||||
case .vc: return "Saint Vincent and the Grenadines"
|
|
||||||
case .ws: return "Samoa"
|
|
||||||
case .sm: return "San Marino"
|
|
||||||
case .st: return "Sao Tome and Principe"
|
|
||||||
case .sa: return "Saudi Arabia"
|
case .sa: return "Saudi Arabia"
|
||||||
case .sn: return "Senegal"
|
case .sn: return "Senegal"
|
||||||
case .rs: return "Serbia"
|
case .rs: return "Serbia"
|
||||||
case .sc: return "Seychelles"
|
|
||||||
case .sl: return "Sierra Leone"
|
|
||||||
case .sg: return "Singapore"
|
case .sg: return "Singapore"
|
||||||
case .sx: return "Sint Maarten (Dutch part)"
|
|
||||||
case .sk: return "Slovakia"
|
case .sk: return "Slovakia"
|
||||||
case .si: return "Slovenia"
|
case .si: return "Slovenia"
|
||||||
case .sb: return "Solomon Islands"
|
|
||||||
case .so: return "Somalia"
|
|
||||||
case .za: return "South Africa"
|
case .za: return "South Africa"
|
||||||
case .gs: return "South Georgia and the South Sandwich Islands"
|
|
||||||
case .ss: return "South Sudan"
|
|
||||||
case .es: return "Spain"
|
case .es: return "Spain"
|
||||||
case .lk: return "Sri Lanka"
|
case .lk: return "Sri Lanka"
|
||||||
case .sd: return "Sudan"
|
|
||||||
case .sr: return "Suriname"
|
|
||||||
case .sj: return "Svalbard and Jan Mayen"
|
|
||||||
case .sz: return "Swaziland"
|
|
||||||
case .se: return "Sweden"
|
case .se: return "Sweden"
|
||||||
case .ch: return "Switzerland"
|
case .ch: return "Switzerland"
|
||||||
case .sy: return "Syrian Arab Republic"
|
|
||||||
case .tw: return "Taiwan, Province of China[a]"
|
case .tw: return "Taiwan, Province of China[a]"
|
||||||
case .tj: return "Tajikistan"
|
|
||||||
case .tz: return "Tanzania, United Republic of"
|
case .tz: return "Tanzania, United Republic of"
|
||||||
case .th: return "Thailand"
|
case .th: return "Thailand"
|
||||||
case .tl: return "Timor-Leste"
|
|
||||||
case .tg: return "Togo"
|
|
||||||
case .tk: return "Tokelau"
|
|
||||||
case .to: return "Tonga"
|
|
||||||
case .tt: return "Trinidad and Tobago"
|
|
||||||
case .tn: return "Tunisia"
|
case .tn: return "Tunisia"
|
||||||
case .tr: return "Turkey"
|
case .tr: return "Turkey"
|
||||||
case .tm: return "Turkmenistan"
|
|
||||||
case .tc: return "Turks and Caicos Islands"
|
|
||||||
case .tv: return "Tuvalu"
|
|
||||||
case .ug: return "Uganda"
|
case .ug: return "Uganda"
|
||||||
case .ua: return "Ukraine"
|
case .ua: return "Ukraine"
|
||||||
case .ae: return "United Arab Emirates"
|
case .ae: return "United Arab Emirates"
|
||||||
case .gb: return "United Kingdom of Great Britain and Northern Ireland"
|
case .gb: return "United Kingdom of Great Britain and Northern Ireland"
|
||||||
case .us: return "United States of America"
|
case .us: return "United States of America"
|
||||||
case .um: return "United States Minor Outlying Islands"
|
|
||||||
case .uy: return "Uruguay"
|
case .uy: return "Uruguay"
|
||||||
case .uz: return "Uzbekistan"
|
|
||||||
case .vu: return "Vanuatu"
|
|
||||||
case .ve: return "Venezuela (Bolivarian Republic of)"
|
case .ve: return "Venezuela (Bolivarian Republic of)"
|
||||||
case .vn: return "Viet Nam"
|
case .vn: return "Viet Nam"
|
||||||
case .vg: return "Virgin Islands (British)"
|
|
||||||
case .vi: return "Virgin Islands (U.S.)"
|
case .vi: return "Virgin Islands (U.S.)"
|
||||||
case .wf: return "Wallis and Futuna"
|
|
||||||
case .eh: return "Western Sahara"
|
|
||||||
case .ye: return "Yemen"
|
case .ye: return "Yemen"
|
||||||
case .zm: return "Zambia"
|
|
||||||
case .zw: return "Zimbabwe"
|
case .zw: return "Zimbabwe"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,11 +258,11 @@ extension Country {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func searchByPartialName(_ name: String) -> [Country] {
|
static func searchByPartialName(_ name: String) -> [Country] {
|
||||||
guard name.count >= 2 else {
|
guard !name.isEmpty else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredCountries { stringFolding($0).contains(name) }
|
return filteredCountries { stringFolding($0).contains(stringFolding(name)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func stringFolding(_ string: String) -> String {
|
private static func stringFolding(_ string: String) -> String {
|
||||||
|
101
Shared/TrendingCountrySelection.swift
Normal file
101
Shared/TrendingCountrySelection.swift
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct TrendingCountrySelection: View {
|
||||||
|
static let prompt = "Country Name or Code"
|
||||||
|
@Binding var selectedCountry: Country?
|
||||||
|
|
||||||
|
@ObservedObject private var store = Store(Country.allCases)
|
||||||
|
|
||||||
|
@State private var query: String = ""
|
||||||
|
@State private var selection: Country?
|
||||||
|
|
||||||
|
@FocusState var countryIsFocused
|
||||||
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
#if os(macOS)
|
||||||
|
HStack {
|
||||||
|
TextField("Country", text: $query, prompt: Text(TrendingCountrySelection.prompt))
|
||||||
|
.focused($countryIsFocused)
|
||||||
|
Button("Done") { selectCountryAndDismiss() }
|
||||||
|
}
|
||||||
|
.padding([.horizontal, .top])
|
||||||
|
|
||||||
|
countriesList
|
||||||
|
#else
|
||||||
|
NavigationView {
|
||||||
|
countriesList
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||||
|
Button("Done") { selectCountryAndDismiss() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if os(iOS)
|
||||||
|
.navigationBarTitle("Trending Country", displayMode: .automatic)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
countryIsFocused = true
|
||||||
|
}
|
||||||
|
.onSubmit { selectCountryAndDismiss() }
|
||||||
|
#if !os(macOS)
|
||||||
|
.searchable(text: $query, placement: searchPlacement, prompt: Text(TrendingCountrySelection.prompt))
|
||||||
|
#endif
|
||||||
|
#if os(tvOS)
|
||||||
|
.background(.thinMaterial)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
var countriesList: some View {
|
||||||
|
ScrollViewReader { _ in
|
||||||
|
List(store.collection, selection: $selection) { country in
|
||||||
|
#if os(macOS)
|
||||||
|
Text(country.name)
|
||||||
|
.tag(country)
|
||||||
|
.id(country)
|
||||||
|
#else
|
||||||
|
Button(country.name) { selectCountryAndDismiss(country) }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
.onChange(of: query) { newQuery in
|
||||||
|
let results = Country.search(newQuery)
|
||||||
|
store.replace(results)
|
||||||
|
|
||||||
|
selection = results.first
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||||
|
.padding(.bottom, 5)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchPlacement: SearchFieldPlacement {
|
||||||
|
#if os(iOS)
|
||||||
|
.navigationBarDrawer(displayMode: .always)
|
||||||
|
#else
|
||||||
|
.automatic
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectCountryAndDismiss(_ country: Country? = nil) {
|
||||||
|
let selected = country ?? selection
|
||||||
|
|
||||||
|
if selected != nil {
|
||||||
|
selectedCountry = selected
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TrendingCountrySelection_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
TrendingCountrySelection(selectedCountry: .constant(.pl))
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct TrendingView: View {
|
struct TrendingView: View {
|
||||||
@State private var category: TrendingCategory = .default
|
@State private var category: TrendingCategory = .default
|
||||||
@State private var country: Country = .pl
|
@State private var country: Country! = .pl
|
||||||
@State private var selectingCountry = false
|
@State private var selectingCountry = false
|
||||||
|
|
||||||
@ObservedObject private var store = Store<[Video]>()
|
@ObservedObject private var store = Store<[Video]>()
|
||||||
@ -16,37 +16,77 @@ struct TrendingView: View {
|
|||||||
resource.addObserver(store)
|
resource.addObserver(store)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var toolbar: some View {
|
||||||
Section {
|
HStack {
|
||||||
VStack(alignment: .center, spacing: 2) {
|
|
||||||
#if os(tvOS)
|
|
||||||
HStack {
|
HStack {
|
||||||
Text("Category")
|
Text("Category")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
categoryButton
|
categoryButton
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
Spacer()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HStack {
|
||||||
Text("Country")
|
Text("Country")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
countryFlag
|
|
||||||
countryButton
|
countryButton
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Section {
|
||||||
|
VStack(alignment: .center, spacing: 2) {
|
||||||
|
#if os(tvOS)
|
||||||
|
toolbar
|
||||||
.scaleEffect(0.85)
|
.scaleEffect(0.85)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VideosView(videos: store.collection)
|
VideosView(videos: store.collection)
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
toolbar
|
||||||
|
.font(.system(size: 14))
|
||||||
|
.animation(nil)
|
||||||
|
.padding(.horizontal)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.overlay(Divider().offset(x: 0, y: -2), alignment: .topTrailing)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if !os(tvOS)
|
#if os(tvOS)
|
||||||
|
.fullScreenCover(isPresented: $selectingCountry, onDismiss: { setCountry(country) }) {
|
||||||
|
TrendingCountrySelection(selectedCountry: $country)
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
.sheet(isPresented: $selectingCountry, onDismiss: { setCountry(country) }) {
|
||||||
|
TrendingCountrySelection(selectedCountry: $country)
|
||||||
|
#if os(macOS)
|
||||||
|
.frame(minWidth: 400, minHeight: 400)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
.navigationTitle("Trending")
|
.navigationTitle("Trending")
|
||||||
#endif
|
#endif
|
||||||
|
#if os(macOS)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItemGroup {
|
||||||
|
categoryButton
|
||||||
|
countryButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
.onAppear {
|
.onAppear {
|
||||||
resource.loadIfNeeded()
|
resource.loadIfNeeded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var categoryButton: some View {
|
var categoryButton: some View {
|
||||||
|
#if os(tvOS)
|
||||||
Button(category.name) {
|
Button(category.name) {
|
||||||
setCategory(category.next())
|
setCategory(category.next())
|
||||||
}
|
}
|
||||||
@ -55,23 +95,28 @@ struct TrendingView: View {
|
|||||||
Button(category.name) { setCategory(category) }
|
Button(category.name) { setCategory(category) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
Menu(category.name) {
|
||||||
|
ForEach(TrendingCategory.allCases) { category in
|
||||||
|
Button(action: { setCategory(category) }) {
|
||||||
|
if category == self.category {
|
||||||
|
Label(category.name, systemImage: "checkmark")
|
||||||
|
} else {
|
||||||
|
Text(category.name)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var countryFlag: some View {
|
}
|
||||||
Text(country.flag)
|
}
|
||||||
.font(.system(size: 60))
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var countryButton: some View {
|
var countryButton: some View {
|
||||||
Button(country.rawValue) {
|
Button(action: {
|
||||||
selectingCountry.toggle()
|
selectingCountry.toggle()
|
||||||
resource.removeObservers(ownedBy: store)
|
resource.removeObservers(ownedBy: store)
|
||||||
|
}) {
|
||||||
|
Text("\(country.flag) \(country.id)")
|
||||||
}
|
}
|
||||||
#if os(tvOS)
|
|
||||||
.fullScreenCover(isPresented: $selectingCountry, onDismiss: { setCountry(country) }) {
|
|
||||||
TrendingCountrySelectionView(selectedCountry: $country)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func setCategory(_ category: TrendingCategory) {
|
fileprivate func setCategory(_ category: TrendingCategory) {
|
||||||
@ -87,3 +132,10 @@ struct TrendingView: View {
|
|||||||
resource.loadIfNeeded()
|
resource.loadIfNeeded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TrendingView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
TrendingView()
|
||||||
|
.environmentObject(NavigationState())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -193,7 +193,7 @@ struct VideoView: View {
|
|||||||
minHeight: Double = 140,
|
minHeight: Double = 140,
|
||||||
maxHeight: Double = .infinity
|
maxHeight: Double = .infinity
|
||||||
) -> some View {
|
) -> some View {
|
||||||
ZStack(alignment: .trailing) {
|
ZStack(alignment: .leading) {
|
||||||
thumbnail(.maxres, minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
thumbnail(.maxres, minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight)
|
||||||
|
|
||||||
VStack {
|
VStack {
|
||||||
@ -222,6 +222,7 @@ struct VideoView: View {
|
|||||||
.padding(10)
|
.padding(10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: 600)
|
||||||
}
|
}
|
||||||
|
|
||||||
func thumbnail(
|
func thumbnail(
|
||||||
|
@ -6,18 +6,26 @@ struct VideosListView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Section {
|
Section {
|
||||||
|
ScrollViewReader { scrollView in
|
||||||
List {
|
List {
|
||||||
ForEach(videos) { video in
|
ForEach(videos) { video in
|
||||||
VideoView(video: video, layout: .list)
|
VideoView(video: video, layout: .list)
|
||||||
.contextMenu { VideoContextMenuView(video: video) }
|
.contextMenu { VideoContextMenuView(video: video) }
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.listRowInsets(listRowInsets)
|
.listRowInsets(listRowInsets)
|
||||||
|
|
||||||
#elseif os(iOS)
|
#elseif os(iOS)
|
||||||
.listRowInsets(EdgeInsets(.zero))
|
.listRowInsets(EdgeInsets(.zero))
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
.onChange(of: videos) { videos in
|
||||||
|
guard let video = videos.first else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollView.scrollTo(video.id, anchor: .top)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.listStyle(GroupedListStyle())
|
.listStyle(GroupedListStyle())
|
||||||
|
Loading…
Reference in New Issue
Block a user