mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
New account selection menu
This commit is contained in:
parent
4c143f6d88
commit
d02bb23e57
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
21
Shared/Assets.xcassets/Invidious.imageset/Contents.json
vendored
Normal file
21
Shared/Assets.xcassets/Invidious.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
2
Shared/Assets.xcassets/Invidious.imageset/Invidious.svg
vendored
Normal file
2
Shared/Assets.xcassets/Invidious.imageset/Invidious.svg
vendored
Normal 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 |
21
Shared/Assets.xcassets/Peertube.imageset/Contents.json
vendored
Normal file
21
Shared/Assets.xcassets/Peertube.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
2
Shared/Assets.xcassets/Peertube.imageset/PeerTube.svg
vendored
Normal file
2
Shared/Assets.xcassets/Peertube.imageset/PeerTube.svg
vendored
Normal 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 |
21
Shared/Assets.xcassets/Piped.imageset/Contents.json
vendored
Normal file
21
Shared/Assets.xcassets/Piped.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
1
Shared/Assets.xcassets/Piped.imageset/Piped.svg
vendored
Normal file
1
Shared/Assets.xcassets/Piped.imageset/Piped.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.4 KiB |
@ -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
|
||||
}
|
||||
|
@ -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)"
|
||||
}
|
||||
}
|
||||
|
112
Shared/Navigation/AccountsView.swift
Normal file
112
Shared/Navigation/AccountsView.swift
Normal 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()
|
||||
}
|
||||
}
|
36
Shared/Navigation/AccountsViewModel.swift
Normal file
36
Shared/Navigation/AccountsViewModel.swift
Normal 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 }
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -69,6 +69,11 @@ struct ContentView: View {
|
||||
SettingsView()
|
||||
}
|
||||
)
|
||||
.background(
|
||||
EmptyView().sheet(isPresented: $navigation.presentingAccounts) {
|
||||
AccountsView()
|
||||
}
|
||||
)
|
||||
#if !os(tvOS)
|
||||
.fileImporter(
|
||||
isPresented: $navigation.presentingFileImporter,
|
||||
|
@ -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")
|
||||
|
@ -213,9 +213,7 @@ struct SearchView: View {
|
||||
}
|
||||
|
||||
Section {
|
||||
Button(action: { navigation.presentingSettings = true }) {
|
||||
Label("Settings", systemImage: "gearshape.2")
|
||||
}
|
||||
SettingsButtons()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)")
|
||||
|
@ -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)
|
||||
|
21
Shared/Views/SettingsButtons.swift
Normal file
21
Shared/Views/SettingsButtons.swift
Normal 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()
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */,
|
||||
|
@ -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)"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user