New account selection menu

This commit is contained in:
Arkadiusz Fal 2022-12-11 23:15:56 +01:00
parent 4c143f6d88
commit d02bb23e57
26 changed files with 312 additions and 128 deletions

View File

@ -7,7 +7,7 @@ struct Account: Defaults.Serializable, Hashable, Identifiable {
let id: String
var app: VideosApp?
let instanceID: String?
var name: String?
var name: String
let urlString: String
var username: String
var password: String?
@ -31,7 +31,7 @@ struct Account: Defaults.Serializable, Hashable, Identifiable {
self.id = id ?? (anonymous ? "anonymous-\(instanceID ?? urlString ?? UUID().uuidString)" : UUID().uuidString)
self.instanceID = instanceID
self.name = name
self.name = name ?? ""
self.urlString = urlString ?? ""
self.username = username ?? ""
self.password = password ?? ""
@ -74,13 +74,17 @@ struct Account: Defaults.Serializable, Hashable, Identifiable {
}
var description: String {
guard let name, !name.isEmpty else {
guard !name.isEmpty else {
return shortUsername
}
return name
}
var urlHost: String {
URLComponents(url: url, resolvingAgainstBaseURL: false)?.host ?? ""
}
func hash(into hasher: inout Hasher) {
hasher.combine(username)
}

View File

@ -13,7 +13,12 @@ enum VideosApp: String, CaseIterable {
case peerTube
var name: String {
rawValue.capitalized
switch self {
case .peerTube:
return "PeerTube"
default:
return rawValue.capitalized
}
}
var appType: AppType {

View File

@ -79,6 +79,7 @@ final class NavigationModel: ObservableObject {
@Published var presentingOpenVideos = false
@Published var presentingSettings = false
@Published var presentingAccounts = false
@Published var presentingWelcomeScreen = false
@Published var presentingShareSheet = false

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Invidious.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="512pt" height="512pt" version="1.0" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g><rect x="-.0072516" y=".00056299" width="512.01" height="512.02" fill="#575757" stroke-width=".063019"/><path d="m247.17 455.95c-19.792-0.78921-38.719-4.2564-57.154-10.47-60.968-20.55-108.68-68.579-127-127.86-7.8955-25.538-10.062-53.943-6.2586-82.067 3.7105-27.439 13.603-53.515 29.342-77.344 12.069-18.273 29.138-36.277 47.228-49.816 36.891-27.61 85.944-42.49 132.38-40.157 25.88 1.3001 49.939 6.765 73.106 16.606 8.1948 3.481 20.024 9.6845 27.696 14.525 14.15 8.9272 22.367 15.498 34.482 27.573 13.254 13.211 22.128 24.276 30.398 37.906 7.2081 11.879 14.099 27.15 18.229 40.397 1.5996 5.1305 4.442 16.456 5.6852 22.653 2.3908 11.917 2.6998 15.722 2.7049 33.312 6e-3 18.515-0.46256 24.413-2.9166 36.758-9.3274 46.92-35.58 88.167-74.872 117.64-22.814 17.112-50.027 29.535-78.547 35.858-16.714 3.7059-35.421 5.2453-54.498 4.4846zm-35.1-78.786c-5.3e-4 -0.52647-0.0741-2.0564-0.16311-3.3999l-0.16178-2.4427-4.7018-0.26271c-4.0477-0.22614-4.7968-0.33363-5.3847-0.77253-2.0235-1.5108-1.4679-6.0695 2.2494-18.457 0.8637-2.8781 3.3371-11.321 5.4966-18.762 2.1594-7.4409 5.2002-17.836 6.7573-23.101 1.5571-5.2648 4.1948-14.282 5.8615-20.038 1.6667-5.7562 3.6145-12.4 4.3284-14.764 0.71391-2.3641 3.2583-11.037 5.6542-19.272 4.9475-17.007 8.1626-27.723 8.9438-29.811 0.51852-1.3858 0.54785-1.4139 0.99761-0.95317 0.25486 0.26106 3.8462 7.3667 7.9807 15.79 4.1345 8.4236 13.089 26.573 19.898 40.331 17.188 34.73 37.849 76.578 43.261 87.622l4.5356 9.257 11.359-0.0895c6.2475-0.0492 11.615-0.19623 11.929-0.32672 0.5614-0.23385 0.54167-0.2959-1.3723-4.3176-1.068-2.2442-8.1436-16.601-15.724-31.904-48.687-98.293-61.22-123.86-67.889-138.48-4.7022-10.309-6.9031-14.807-7.7139-15.762-0.82931-0.97742-1.6319-1.0638-2.3704-0.25525-1.1993 1.313-4.1046 10.063-9.3869 28.27-2.0569 7.0899-6.5372 22.425-9.9562 34.077-6.6396 22.629-8.5182 29.037-14.33 48.883-2.0354 6.9495-4.7977 16.369-6.1385 20.931-1.3408 4.5628-4.033 13.81-5.9826 20.549-4.304 14.877-6.136 20.889-7.3886 24.25-2.1371 5.7334-2.5723 6.3292-4.9216 6.7384-0.88855 0.15472-2.4102 0.28196-3.3815 0.28275-2.1993 3e-3 -3.5494 0.36339-4.0558 1.0863-0.42176 0.60215-0.56421 4.8802-0.18251 5.4812 0.20573 0.32388 2.4672 0.37414 23.34 0.51873l8.6151 0.0597-7e-4 -0.95723zm36.751-205.59c4.3282-0.92335 8.4607-4.943 9.4374-9.1796 0.36569-1.5862 0.32543-4.9758-0.077-6.4799-0.85108-3.1813-3.2688-6.291-6.039-7.7675-3.8111-2.0313-9.456-2.0295-13.272 5e-3 -5.9828 3.1888-8.1556 11.089-4.7878 17.408 2.6995 5.0648 8.3611 7.3754 14.738 6.015z" fill="#f0f0f0" stroke-width=".025526"/></g><g transform="matrix(.069892 0 0 -.069892 44.236 474.48)"><path d="m2787 4669c-124-65-123-255 3-319 86-44 196-16 247 62 58 87 26 211-67 258-51 26-132 26-183-1z" fill="#00b6f0" stroke="#00b6f0" stroke-width="4.25"/><path d="m2882 4108c-12-16-63-166-102-303-30-104-101-350-165-565-20-69-58-199-85-290-26-91-64-221-85-290-20-69-58-199-85-290-26-91-64-221-85-290-20-69-57-195-81-280-59-207-93-299-115-310-10-6-35-10-56-10-73 0-84-8-81-54l3-41 228-3 228-2-3 47-3 48-73 3c-66 3-74 5-84 27-13 28 0 104 37 225 13 41 47 156 75 255s66 230 85 290c18 61 56 191 85 290 28 99 66 230 85 290 18 61 56 191 85 290 85 297 123 419 131 429 5 5 17-11 28-35 10-24 192-393 403-819s447-902 523-1058l139-282h168c92 0 168 4 168 8s-75 158-166 342c-588 1183-969 1958-1033 2100-29 63-69 151-89 195-44 95-58 110-80 83z" fill="#575757"/></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "PeerTube.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg height="682.68799" viewBox="2799 -911 512 682.688" width="512" xmlns="http://www.w3.org/2000/svg"><g stroke-width="32"><path d="m2799-911v341.344l256-170.656" fill="#211f20"/><path d="m2799-569.656v341.344l256-170.656" fill="#737373"/><path d="m3055-740.344v341.344l256-170.656" fill="#f1680d"/></g></svg>

After

Width:  |  Height:  |  Size: 365 B

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Piped.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -40,6 +40,9 @@ struct HomeView: View {
NavigationModel.shared.presentingOpenVideos = true
}
}
OpenVideosButton(text: "Locations", imageSystemName: "globe") {
NavigationModel.shared.presentingAccounts = true
}
OpenVideosButton(text: "Settings", imageSystemName: "gear") {
NavigationModel.shared.presentingSettings = true
}

View File

@ -3,6 +3,7 @@ import SwiftUI
struct AccountsMenuView: View {
@ObservedObject private var model = AccountsModel.shared
private var navigation = NavigationModel.shared
@Default(.accounts) private var accounts
@Default(.instances) private var instances
@ -11,22 +12,8 @@ struct AccountsMenuView: View {
@ViewBuilder var body: some View {
if !instances.isEmpty {
Menu {
ForEach(allAccounts, id: \.id) { account in
Button {
model.setCurrent(account)
} label: {
HStack {
Text(accountButtonTitle(account: account))
Spacer()
if model.current == account {
Image(systemName: "checkmark")
}
}
}
}
navigation.presentingAccounts = true
} label: {
HStack {
if !accountPickerDisplaysUsername || !(model.current?.isPublic ?? true) {
@ -39,7 +26,6 @@ struct AccountsMenuView: View {
}
}
}
.disabled(allAccounts.isEmpty)
.transaction { t in t.animation = .none }
}
}
@ -47,13 +33,4 @@ struct AccountsMenuView: View {
private var label: some View {
Label(model.current?.description ?? "Select Account", systemImage: "globe")
}
private var allAccounts: [Account] {
let anonymousAccounts = accountPickerDisplaysAnonymousAccounts ? instances.map(\.anonymousAccount) : []
return accounts + anonymousAccounts + [model.publicAccount].compactMap { $0 }
}
private func accountButtonTitle(account: Account) -> String {
account.isPublic ? account.description : "\(account.description)\(account.instance.shortDescription)"
}
}

View File

@ -0,0 +1,112 @@
import SwiftUI
struct AccountsView: View {
@StateObject private var model = AccountsViewModel()
@Environment(\.presentationMode) private var presentationMode
var body: some View {
#if os(macOS)
VStack(alignment: .leading) {
closeButton
.padding([.leading, .top])
list
}
.frame(minWidth: 500, maxWidth: 800, minHeight: 350, maxHeight: 700)
#else
NavigationView {
list
#if os(iOS)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
closeButton
}
}
#endif
.navigationTitle("Accounts")
}
#if os(tvOS)
.frame(maxWidth: 1000)
#endif
#endif
}
var list: some View {
List {
if !model.accounts.isEmpty {
Section(header: Text("Your Accounts")) {
ForEach(model.sortedAccounts) { account in
accountButton(account)
}
}
}
if !model.instances.isEmpty {
Section(header: Text("Browse without account")) {
ForEach(model.instances) { instance in
accountButton(instance.anonymousAccount)
}
}
}
if let account = model.publicAccount {
Section(header: Text("Public account")) {
accountButton(account)
}
}
}
}
func accountButton(_ account: Account) -> some View {
Button {
presentationMode.wrappedValue.dismiss()
AccountsModel.shared.setCurrent(account)
} label: {
HStack {
instanceImage(account.instance)
if !account.anonymous {
Text(account.description)
}
Text((account.anonymous ? "" : "@ ") + account.urlHost)
.lineLimit(1)
.truncationMode(.head)
.foregroundColor(account.anonymous ? .primary : .secondary)
Spacer()
Image(systemName: "checkmark")
.foregroundColor(.accentColor)
.opacity(account == model.currentAccount ? 1 : 0)
}
.contentShape(Rectangle())
}
.buttonStyle(.plain)
}
var closeButton: some View {
Button(action: { presentationMode.wrappedValue.dismiss() }) {
Label("Done", systemImage: "xmark")
}
#if os(macOS)
.labelStyle(.titleOnly)
#endif
#if !os(tvOS)
.keyboardShortcut(.cancelAction)
#endif
}
func instanceImage(_ instance: Instance) -> some View {
Image(instance.app.rawValue.capitalized)
.resizable()
.frame(width: 30, height: 30)
}
}
struct AccountsView_Previews: PreviewProvider {
static var previews: some View {
AccountsView()
}
}

View File

@ -0,0 +1,36 @@
import Foundation
final class AccountsViewModel: ObservableObject {
typealias AreInIncreasingOrder = (Account, Account) -> Bool
var accounts: [Account] { AccountsModel.shared.all }
var sortedAccounts: [Account] {
accounts.sorted { lhs, rhs in
let predicates: [AreInIncreasingOrder] = [
{ ($0.app ?? .local).rawValue < ($1.app ?? .local).rawValue },
{ $0.urlHost < $1.urlHost },
{ $0.description < $1.description }
]
for predicate in predicates {
if !predicate(lhs, rhs), !predicate(rhs, lhs) {
continue
}
return predicate(lhs, rhs)
}
return false
}
}
var publicAccount: Account? { AccountsModel.shared.publicAccount }
var currentAccount: Account? { AccountsModel.shared.current }
var instances: [Instance] { InstancesModel.shared.all }
func accountsOfInstance(_ instance: Instance) -> [Account] {
accounts.filter { $0.instance.apiURL == instance.apiURL }.sorted { $0.name < $1.name }
}
}

View File

@ -77,12 +77,6 @@ struct AppSidebarNavigation: View {
ToolbarItemGroup(placement: accountsMenuToolbarItemPlacement) {
AccountsMenuView()
.help(
"Switch Instances and Accounts\n" +
"Current Instance: \n" +
"\(accounts.current?.urlString ?? "Not Set")\n" +
"Current User: \(accounts.current?.description ?? "Not set")"
)
}
#if os(macOS)

View File

@ -81,7 +81,6 @@ struct AppTabNavigation: View {
private var subscriptionsNavigationView: some View {
NavigationView {
LazyView(SubscriptionsView())
.toolbar { toolbarContent }
}
.tabItem {
Label("Subscriptions", systemImage: "star.circle.fill")
@ -115,7 +114,6 @@ struct AppTabNavigation: View {
private var trendingNavigationView: some View {
NavigationView {
LazyView(TrendingView())
.toolbar { toolbarContent }
}
.tabItem {
Label("Trending", systemImage: "chart.bar.fill")
@ -127,7 +125,6 @@ struct AppTabNavigation: View {
private var playlistsNavigationView: some View {
NavigationView {
LazyView(PlaylistsView())
.toolbar { toolbarContent }
}
.tabItem {
Label("Playlists", systemImage: "list.and.film")

View File

@ -69,6 +69,11 @@ struct ContentView: View {
SettingsView()
}
)
.background(
EmptyView().sheet(isPresented: $navigation.presentingAccounts) {
AccountsView()
}
)
#if !os(tvOS)
.fileImporter(
isPresented: $navigation.presentingFileImporter,

View File

@ -191,8 +191,6 @@ struct PlaylistsView: View {
#if os(iOS)
var playlistsMenu: some View {
Menu {
selectPlaylistButton
Section {
if let currentPlaylist {
playButton
@ -207,6 +205,12 @@ struct PlaylistsView: View {
if accounts.signedIn {
newPlaylistButton
}
selectPlaylistButton
Section {
SettingsButtons()
}
} label: {
HStack(spacing: 12) {
Text(currentPlaylist?.title ?? "Playlists")

View File

@ -213,9 +213,7 @@ struct SearchView: View {
}
Section {
Button(action: { navigation.presentingSettings = true }) {
Label("Settings", systemImage: "gearshape.2")
}
SettingsButtons()
}
} label: {
HStack {

View File

@ -112,7 +112,15 @@ struct SettingsView: View {
List {
#if os(tvOS)
if !accounts.isEmpty {
AccountSelectionView()
Section(header: Text("Current Location")) {
NavigationLink(destination: AccountsView()) {
if let account = accounts.current {
Text(account.isPublic ? account.description : "\(account.description)\(account.instance.shortDescription)")
} else {
Text("Not Selected")
}
}
}
Divider()
}
#endif

View File

@ -39,6 +39,10 @@ struct SubscriptionsView: View {
Label("Feed", systemImage: "film").tag(Page.feed)
Label("Channels", systemImage: "person.3.fill").tag(Page.channels)
}
Section {
SettingsButtons()
}
} label: {
HStack(spacing: 12) {
Text(menuLabel)

View File

@ -158,10 +158,14 @@ struct TrendingView: View {
var trendingMenu: some View {
Menu {
countryButton
if accounts.app.supportsTrendingCategories {
categoryButton
}
FavoriteButton(item: favoriteItem)
Section {
SettingsButtons()
}
} label: {
HStack(spacing: 12) {
Text("\(country.flag) \(country.name)")

View File

@ -35,7 +35,7 @@ struct OpenVideosView: View {
var closeButton: some View {
Button(action: { presentationMode.wrappedValue.dismiss() }) {
Label("Close", systemImage: "xmark")
Label("Done", systemImage: "xmark")
}
#if os(macOS)
.labelStyle(.titleOnly)

View File

@ -0,0 +1,21 @@
import SwiftUI
struct SettingsButtons: View {
@ObservedObject private var accounts = AccountsModel.shared
private var navigation = NavigationModel.shared
var body: some View {
Button(action: { navigation.presentingAccounts = true }) {
Label(accounts.current?.description ?? "", image: accounts.app.rawValue.capitalized)
}
Button(action: { navigation.presentingSettings = true }) {
Label("Settings", systemImage: "gearshape.2")
}
}
}
struct SettingsButtons_Previews: PreviewProvider {
static var previews: some View {
SettingsButtons()
}
}

View File

@ -134,8 +134,6 @@ struct YatteeApp: App {
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
SDWebImageManager.defaultImageCache = PINCache(name: "stream.yattee.app")
migrateAccounts()
if !Defaults[.lastAccountIsPublic] {
AccountsModel.shared.configureAccount()
}
@ -182,28 +180,4 @@ struct YatteeApp: App {
URLBookmarkModel.shared.refreshAll()
}
func migrateAccounts() {
Defaults[.accounts].forEach { account in
if !account.username.isEmpty || !(account.password?.isEmpty ?? true) || !(account.name?.isEmpty ?? true) {
print("Account needs migration: \(account.description)")
if account.app == .invidious {
if let name = account.name, !name.isEmpty {
AccountsModel.setCredentials(account, username: name, password: "")
}
if !account.username.isEmpty {
AccountsModel.setToken(account, account.username)
}
} else if account.app == .piped,
!account.username.isEmpty,
let password = account.password,
!password.isEmpty
{
AccountsModel.setCredentials(account, username: account.username, password: password)
}
AccountsModel.removeDefaultsCredentials(account)
}
}
}
}

View File

@ -193,6 +193,15 @@
371B7E6A2759791900D21217 /* CommentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B7E692759791900D21217 /* CommentsModel.swift */; };
371B7E6B2759791900D21217 /* CommentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B7E692759791900D21217 /* CommentsModel.swift */; };
371B7E6C2759791900D21217 /* CommentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B7E692759791900D21217 /* CommentsModel.swift */; };
371CC76829466ED000979C1A /* AccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76729466ED000979C1A /* AccountsView.swift */; };
371CC76929466ED000979C1A /* AccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76729466ED000979C1A /* AccountsView.swift */; };
371CC76A29466ED000979C1A /* AccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76729466ED000979C1A /* AccountsView.swift */; };
371CC76C29466F5A00979C1A /* AccountsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76B29466F5A00979C1A /* AccountsViewModel.swift */; };
371CC76D29466F5A00979C1A /* AccountsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76B29466F5A00979C1A /* AccountsViewModel.swift */; };
371CC76E29466F5A00979C1A /* AccountsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76B29466F5A00979C1A /* AccountsViewModel.swift */; };
371CC77029468BDC00979C1A /* SettingsButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76F29468BDC00979C1A /* SettingsButtons.swift */; };
371CC77129468BDC00979C1A /* SettingsButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76F29468BDC00979C1A /* SettingsButtons.swift */; };
371CC77229468BDC00979C1A /* SettingsButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371CC76F29468BDC00979C1A /* SettingsButtons.swift */; };
371F2F1A269B43D300E4A7AB /* 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 */; };
@ -449,7 +458,6 @@
376578932685490700D4EA09 /* PlaylistsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376578902685490700D4EA09 /* PlaylistsView.swift */; };
3765917C27237D21009F956E /* PINCache in Frameworks */ = {isa = PBXBuildFile; productRef = 3765917B27237D21009F956E /* PINCache */; };
3765917E27237D2A009F956E /* PINCache in Frameworks */ = {isa = PBXBuildFile; productRef = 3765917D27237D2A009F956E /* PINCache */; };
37666BAA27023AF000F869E5 /* AccountSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37666BA927023AF000F869E5 /* AccountSelectionView.swift */; };
3766AFD2273DA97D00686348 /* Int+FormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BA796D26DC412E002A0235 /* Int+FormatTests.swift */; };
3769537928A877C4005D87C3 /* StreamControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3795593527B08538007FF8F4 /* StreamControl.swift */; };
3769C02E2779F18600DDB3EA /* PlaceholderProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3769C02D2779F18600DDB3EA /* PlaceholderProgressView.swift */; };
@ -1120,6 +1128,9 @@
371B7E602759706A00D21217 /* CommentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentsView.swift; sourceTree = "<group>"; };
371B7E652759786B00D21217 /* Comment+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Comment+Fixtures.swift"; sourceTree = "<group>"; };
371B7E692759791900D21217 /* CommentsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentsModel.swift; sourceTree = "<group>"; };
371CC76729466ED000979C1A /* AccountsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsView.swift; sourceTree = "<group>"; };
371CC76B29466F5A00979C1A /* AccountsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsViewModel.swift; sourceTree = "<group>"; };
371CC76F29468BDC00979C1A /* SettingsButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButtons.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>"; };
@ -1232,7 +1243,6 @@
376578882685471400D4EA09 /* Playlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Playlist.swift; sourceTree = "<group>"; };
376578902685490700D4EA09 /* PlaylistsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistsView.swift; sourceTree = "<group>"; };
37658ED428E1C567004BF6A2 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
37666BA927023AF000F869E5 /* AccountSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSelectionView.swift; sourceTree = "<group>"; };
376787BA291C43CD00D356A4 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
3768122C28E8D0BC0036FC8D /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = "<group>"; };
3769C02D2779F18600DDB3EA /* PlaceholderProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderProgressView.swift; sourceTree = "<group>"; };
@ -1702,6 +1712,8 @@
isa = PBXGroup;
children = (
378E50FE26FE8EEE00F49626 /* AccountsMenuView.swift */,
371CC76729466ED000979C1A /* AccountsView.swift */,
371CC76B29466F5A00979C1A /* AccountsViewModel.swift */,
37BD07BA2698AB60003EBB87 /* AppSidebarNavigation.swift */,
37BA794A26DC30EC002A0235 /* AppSidebarPlaylists.swift */,
3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */,
@ -1789,6 +1801,7 @@
3769C02D2779F18600DDB3EA /* PlaceholderProgressView.swift */,
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */,
37AAF27D26737323007FC770 /* PopularView.swift */,
371CC76F29468BDC00979C1A /* SettingsButtons.swift */,
37F7D82B289EB05F00E2B3D0 /* SettingsPickerModifier.swift */,
3784B23C2728B85300B09468 /* ShareButton.swift */,
376B2E0626F920D600B1D64D /* SignInRequiredView.swift */,
@ -2235,7 +2248,6 @@
37D4B159267164AE00C925CA /* tvOS */ = {
isa = PBXGroup;
children = (
37666BA927023AF000F869E5 /* AccountSelectionView.swift */,
37D6025C28C17719009E8D98 /* ControlsOverlayButton.swift */,
3730D89F2712E2B70020ED53 /* NowPlayingView.swift */,
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */,
@ -3009,6 +3021,7 @@
37C0698227260B2100F7F6CB /* ThumbnailsModel.swift in Sources */,
37BC50A82778A84700510953 /* HistorySettings.swift in Sources */,
37DD9DB12785D58D00539416 /* RefreshControl.swift in Sources */,
371CC76C29466F5A00979C1A /* AccountsViewModel.swift in Sources */,
37B4E805277D0AB4004BF56A /* Orientation.swift in Sources */,
37DD87C7271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */,
37F7D82C289EB05F00E2B3D0 /* SettingsPickerModifier.swift in Sources */,
@ -3063,6 +3076,7 @@
373031F32838388A000CFD59 /* PlayerLayerView.swift in Sources */,
376E331228AD3B320070E30C /* ScrollDismissesKeyboard+Backport.swift in Sources */,
373EBD68291F1EAF002ADB9C /* EditFavorites.swift in Sources */,
371CC76829466ED000979C1A /* AccountsView.swift in Sources */,
37B044B726F7AB9000E1419D /* SettingsView.swift in Sources */,
377FC7E3267A084A00A6BBAF /* VideoCell.swift in Sources */,
37C3A251272366440087A57A /* ChannelPlaylistView.swift in Sources */,
@ -3113,6 +3127,7 @@
379775932689365600DD52A8 /* Array+Next.swift in Sources */,
37CFB48528AFE2510070024C /* VideoDescription.swift in Sources */,
37B81AFC26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
371CC77029468BDC00979C1A /* SettingsButtons.swift in Sources */,
37C7A1D5267BFD9D0010EAD6 /* SponsorBlockSegment.swift in Sources */,
37BA794F26DC3E0E002A0235 /* Int+Format.swift in Sources */,
378E9C3C2945565500B2D696 /* SubscriptionsView.swift in Sources */,
@ -3211,6 +3226,7 @@
37FD77012932C4DA00D91A5F /* URL+ByReplacingYatteeProtocol.swift in Sources */,
374924F129216C630017D862 /* VideoActions.swift in Sources */,
37C3A24627235DA70087A57A /* ChannelPlaylist.swift in Sources */,
371CC77129468BDC00979C1A /* SettingsButtons.swift in Sources */,
37CEE4BE2677B670005A1EFE /* SingleAssetStream.swift in Sources */,
3703100327B0713600ECDDAA /* PlayerGestures.swift in Sources */,
374C0540272472C0009BDDBE /* PlayerSponsorBlock.swift in Sources */,
@ -3239,6 +3255,7 @@
37001564271B1F250049C794 /* AccountsModel.swift in Sources */,
378FFBC528660172009E3FBE /* URLParser.swift in Sources */,
3761ABFE26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */,
371CC76D29466F5A00979C1A /* AccountsViewModel.swift in Sources */,
37BA795026DC3E0E002A0235 /* Int+Format.swift in Sources */,
3743CA4F270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */,
374C053C2724614F009BDDBE /* PlayerTVMenu.swift in Sources */,
@ -3331,6 +3348,7 @@
3744A96128B99ADD005DE0A7 /* PlayerControlsLayout.swift in Sources */,
372915E72687E3B900F5A35B /* Defaults.swift in Sources */,
377E17152928265900894889 /* ListRowSeparator+Backport.swift in Sources */,
371CC76929466ED000979C1A /* AccountsView.swift in Sources */,
37C3A242272359900087A57A /* Double+Format.swift in Sources */,
37B795912771DAE0001CF27B /* OpenURLHandler.swift in Sources */,
37EFAC0928C138CD00ED9B89 /* ControlsOverlayModel.swift in Sources */,
@ -3534,6 +3552,7 @@
37D2E0D628B67EFC00F64D52 /* Delay.swift in Sources */,
379F1421289ECE7F00DE48B5 /* QualitySettings.swift in Sources */,
37A9965C26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
371CC76A29466ED000979C1A /* AccountsView.swift in Sources */,
3782B95727557E6E00990149 /* SearchSuggestions.swift in Sources */,
3776ADD8287381240078EBC4 /* Captions.swift in Sources */,
37F0F4EC286F397E00C06C2E /* SettingsModel.swift in Sources */,
@ -3561,6 +3580,7 @@
375168D82700FDB9008F96A6 /* Debounce.swift in Sources */,
3718B9A42921A96C0003DB2E /* VideoDetailsTool.swift in Sources */,
37BA794126DB8F97002A0235 /* ChannelVideosView.swift in Sources */,
371CC77229468BDC00979C1A /* SettingsButtons.swift in Sources */,
37C0697C2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
3718B9A12921A9640003DB2E /* VideoDetails.swift in Sources */,
378AE93D274EDFB3006A4EE1 /* Backport.swift in Sources */,
@ -3573,6 +3593,7 @@
377692582946476F0055EC18 /* ChannelPlaylistsCacheModel.swift in Sources */,
371B7E5E27596B8400D21217 /* Comment.swift in Sources */,
37732FF22703A26300F04329 /* AccountValidationStatus.swift in Sources */,
371CC76E29466F5A00979C1A /* AccountsViewModel.swift in Sources */,
3756C2AC2861151C00E4B059 /* NetworkStateModel.swift in Sources */,
37F5E8B8291BE9D0006C15F5 /* URLBookmarkModel.swift in Sources */,
37A5DBCA285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */,
@ -3580,7 +3601,6 @@
37C0698427260B2100F7F6CB /* ThumbnailsModel.swift in Sources */,
374924DC2921050B0017D862 /* LocationsSettings.swift in Sources */,
37D6025B28C17375009E8D98 /* PlaybackStatsView.swift in Sources */,
37666BAA27023AF000F869E5 /* AccountSelectionView.swift in Sources */,
3765788B2685471400D4EA09 /* Playlist.swift in Sources */,
376A33E22720CAD6000C1D6B /* VideosApp.swift in Sources */,
373CFADD269663F1003CB2C6 /* Thumbnail.swift in Sources */,

View File

@ -1,51 +0,0 @@
import Defaults
import Foundation
import SwiftUI
struct AccountSelectionView: View {
var showHeader = true
@ObservedObject private var accountsModel = AccountsModel.shared
@Default(.accounts) private var accounts
@Default(.instances) private var instances
@Default(.accountPickerDisplaysAnonymousAccounts) private var accountPickerDisplaysAnonymousAccounts
var body: some View {
Section(header: Text(showHeader ? "Current Location" : "")) {
Button(accountButtonTitle(account: accountsModel.current)) {
if let account = nextAccount {
accountsModel.setCurrent(account)
}
}
.disabled(instances.isEmpty && Defaults[.countryOfPublicInstances].isNil)
.contextMenu {
ForEach(allAccounts) { account in
Button(accountButtonTitle(account: account)) {
accountsModel.setCurrent(account)
}
}
Button("Cancel", role: .cancel) {}
}
}
.id(UUID())
}
var allAccounts: [Account] {
let anonymousAccounts = accountPickerDisplaysAnonymousAccounts ? instances.map(\.anonymousAccount) : []
return accounts + anonymousAccounts + [accountsModel.publicAccount].compactMap { $0 }
}
private var nextAccount: Account? {
allAccounts.next(after: accountsModel.current)
}
func accountButtonTitle(account: Account! = nil) -> String {
guard account != nil else {
return "Not selected"
}
return account.isPublic ? account.description : "\(account.description)\(account.instance.shortDescription)"
}
}