refactor(ios): cleanup pass — dead code removal and component consolidation
All checks were successful
CI / Scraper / Lint (pull_request) Successful in 16s
CI / Scraper / Test (pull_request) Successful in 20s
CI / Scraper / Docker Push (pull_request) Has been skipped
CI / UI / Build (pull_request) Successful in 21s
CI / UI / Docker Push (pull_request) Has been skipped
iOS CI / Build (push) Successful in 7m18s
iOS CI / Build (pull_request) Successful in 5m22s
iOS CI / Test (push) Successful in 10m55s
iOS CI / Test (pull_request) Successful in 9m32s
All checks were successful
CI / Scraper / Lint (pull_request) Successful in 16s
CI / Scraper / Test (pull_request) Successful in 20s
CI / Scraper / Docker Push (pull_request) Has been skipped
CI / UI / Build (pull_request) Successful in 21s
CI / UI / Docker Push (pull_request) Has been skipped
iOS CI / Build (push) Successful in 7m18s
iOS CI / Build (pull_request) Successful in 5m22s
iOS CI / Test (push) Successful in 10m55s
iOS CI / Test (pull_request) Successful in 9m32s
- Remove dead structs: ReadingProgress, HomeData, PBList (Models.swift) - Remove unused APIClient members: fetchRaw, setSessionId, BrowseParams; simplify logout(); drop no-op CodingKeys from BrowseResponse - Remove absolutePrevChapter/absoluteNextChapter computed props (replaced by prevChapter/nextChapter); replace URLSession cover prefetch with Kingfisher - Drop scrollOffset state var and dead subtitle block in ChapterRow (BookDetailView) - Remove never-set chaptersLoading published prop (BookDetailViewModel) - Add unified ChipButton(.filled/.outlined) to CommonViews replacing three near-identical pill chip types - Replace FilterChipView+SortChip in LibraryView and FilterChip in BrowseView with ChipButton - Replace inline KFImage usage in HomeView with AsyncCoverImage - Fix deprecated .navigationBarHidden(true) → .toolbar(.hidden, for: .navigationBar) in AuthView
This commit is contained in:
@@ -96,7 +96,7 @@ struct AuthView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.navigationBarHidden(true)
|
.toolbar(.hidden, for: .navigationBar)
|
||||||
}
|
}
|
||||||
.onChange(of: mode) { _, _ in
|
.onChange(of: mode) { _, _ in
|
||||||
authStore.error = nil
|
authStore.error = nil
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ struct BrowseView: View {
|
|||||||
// Filter chips row
|
// Filter chips row
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
FilterChip(label: "Sort: \(vm.sort.capitalized)", isActive: vm.sort != "popular") {
|
ChipButton(label: "Sort: \(vm.sort.capitalized)", isSelected: vm.sort != "popular", style: .outlined) {
|
||||||
showFilters = true
|
showFilters = true
|
||||||
}
|
}
|
||||||
FilterChip(label: "Genre: \(vm.genre == "all" ? "All" : vm.genre.capitalized)", isActive: vm.genre != "all") {
|
ChipButton(label: "Genre: \(vm.genre == "all" ? "All" : vm.genre.capitalized)", isSelected: vm.genre != "all", style: .outlined) {
|
||||||
showFilters = true
|
showFilters = true
|
||||||
}
|
}
|
||||||
FilterChip(label: "Status: \(vm.status == "all" ? "All" : vm.status.capitalized)", isActive: vm.status != "all") {
|
ChipButton(label: "Status: \(vm.status == "all" ? "All" : vm.status.capitalized)", isSelected: vm.status != "all", style: .outlined) {
|
||||||
showFilters = true
|
showFilters = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,25 +103,6 @@ struct BrowseView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Filter chip
|
|
||||||
|
|
||||||
private struct FilterChip: View {
|
|
||||||
let label: String
|
|
||||||
let isActive: Bool
|
|
||||||
let action: () -> Void
|
|
||||||
var body: some View {
|
|
||||||
Button(action: action) {
|
|
||||||
Text(label)
|
|
||||||
.font(.caption.bold())
|
|
||||||
.padding(.horizontal, 10)
|
|
||||||
.padding(.vertical, 6)
|
|
||||||
.background(isActive ? Color.amber.opacity(0.15) : Color(.systemGray6), in: Capsule())
|
|
||||||
.foregroundStyle(isActive ? .amber : .primary)
|
|
||||||
.overlay(Capsule().strokeBorder(isActive ? Color.amber : .clear, lineWidth: 1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Browse card
|
// MARK: - Browse card
|
||||||
|
|
||||||
private struct BrowseCard: View {
|
private struct BrowseCard: View {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Kingfisher
|
|
||||||
|
|
||||||
struct HomeView: View {
|
struct HomeView: View {
|
||||||
@StateObject private var vm = HomeViewModel()
|
@StateObject private var vm = HomeViewModel()
|
||||||
@@ -100,9 +99,7 @@ private struct HeroContinueCard: View {
|
|||||||
NavigationLink(value: NavDestination.chapter(item.book.slug, item.chapter)) {
|
NavigationLink(value: NavDestination.chapter(item.book.slug, item.chapter)) {
|
||||||
ZStack(alignment: .bottomLeading) {
|
ZStack(alignment: .bottomLeading) {
|
||||||
// Blurred background
|
// Blurred background
|
||||||
KFImage(URL(string: item.book.cover))
|
AsyncCoverImage(url: item.book.cover, isBackground: true)
|
||||||
.resizable()
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(height: 220)
|
.frame(height: 220)
|
||||||
.blur(radius: 22)
|
.blur(radius: 22)
|
||||||
@@ -122,13 +119,7 @@ private struct HeroContinueCard: View {
|
|||||||
|
|
||||||
// Content: cover on left, info stacked on right
|
// Content: cover on left, info stacked on right
|
||||||
HStack(alignment: .bottom, spacing: 14) {
|
HStack(alignment: .bottom, spacing: 14) {
|
||||||
KFImage(URL(string: item.book.cover))
|
AsyncCoverImage(url: item.book.cover)
|
||||||
.resizable()
|
|
||||||
.placeholder {
|
|
||||||
RoundedRectangle(cornerRadius: 10)
|
|
||||||
.fill(Color(.systemGray5))
|
|
||||||
}
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(width: 96, height: 138)
|
.frame(width: 96, height: 138)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
.shadow(color: .black.opacity(0.55), radius: 12, y: 6)
|
.shadow(color: .black.opacity(0.55), radius: 12, y: 6)
|
||||||
@@ -215,14 +206,7 @@ private struct ContinueReadingCard: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
ZStack(alignment: .bottomTrailing) {
|
ZStack(alignment: .bottomTrailing) {
|
||||||
KFImage(URL(string: item.book.cover))
|
AsyncCoverImage(url: item.book.cover)
|
||||||
.resizable()
|
|
||||||
.placeholder {
|
|
||||||
RoundedRectangle(cornerRadius: 8)
|
|
||||||
.fill(Color(.systemGray5))
|
|
||||||
.overlay(Image(systemName: "book.closed").foregroundStyle(.secondary))
|
|
||||||
}
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(width: 110, height: 158)
|
.frame(width: 110, height: 158)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||||
|
|
||||||
@@ -258,14 +242,7 @@ private struct ShelfBookCard: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
KFImage(URL(string: book.cover))
|
AsyncCoverImage(url: book.cover)
|
||||||
.resizable()
|
|
||||||
.placeholder {
|
|
||||||
RoundedRectangle(cornerRadius: 8)
|
|
||||||
.fill(Color(.systemGray5))
|
|
||||||
.overlay(Image(systemName: "book.closed").foregroundStyle(.secondary))
|
|
||||||
}
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(width: 110, height: 158)
|
.frame(width: 110, height: 158)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||||
.shadow(color: .black.opacity(0.12), radius: 4, y: 2)
|
.shadow(color: .black.opacity(0.12), radius: 4, y: 2)
|
||||||
|
|||||||
@@ -235,56 +235,6 @@ struct LibraryView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Genre filter chip
|
|
||||||
|
|
||||||
private struct FilterChipView: View {
|
|
||||||
let label: String
|
|
||||||
let isSelected: Bool
|
|
||||||
let action: () -> Void
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Button(action: action) {
|
|
||||||
Text(label)
|
|
||||||
.font(.caption.weight(isSelected ? .semibold : .regular))
|
|
||||||
.padding(.horizontal, 12)
|
|
||||||
.padding(.vertical, 6)
|
|
||||||
.background(
|
|
||||||
Capsule()
|
|
||||||
.fill(isSelected ? Color.amber : Color(.systemGray5))
|
|
||||||
)
|
|
||||||
.foregroundStyle(isSelected ? .white : .primary)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Sort chip
|
|
||||||
|
|
||||||
private struct SortChip: View {
|
|
||||||
let label: String
|
|
||||||
let isSelected: Bool
|
|
||||||
let action: () -> Void
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Button(action: action) {
|
|
||||||
Text(label)
|
|
||||||
.font(.subheadline.weight(isSelected ? .semibold : .regular))
|
|
||||||
.padding(.horizontal, 14)
|
|
||||||
.padding(.vertical, 6)
|
|
||||||
.background(
|
|
||||||
Capsule()
|
|
||||||
.fill(isSelected ? Color.amber.opacity(0.15) : Color(.systemGray6))
|
|
||||||
.overlay(
|
|
||||||
Capsule()
|
|
||||||
.stroke(isSelected ? Color.amber : .clear, lineWidth: 1.5)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.foregroundStyle(isSelected ? .amber : .primary)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Library book card (3-column)
|
// MARK: - Library book card (3-column)
|
||||||
|
|
||||||
private struct LibraryBookCard: View {
|
private struct LibraryBookCard: View {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ struct MiniPlayerView: View {
|
|||||||
// Previous chapter button
|
// Previous chapter button
|
||||||
if audioPlayer.status == .ready {
|
if audioPlayer.status == .ready {
|
||||||
Button {
|
Button {
|
||||||
if let prev = audioPlayer.absolutePrevChapter {
|
if let prev = audioPlayer.prevChapter {
|
||||||
NotificationCenter.default.post(
|
NotificationCenter.default.post(
|
||||||
name: .skipToPrevChapter,
|
name: .skipToPrevChapter,
|
||||||
object: nil,
|
object: nil,
|
||||||
@@ -62,8 +62,8 @@ struct MiniPlayerView: View {
|
|||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.disabled(audioPlayer.absolutePrevChapter == nil)
|
.disabled(audioPlayer.prevChapter == nil)
|
||||||
.opacity(audioPlayer.absolutePrevChapter == nil ? 0.4 : 1.0)
|
.opacity(audioPlayer.prevChapter == nil ? 0.4 : 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status indicator or play/pause control
|
// Status indicator or play/pause control
|
||||||
@@ -92,7 +92,7 @@ struct MiniPlayerView: View {
|
|||||||
// Next chapter button
|
// Next chapter button
|
||||||
if audioPlayer.status == .ready {
|
if audioPlayer.status == .ready {
|
||||||
Button {
|
Button {
|
||||||
if let next = audioPlayer.absoluteNextChapter {
|
if let next = audioPlayer.nextChapter {
|
||||||
NotificationCenter.default.post(
|
NotificationCenter.default.post(
|
||||||
name: .skipToNextChapter,
|
name: .skipToNextChapter,
|
||||||
object: nil,
|
object: nil,
|
||||||
@@ -124,8 +124,8 @@ struct MiniPlayerView: View {
|
|||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.disabled(audioPlayer.absoluteNextChapter == nil)
|
.disabled(audioPlayer.nextChapter == nil)
|
||||||
.opacity(audioPlayer.absoluteNextChapter == nil ? 0.4 : 1.0)
|
.opacity(audioPlayer.nextChapter == nil ? 0.4 : 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,9 +342,9 @@ struct FullPlayerView: View {
|
|||||||
PlayerChapterSkipButton(
|
PlayerChapterSkipButton(
|
||||||
systemName: "backward.end.fill",
|
systemName: "backward.end.fill",
|
||||||
size: 30,
|
size: 30,
|
||||||
disabled: audioPlayer.absolutePrevChapter == nil
|
disabled: audioPlayer.prevChapter == nil
|
||||||
) {
|
) {
|
||||||
if let prev = audioPlayer.absolutePrevChapter {
|
if let prev = audioPlayer.prevChapter {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
NotificationCenter.default.post(
|
NotificationCenter.default.post(
|
||||||
name: .skipToPrevChapter, object: nil,
|
name: .skipToPrevChapter, object: nil,
|
||||||
@@ -364,10 +364,10 @@ struct FullPlayerView: View {
|
|||||||
PlayerChapterSkipButton(
|
PlayerChapterSkipButton(
|
||||||
systemName: "forward.end.fill",
|
systemName: "forward.end.fill",
|
||||||
size: 30,
|
size: 30,
|
||||||
disabled: audioPlayer.absoluteNextChapter == nil,
|
disabled: audioPlayer.nextChapter == nil,
|
||||||
prefetching: audioPlayer.nextPrefetchStatus == .prefetching
|
prefetching: audioPlayer.nextPrefetchStatus == .prefetching
|
||||||
) {
|
) {
|
||||||
if let next = audioPlayer.absoluteNextChapter {
|
if let next = audioPlayer.nextChapter {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
NotificationCenter.default.post(
|
NotificationCenter.default.post(
|
||||||
name: .skipToNextChapter, object: nil,
|
name: .skipToNextChapter, object: nil,
|
||||||
|
|||||||
13
scripts/.runner
Normal file
13
scripts/.runner
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"WARNING": "This file is automatically generated by act-runner. Do not edit it manually unless you know what you are doing. Removing this file will cause act runner to re-register as a new runner.",
|
||||||
|
"id": 11,
|
||||||
|
"uuid": "d5d04e0a-572c-46c0-83be-405508948391",
|
||||||
|
"name": "runner-mac-1",
|
||||||
|
"token": "ddf214ce148b4673a186f29cb684b407cb8c2ecc",
|
||||||
|
"address": "https://gitea.kalekber.cc/",
|
||||||
|
"labels": [
|
||||||
|
"macos-latest:host",
|
||||||
|
"macos-14:host"
|
||||||
|
],
|
||||||
|
"ephemeral": false
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user