[tvOS] ItemView Button Cleanup (#1296)
This commit is contained in:
parent
83843e2173
commit
d276bd7449
|
@ -1,61 +0,0 @@
|
|||
//
|
||||
// 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) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension ItemView {
|
||||
|
||||
struct ActionButtonHStack: View {
|
||||
|
||||
@ObservedObject
|
||||
var viewModel: ItemViewModel
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Button {
|
||||
viewModel.send(.toggleIsPlayed)
|
||||
} label: {
|
||||
Group {
|
||||
if viewModel.item.userData?.isPlayed ?? false {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(
|
||||
.primary,
|
||||
Color.jellyfinPurple
|
||||
)
|
||||
} else {
|
||||
Image(systemName: "checkmark.circle")
|
||||
}
|
||||
}
|
||||
.font(.title3)
|
||||
.frame(height: 100)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Button {
|
||||
viewModel.send(.toggleIsFavorite)
|
||||
} label: {
|
||||
Group {
|
||||
if viewModel.item.userData?.isFavorite ?? false {
|
||||
Image(systemName: "heart.circle.fill")
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.white, .pink)
|
||||
} else {
|
||||
Image(systemName: "heart.circle")
|
||||
}
|
||||
}
|
||||
.font(.title3)
|
||||
.frame(height: 100)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// 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) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
extension ItemView {
|
||||
|
||||
struct ActionButton: View {
|
||||
|
||||
@Environment(\.isSelected)
|
||||
private var isSelected
|
||||
@FocusState
|
||||
private var isFocused: Bool
|
||||
|
||||
let title: String
|
||||
let icon: String
|
||||
let selectedIcon: String
|
||||
let onSelect: () -> Void
|
||||
|
||||
// MARK: - Body
|
||||
|
||||
var body: some View {
|
||||
Button(action: onSelect) {
|
||||
ZStack {
|
||||
if isSelected {
|
||||
Rectangle()
|
||||
.fill(
|
||||
isFocused ? AnyShapeStyle(HierarchicalShapeStyle.primary) :
|
||||
AnyShapeStyle(HierarchicalShapeStyle.primary.opacity(0.5))
|
||||
)
|
||||
} else {
|
||||
Rectangle()
|
||||
.fill(isFocused ? Color.white : Color.white.opacity(0.5))
|
||||
}
|
||||
|
||||
Label(title, systemImage: isSelected ? selectedIcon : icon)
|
||||
.font(.title3)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundStyle(.black)
|
||||
.labelStyle(.iconOnly)
|
||||
}
|
||||
}
|
||||
.focused($isFocused)
|
||||
.buttonStyle(.card)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension ItemView {
|
||||
|
||||
struct ActionButtonHStack: View {
|
||||
|
||||
@ObservedObject
|
||||
var viewModel: ItemViewModel
|
||||
|
||||
// TODO: Shrink to minWWith 100 (button) / 50 (menu) and 16 spacing to get 4 buttons inline
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 24) {
|
||||
|
||||
// MARK: - Toggle Played
|
||||
|
||||
ActionButton(
|
||||
title: L10n.played,
|
||||
icon: "checkmark.circle",
|
||||
selectedIcon: "checkmark.circle.fill"
|
||||
) {
|
||||
viewModel.send(.toggleIsPlayed)
|
||||
}
|
||||
.foregroundStyle(.purple)
|
||||
.environment(\.isSelected, viewModel.item.userData?.isPlayed ?? false)
|
||||
.frame(minWidth: 140, maxWidth: .infinity)
|
||||
|
||||
// MARK: - Toggle Favorite
|
||||
|
||||
ActionButton(
|
||||
title: L10n.favorited,
|
||||
icon: "heart.circle",
|
||||
selectedIcon: "heart.circle.fill"
|
||||
) {
|
||||
viewModel.send(.toggleIsFavorite)
|
||||
}
|
||||
.foregroundStyle(.pink)
|
||||
.environment(\.isSelected, viewModel.item.userData?.isFavorite ?? false)
|
||||
.frame(minWidth: 140, maxWidth: .infinity)
|
||||
|
||||
// MARK: - Additional Menu Options
|
||||
|
||||
// TODO: Enable if there are more items needed
|
||||
/* ActionMenu {}
|
||||
.frame(width: 70)*/
|
||||
}
|
||||
.frame(height: 100)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// 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) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
extension ItemView {
|
||||
|
||||
struct ActionMenu<Content: View>: View {
|
||||
|
||||
@FocusState
|
||||
private var isFocused: Bool
|
||||
|
||||
@ViewBuilder
|
||||
let menuItems: Content
|
||||
|
||||
// MARK: - Body
|
||||
|
||||
var body: some View {
|
||||
Menu {
|
||||
menuItems
|
||||
} label: {
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.fill(isFocused ? Color.white : Color.white.opacity(0.5))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.stroke(Color.clear, lineWidth: 2)
|
||||
)
|
||||
|
||||
Label(L10n.menuButtons, systemImage: "ellipsis")
|
||||
.font(.title3)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundStyle(.black)
|
||||
.labelStyle(.iconOnly)
|
||||
.rotationEffect(.degrees(90))
|
||||
}
|
||||
}
|
||||
.focused($isFocused)
|
||||
.scaleEffect(isFocused ? 1.20 : 1.0)
|
||||
.animation(.easeInOut(duration: 0.15), value: isFocused)
|
||||
.menuStyle(.borderlessButton)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ extension SeriesEpisodeSelector {
|
|||
Image(systemName: "play.fill")
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.foregroundColor(.white)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,20 +52,19 @@ extension SeriesEpisodeSelector {
|
|||
Button {
|
||||
onSelect()
|
||||
} label: {
|
||||
VStack(alignment: .leading) {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
subHeaderView
|
||||
|
||||
headerView
|
||||
|
||||
contentView
|
||||
// Removing the alignment below makes the text center
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
L10n.seeMore.text
|
||||
.font(.caption.weight(.light))
|
||||
.foregroundStyle(accentColor)
|
||||
}
|
||||
.padding(5)
|
||||
.padding()
|
||||
}
|
||||
.buttonStyle(.card)
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ extension SeriesEpisodeSelector {
|
|||
) { episode in
|
||||
SeriesEpisodeSelector.EpisodeCard(episode: episode)
|
||||
.focused($focusedEpisodeID, equals: episode.id)
|
||||
.padding(.horizontal, 4)
|
||||
}
|
||||
.scrollBehavior(.continuousLeadingEdge)
|
||||
.insets(horizontal: EdgeInsets.edgePadding)
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
4E35CE6D2CBEDB7600DBD886 /* TaskState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E35CE6B2CBEDB7300DBD886 /* TaskState.swift */; };
|
||||
4E36395C2CC4DF0E00110EBC /* APIKeysViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E36395A2CC4DF0900110EBC /* APIKeysViewModel.swift */; };
|
||||
4E4A53222CBE0A1C003BD24D /* ChevronAlertButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB7B33A2CBDE63F004A342E /* ChevronAlertButton.swift */; };
|
||||
4E5334A22CD1A28700D59FA8 /* ActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E5334A12CD1A28400D59FA8 /* ActionButton.swift */; };
|
||||
4E5E48E52AB59806003F1B48 /* CustomizeViewsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */; };
|
||||
4E63B9FA2C8A5BEF00C25378 /* AdminDashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E63B9F42C8A5BEF00C25378 /* AdminDashboardView.swift */; };
|
||||
4E63B9FC2C8A5C3E00C25378 /* ActiveSessionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E63B9FB2C8A5C3E00C25378 /* ActiveSessionsViewModel.swift */; };
|
||||
|
@ -121,6 +122,7 @@
|
|||
4EF18B262CB9934C00343666 /* LibraryRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF18B252CB9934700343666 /* LibraryRow.swift */; };
|
||||
4EF18B282CB9936D00343666 /* ListColumnsPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF18B272CB9936400343666 /* ListColumnsPickerView.swift */; };
|
||||
4EF18B2A2CB993BD00343666 /* ListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF18B292CB993AD00343666 /* ListRow.swift */; };
|
||||
4EF659E32CDD270D00E0BE5D /* ActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF659E22CDD270B00E0BE5D /* ActionMenu.swift */; };
|
||||
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690E6267ABD79005D8AB9 /* HomeView.swift */; };
|
||||
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531AC8BE26750DE20091C7EB /* ImageView.swift */; };
|
||||
5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5321753A2671BCFC005491E6 /* SettingsViewModel.swift */; };
|
||||
|
@ -1099,6 +1101,7 @@
|
|||
4E35CE682CBED95F00DBD886 /* DayOfWeek.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayOfWeek.swift; sourceTree = "<group>"; };
|
||||
4E35CE6B2CBEDB7300DBD886 /* TaskState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskState.swift; sourceTree = "<group>"; };
|
||||
4E36395A2CC4DF0900110EBC /* APIKeysViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIKeysViewModel.swift; sourceTree = "<group>"; };
|
||||
4E5334A12CD1A28400D59FA8 /* ActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButton.swift; sourceTree = "<group>"; };
|
||||
4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeViewsSettings.swift; sourceTree = "<group>"; };
|
||||
4E63B9F42C8A5BEF00C25378 /* AdminDashboardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdminDashboardView.swift; sourceTree = "<group>"; };
|
||||
4E63B9FB2C8A5C3E00C25378 /* ActiveSessionsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveSessionsViewModel.swift; sourceTree = "<group>"; };
|
||||
|
@ -1152,6 +1155,7 @@
|
|||
4EF18B252CB9934700343666 /* LibraryRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryRow.swift; sourceTree = "<group>"; };
|
||||
4EF18B272CB9936400343666 /* ListColumnsPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListColumnsPickerView.swift; sourceTree = "<group>"; };
|
||||
4EF18B292CB993AD00343666 /* ListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRow.swift; sourceTree = "<group>"; };
|
||||
4EF659E22CDD270B00E0BE5D /* ActionMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionMenu.swift; sourceTree = "<group>"; };
|
||||
531690E6267ABD79005D8AB9 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
|
||||
531AC8BE26750DE20091C7EB /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = "<group>"; };
|
||||
5321753A2671BCFC005491E6 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
|
@ -2018,6 +2022,16 @@
|
|||
path = PlaybackBitrate;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E5334A02CD1A27C00D59FA8 /* ActionButtons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E5334A12CD1A28400D59FA8 /* ActionButton.swift */,
|
||||
E1C926032887565C002A7A66 /* ActionButtonHStack.swift */,
|
||||
4EF659E22CDD270B00E0BE5D /* ActionMenu.swift */,
|
||||
);
|
||||
path = ActionButtons;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E63B9F52C8A5BEF00C25378 /* AdminDashboardView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3967,7 +3981,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
E1A16CA2288A7D0000EA4679 /* AboutView */,
|
||||
E1C926032887565C002A7A66 /* ActionButtonHStack.swift */,
|
||||
4E5334A02CD1A27C00D59FA8 /* ActionButtons */,
|
||||
E1C926012887565C002A7A66 /* AttributeHStack.swift */,
|
||||
E185920528CDAA6400326F80 /* CastAndCrewHStack.swift */,
|
||||
E1153D982BBA3E6100424D36 /* EpisodeSelector */,
|
||||
|
@ -4572,6 +4586,7 @@
|
|||
E152107D2947ACA000375CC2 /* InvertedLightAppIcon.swift in Sources */,
|
||||
E1549663296CA2EF00C4EF88 /* UserSession.swift in Sources */,
|
||||
4EF18B2A2CB993BD00343666 /* ListRow.swift in Sources */,
|
||||
4EF659E32CDD270D00E0BE5D /* ActionMenu.swift in Sources */,
|
||||
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */,
|
||||
E145EB232BDCCA43003BF6F3 /* BulletedList.swift in Sources */,
|
||||
E104DC972B9E7E29008F506D /* AssertionFailureView.swift in Sources */,
|
||||
|
@ -4893,6 +4908,7 @@
|
|||
E1575E9A293E7B1E001665B1 /* Array.swift in Sources */,
|
||||
E1575E8D293E7B1E001665B1 /* URLComponents.swift in Sources */,
|
||||
E187A60329AB28F0008387E6 /* RotateContentView.swift in Sources */,
|
||||
4E5334A22CD1A28700D59FA8 /* ActionButton.swift in Sources */,
|
||||
4EBE064E2C7EB6D3004A6C03 /* VideoPlayerType.swift in Sources */,
|
||||
E1575E94293E7B1E001665B1 /* VerticalAlignment.swift in Sources */,
|
||||
E1575EA3293E7B1E001665B1 /* UIDevice.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue