diff --git a/Swiftfin tvOS/Components/LibraryFilters/FilterViews/Components/FilterButton.swift b/Swiftfin tvOS/Components/LibraryFilters/FilterViews/Components/FilterButton.swift index 9893193c6..532c86616 100644 --- a/Swiftfin tvOS/Components/LibraryFilters/FilterViews/Components/FilterButton.swift +++ b/Swiftfin tvOS/Components/LibraryFilters/FilterViews/Components/FilterButton.swift @@ -33,7 +33,7 @@ struct FilterButton: View { private let role: ButtonRole? private var onSelect: () -> Void - // MARK: - Button Widths + // MARK: - Button Dimensions private let collapsedWidth: CGFloat = 75 @@ -44,11 +44,11 @@ struct FilterButton: View { // MARK: - Button Styles private var buttonColor: Color { - isSelected ? ((role == .destructive && isFocused) ? .red : accentColor) : Color.secondarySystemFill + isSelected ? ((role == .destructive && isFocused) ? Color.red.opacity(0.2) : accentColor) : Color.secondarySystemFill } private var textColor: Color { - isFocused ? ((role == .destructive) ? Color.red.opacity(0.2) : .black) : .primary + isFocused ? ((role == .destructive) ? .red : .black) : .primary } // MARK: - Initializer @@ -83,9 +83,20 @@ struct FilterButton: View { // MARK: - Body var body: some View { - Button { - onSelect() - } label: { + ZStack(alignment: .leading) { + // Visual background that expands/contracts + Capsule() + .foregroundColor(buttonColor) + .brightness(isFocused ? 0.25 : 0) + .opacity(isFocused ? 1 : 0.5) + .frame(width: isFocused ? expandedWidth : collapsedWidth, height: collapsedWidth) + .overlay { + Capsule() + .stroke(buttonColor, lineWidth: 1) + .brightness(isFocused ? 0.25 : 0) + } + .allowsHitTesting(false) + HStack(spacing: 10) { if let systemName = systemName { Image(systemName: systemName) @@ -93,38 +104,32 @@ struct FilterButton: View { .focusEffectDisabled() .foregroundColor(textColor) .frame(width: collapsedWidth, alignment: .center) - .focusable(false) } + if isFocused { Text(title) .foregroundColor(textColor) .transition(.move(edge: .leading).combined(with: .opacity)) + Spacer(minLength: 0) } } .font(.footnote.weight(.semibold)) - .frame( - width: isFocused ? expandedWidth : collapsedWidth, - height: collapsedWidth, - alignment: .leading - ) - .background { - Capsule() - .foregroundColor(buttonColor) - .brightness(isFocused ? 0.25 : 0) - .opacity(isFocused ? 1 : 0.5) - } - .overlay { - Capsule() - .stroke(buttonColor, lineWidth: 1) - .brightness(isFocused ? 0.25 : 0) + .frame(height: collapsedWidth) + .allowsHitTesting(false) + + Button { + onSelect() + } label: { + Color.clear + .frame(width: collapsedWidth, height: collapsedWidth) } - .animation(.easeInOut(duration: 0.25), value: isFocused) + .padding(0) + .buttonStyle(.borderless) + .focused($isFocused) } .frame(width: collapsedWidth, height: collapsedWidth, alignment: .leading) - .padding(0) - .buttonStyle(.borderless) - .focused($isFocused) + .animation(.easeIn(duration: 0.2), value: isFocused) } } diff --git a/Swiftfin tvOS/Components/LibraryFilters/FilterViews/FilterBar.swift b/Swiftfin tvOS/Components/LibraryFilters/FilterViews/FilterBar.swift index b1191ba45..2d18a7ea1 100644 --- a/Swiftfin tvOS/Components/LibraryFilters/FilterViews/FilterBar.swift +++ b/Swiftfin tvOS/Components/LibraryFilters/FilterViews/FilterBar.swift @@ -25,7 +25,7 @@ struct FilterBar: View { // MARK: - Body var body: some View { - VStack { + VStack(spacing: 20) { if viewModel.currentFilters.hasFilters { FilterButton( systemName: "line.3.horizontal.decrease.circle.fill", @@ -36,6 +36,9 @@ struct FilterBar: View { viewModel.send(.reset()) } .environment(\.isSelected, true) + } else { + Spacer() + .frame(width: 75, height: 75) } ForEach(filterTypes, id: \.self) { type in diff --git a/Swiftfin tvOS/Extensions/View/Modifiers/LibraryFilterModifier.swift b/Swiftfin tvOS/Extensions/View/Modifiers/LibraryFilterModifier.swift index f30554ae2..a5ded1ebc 100644 --- a/Swiftfin tvOS/Extensions/View/Modifiers/LibraryFilterModifier.swift +++ b/Swiftfin tvOS/Extensions/View/Modifiers/LibraryFilterModifier.swift @@ -11,42 +11,48 @@ import SwiftUI struct LibraryFilterModifier: ViewModifier { + // MARK: - Filter Views + let filters: () -> Filters let letters: () -> Letters? + // MARK: - Focus State + + @FocusState + private var isContentFocused: Bool + + // MARK: - State Variables + @State private var safeArea: EdgeInsets = .zero - private let collapsedWidth: CGFloat = 75 - private let expandedWidth: CGFloat = 200 - - @FocusState - private var isFilterFocused: Bool + // MARK: - Body func body(content: Content) -> some View { ZStack { content .frame(maxWidth: .infinity, maxHeight: .infinity) - .padding(.leading, collapsedWidth + 20) - .padding(.trailing, collapsedWidth + 20) + .padding(.leading, 100) + .padding(.trailing, LetterPickerBar.size + 20) + .focusSection() HStack(spacing: 0) { filters() - .frame(width: (isFilterFocused ? expandedWidth : collapsedWidth) + 10, alignment: .leading) + .frame(alignment: .leading) .padding(.leading, 20) .padding(.bottom, safeArea.bottom) .padding(.top, safeArea.top) .focusSection() - .focused($isFilterFocused) Spacer() if let letterPickerBar = letters() { letterPickerBar - .frame(width: collapsedWidth, alignment: .center) + .frame(alignment: .leading) .padding(.trailing, 20) .padding(.bottom, safeArea.bottom) .padding(.top, safeArea.top) + .focusSection() } } } diff --git a/Swiftfin tvOS/Views/PagingLibraryView/PagingLibraryView.swift b/Swiftfin tvOS/Views/PagingLibraryView/PagingLibraryView.swift index 8fe995f56..800c57100 100644 --- a/Swiftfin tvOS/Views/PagingLibraryView/PagingLibraryView.swift +++ b/Swiftfin tvOS/Views/PagingLibraryView/PagingLibraryView.swift @@ -275,7 +275,7 @@ struct PagingLibraryView: View { listItemView(item: item, posterType: posterType) } } - .onReachedBottomEdge(offset: .offset(300)) { + .onReachedBottomEdge(offset: .rows(3)) { viewModel.send(.getNextPage) } .proxy(collectionVGridProxy)