iOS/iPadOS - User List Images (#586)

This commit is contained in:
Ethan Pippin 2022-09-14 20:44:28 -06:00 committed by GitHub
parent 93c19dbe54
commit fb38394a43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 77 deletions

View File

@ -154,9 +154,3 @@ struct SettingsView: View {
}
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView(viewModel: SettingsViewModel(server: .sample, user: .sample))
}
}

View File

@ -409,6 +409,7 @@
E18E023C288749540022598C /* UIScrollViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18E0239288749540022598C /* UIScrollViewExtensions.swift */; };
E19169CE272514760085832A /* HTTPScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19169CD272514760085832A /* HTTPScheme.swift */; };
E19169CF272514760085832A /* HTTPScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19169CD272514760085832A /* HTTPScheme.swift */; };
E192608028D28AAD002314B4 /* UserProfileButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E192607F28D28AAD002314B4 /* UserProfileButton.swift */; };
E1937A3B288E54AD00CB80AA /* BaseItemDto+Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1937A3A288E54AD00CB80AA /* BaseItemDto+Images.swift */; };
E1937A3C288E54AD00CB80AA /* BaseItemDto+Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1937A3A288E54AD00CB80AA /* BaseItemDto+Images.swift */; };
E1937A3E288F0D3D00CB80AA /* UIScreenExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1937A3D288F0D3D00CB80AA /* UIScreenExtensions.swift */; };
@ -893,6 +894,7 @@
E18E0203288749200022598C /* BlurView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = "<group>"; };
E18E0239288749540022598C /* UIScrollViewExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIScrollViewExtensions.swift; sourceTree = "<group>"; };
E19169CD272514760085832A /* HTTPScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPScheme.swift; sourceTree = "<group>"; };
E192607F28D28AAD002314B4 /* UserProfileButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileButton.swift; sourceTree = "<group>"; };
E1937A3A288E54AD00CB80AA /* BaseItemDto+Images.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemDto+Images.swift"; sourceTree = "<group>"; };
E1937A3D288F0D3D00CB80AA /* UIScreenExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScreenExtensions.swift; sourceTree = "<group>"; };
E1937A60288F32DB00CB80AA /* Poster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Poster.swift; sourceTree = "<group>"; };
@ -1500,6 +1502,7 @@
E1AA331C2782541500F6439C /* PrimaryButton.swift */,
E18E01A4288746AF0022598C /* RefreshableScrollView.swift */,
E1D3043428D1763100587289 /* SeeAllButton.swift */,
E192607F28D28AAD002314B4 /* UserProfileButton.swift */,
);
path = Components;
sourceTree = "<group>";
@ -2920,6 +2923,7 @@
E13DD4022717EE79009D4DAF /* UserListCoordinator.swift in Sources */,
E1FCD09626C47118007C8DCF /* ErrorMessage.swift in Sources */,
53EE24E6265060780068F029 /* SearchView.swift in Sources */,
E192608028D28AAD002314B4 /* UserProfileButton.swift in Sources */,
625CB5752678C33500530A6E /* MediaViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -33,7 +33,7 @@
"location" : "https://github.com/LePips/CollectionView",
"state" : {
"branch" : "main",
"revision" : "1dbf31d860626f8debdbb08201517a4684d226c6"
"revision" : "b05ad718700cc99a4b88009ede6cf04c7326cd99"
}
},
{

View File

@ -0,0 +1,57 @@
//
// Swiftfin is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
//
import JellyfinAPI
import SwiftUI
struct UserProfileButton: View {
let user: UserDto
private var action: () -> Void
init(user: UserDto) {
self.user = user
self.action = {}
}
init(user: SwiftfinStore.State.User) {
self.init(user: .init(name: user.username, id: user.id))
}
var body: some View {
VStack(alignment: .center) {
Button {
action()
} label: {
ImageView(user.profileImageSource(maxWidth: 120, maxHeight: 120))
.failure {
ZStack {
Color.secondarySystemFill
.opacity(0.5)
Image(systemName: "person.fill")
.resizable()
.frame(width: 60, height: 60)
}
}
.clipShape(Circle())
}
.frame(width: 120, height: 120)
Text(user.name ?? .emptyDash)
}
}
}
extension UserProfileButton {
func onSelect(_ action: @escaping () -> Void) -> Self {
var copy = self
copy.action = action
return copy
}
}

View File

@ -6,6 +6,7 @@
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
//
import CollectionView
import SwiftUI
struct UserListView: View {
@ -15,44 +16,6 @@ struct UserListView: View {
@ObservedObject
var viewModel: UserListViewModel
private var listView: some View {
ScrollView {
LazyVStack {
ForEach(viewModel.users, id: \.id) { user in
Button {
viewModel.signIn(user: user)
} label: {
ZStack(alignment: Alignment.leading) {
Rectangle()
.foregroundColor(Color(UIColor.secondarySystemFill))
.frame(height: 50)
.cornerRadius(10)
HStack {
Text(user.username)
.font(.title2)
Spacer()
if viewModel.isLoading {
ProgressView()
}
}.padding(.leading)
}
.padding()
}
.contextMenu {
Button(role: .destructive) {
viewModel.remove(user: user)
} label: {
Label(L10n.remove, systemImage: "trash")
}
}
}
}
}
}
private var noUserView: some View {
VStack {
L10n.signInGetStarted.text
@ -68,44 +31,59 @@ struct UserListView: View {
}
@ViewBuilder
private var innerBody: some View {
if viewModel.users.isEmpty {
noUserView
.offset(y: -50)
} else {
listView
}
}
@ViewBuilder
private var toolbarContent: some View {
HStack {
Button {
userListRouter.route(to: \.serverDetail, viewModel.server)
} label: {
Image(systemName: "info.circle.fill")
}
if !viewModel.users.isEmpty {
Button {
userListRouter.route(to: \.userSignIn, viewModel.server)
} label: {
Image(systemName: "person.crop.circle.fill.badge.plus")
private var gridView: some View {
CollectionView(items: viewModel.users) { _, user, _ in
UserProfileButton(user: user)
.onSelect {
viewModel.signIn(user: user)
}
}
.contextMenu {
Button(role: .destructive) {
viewModel.remove(user: user)
} label: {
Label(L10n.remove, systemImage: "trash")
}
}
}
.layout { _, layoutEnvironment in
.grid(
layoutEnvironment: layoutEnvironment,
layoutMode: .adaptive(withMinItemSize: 120),
itemSpacing: 30,
lineSpacing: 30
)
}
}
var body: some View {
innerBody
.navigationTitle(viewModel.server.name)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
toolbarContent
Group {
if viewModel.users.isEmpty {
noUserView
.offset(y: -50)
} else {
gridView
}
}
.navigationTitle(viewModel.server.name)
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
if !viewModel.users.isEmpty {
Button {
userListRouter.route(to: \.userSignIn, viewModel.server)
} label: {
Image(systemName: "person.crop.circle.fill.badge.plus")
}
}
Button {
userListRouter.route(to: \.serverDetail, viewModel.server)
} label: {
Image(systemName: "info.circle.fill")
}
}
.onAppear {
viewModel.fetchUsers()
}
}
.onAppear {
viewModel.fetchUsers()
}
}
}