diff --git a/EhPanda/App/Utility.swift b/EhPanda/App/Utility.swift index b5ca0739..0c3c8987 100644 --- a/EhPanda/App/Utility.swift +++ b/EhPanda/App/Utility.swift @@ -58,17 +58,6 @@ var galleryType: GalleryType { return GalleryType(rawValue: rawValue) ?? .ehentai } -var vcsCount: Int { - guard let navigationVC = UIApplication - .shared.windows.first? - .rootViewController? - .children.first - as? UINavigationController - else { return -1 } - - return navigationVC.viewControllers.count -} - var appIconType: IconType { if let alterName = UIApplication .shared.alternateIconName, diff --git a/EhPanda/DataFlow/AppAction.swift b/EhPanda/DataFlow/AppAction.swift index cbe8b58f..d893e31a 100644 --- a/EhPanda/DataFlow/AppAction.swift +++ b/EhPanda/DataFlow/AppAction.swift @@ -22,6 +22,7 @@ enum AppAction { case updateDiskImageCacheSize(size: String) case updateAppIconType(iconType: IconType) case updateHistoryItems(gid: String) + case updateViewControllersCount case resetDownloadCommandResponse case replaceMangaCommentJumpID(gid: String?) case updateIsSlideMenuClosed(isClosed: Bool) diff --git a/EhPanda/DataFlow/AppState.swift b/EhPanda/DataFlow/AppState.swift index 747cf50c..11469bdf 100644 --- a/EhPanda/DataFlow/AppState.swift +++ b/EhPanda/DataFlow/AppState.swift @@ -24,6 +24,7 @@ extension AppState { var isPreview = false var isAppUnlocked = true var blurRadius: CGFloat = 0 + var viewControllersCount = 1 var isSlideMenuClosed = true var navBarHidden = false var homeListType: HomeListType = .frontpage diff --git a/EhPanda/DataFlow/Store.swift b/EhPanda/DataFlow/Store.swift index 1bbaaea9..0cc08e03 100644 --- a/EhPanda/DataFlow/Store.swift +++ b/EhPanda/DataFlow/Store.swift @@ -50,6 +50,19 @@ final class Store: ObservableObject { case .updateHistoryItems(let gid): let item = appState.cachedList.items?[gid] appState.homeInfo.insertHistoryItem(manga: item) + case .updateViewControllersCount: + var viewControllersCount = -1 + if let navigationVC = UIApplication + .shared.windows.first? + .rootViewController? + .children.first + as? UINavigationController + { + viewControllersCount = + navigationVC.viewControllers.count + } + + appState.environment.viewControllersCount = viewControllersCount case .resetDownloadCommandResponse: appState.detailInfo.downloadCommandResponse = nil appState.detailInfo.downloadCommandSending = false diff --git a/EhPanda/DataFlow/StoreAccessor.swift b/EhPanda/DataFlow/StoreAccessor.swift index f5c1a425..c6bb9ef4 100644 --- a/EhPanda/DataFlow/StoreAccessor.swift +++ b/EhPanda/DataFlow/StoreAccessor.swift @@ -51,6 +51,9 @@ extension StoreAccessor { var homeListType: HomeListType { environment.homeListType } + var viewControllersCount: Int { + environment.viewControllersCount + } } // MARK: Settings diff --git a/EhPanda/View/Content/ContentView.swift b/EhPanda/View/Content/ContentView.swift index 7564f6f2..35b54b33 100644 --- a/EhPanda/View/Content/ContentView.swift +++ b/EhPanda/View/Content/ContentView.swift @@ -14,6 +14,10 @@ struct ContentView: View, StoreAccessor { @EnvironmentObject var store: Store @State private var readingProgress: Int = -1 + @State private var scale: CGFloat = 1 + @State private var offset: CGSize = .zero + @State private var newOffset: CGSize = .zero + private let gid: String init(gid: String) { @@ -22,7 +26,23 @@ struct ContentView: View, StoreAccessor { // MARK: ContentView var body: some View { - Group { + let tapGesture = TapGesture( + count: 2 + ) + .onEnded(onTapGestureEnded) + + let magnificationGesture = MagnificationGesture() + .onChanged(onMagnificationGestureChanged) + .onEnded(onMagnificationGestureEnded) + + let dragGesture = DragGesture( + minimumDistance: 0.0, + coordinateSpace: .local + ) + .onChanged(onDragGestureChanged) + .onEnded(onDragGestureEnded) + + return Group { if let contents = mangaContents, let setting = setting, !contents.isEmpty @@ -65,7 +85,18 @@ struct ContentView: View, StoreAccessor { } } .ignoresSafeArea() - .transition(AnyTransition.opacity.animation(.default)) + .transition( + AnyTransition + .opacity + .animation( + .default + ) + ) + .scaleEffect(scale) + .offset(offset) + .gesture(tapGesture) + .gesture(dragGesture) + .gesture(magnificationGesture) } } else if contentInfo.mangaContentsLoading { LoadingView() @@ -175,6 +206,53 @@ private extension ContentView { store.dispatch(.toggleNavBarHidden(isHidden: true)) } } + + // MARK: Gestures + func onTapGestureEnded(_ value: TapGesture.Value) { + setOffset(.zero) + setScale(scale == 1 ? 2 : 1) + } + func onDragGestureChanged(_ value: DragGesture.Value) { +// pointTapped = value.startLocation + + if scale > 1 { + let newX = value.translation.width + newOffset.width + let screenW = UIScreen.main.bounds.width + let marginW = screenW * (scale - 1) / 2 + + let newOffsetW = min(max(newX, -marginW), marginW) + setOffset(CGSize(width: newOffsetW, height: offset.height)) + } + } + func onDragGestureEnded(_ value: DragGesture.Value) { + onDragGestureChanged(value) + + if scale > 1 { + newOffset.width = offset.width + } + } + func onMagnificationGestureChanged(_ value: MagnificationGesture.Value) { + withAnimation { + setOffset(.zero) + setScale(max(value.magnitude, 1)) + } + } + func onMagnificationGestureEnded(_ value: MagnificationGesture.Value) { + onMagnificationGestureChanged(value) + } + + func setOffset(_ newOffset: CGSize) { + let animation = Animation + .linear(duration: 0.1) + withAnimation(animation) { + offset = newOffset + } + } + func setScale(_ newScale: CGFloat) { + withAnimation { + scale = newScale + } + } } // MARK: ImageContainer @@ -215,14 +293,14 @@ private struct ImageContainer: View { .loadImmediately() .resizable() .scaledToFit() - .onTapGesture(perform: onTap) - .onLongPressGesture( - minimumDuration: 0, - maximumDistance: .infinity, - pressing: { _ in - onLongPressing(tag: content.tag) - }, perform: {} - ) +// .onTapGesture(perform: onTap) +// .onLongPressGesture( +// minimumDuration: 2, +// maximumDistance: .infinity, +// pressing: { _ in +// onLongPressing(tag: content.tag) +// }, perform: {} +// ) } private func onWebImageProgress( diff --git a/EhPanda/View/Detail/DetailView.swift b/EhPanda/View/Detail/DetailView.swift index 4dd94d7e..c27c704c 100644 --- a/EhPanda/View/Detail/DetailView.swift +++ b/EhPanda/View/Detail/DetailView.swift @@ -187,8 +187,10 @@ private extension DetailView { updateMangaDetail() } updateHistoryItems() + updateViewControllersCount() } func onDisappear() { + updateViewControllersCount() postDetailViewOnDisappearNotification() } func onArchiveButtonTap() { @@ -263,6 +265,9 @@ private extension DetailView { store.dispatch(.updateHistoryItems(gid: gid)) } } + func updateViewControllersCount() { + store.dispatch(.updateViewControllersCount) + } func sendRating(_ value: Int) { store.dispatch(.rate(gid: gid, rating: value)) } diff --git a/EhPanda/View/Home/Home.swift b/EhPanda/View/Home/Home.swift index 3a897e5e..38027229 100644 --- a/EhPanda/View/Home/Home.swift +++ b/EhPanda/View/Home/Home.swift @@ -42,37 +42,34 @@ struct Home: View, StoreAccessor { .gesture( DragGesture(minimumDistance: 20) .onChanged { value in - if hasPermission { - withAnimation(Animation.linear(duration: 0.2)) { - switch direction { - case .none: - let isToLeft = value.translation.width < 0 - direction = isToLeft ? .toLeft : .toRight - case .toLeft: - if offset > -width { - offset = min(value.translation.width, 0) - } - case .toRight: - if offset < 0, value.startLocation.x < 20 { - offset = max(-width + value.translation.width, -width) - } + withAnimation(Animation.linear(duration: 0.2)) { + switch direction { + case .none: + let isToLeft = value.translation.width < 0 + direction = isToLeft ? .toLeft : .toRight + case .toLeft: + if offset > -width { + offset = min(value.translation.width, 0) + } + case .toRight: + if offset < 0, value.startLocation.x < 20 { + offset = max(-width + value.translation.width, -width) } - updateSlideMenuState(isClosed: offset == -width) } + updateSlideMenuState(isClosed: offset == -width) } } .onEnded { value in - if hasPermission { - let perdictedWidth = value.predictedEndTranslation.width - if perdictedWidth > width / 2 || -offset < width / 2 { - performTransition(0) - } - if perdictedWidth < -width / 2 || -offset > width / 2 { - performTransition(-width) - } - direction = .none + let perdictedWidth = value.predictedEndTranslation.width + if perdictedWidth > width / 2 || -offset < width / 2 { + performTransition(0) } - } + if perdictedWidth < -width / 2 || -offset > width / 2 { + performTransition(-width) + } + direction = .none + }, + including: gestureMask ) .onReceive( NotificationCenter.default.publisher( @@ -107,9 +104,10 @@ private extension Home { case toRight } - var hasPermission: Bool { - vcsCount == 1 + var gestureMask: GestureMask { + viewControllersCount == 1 ? .all : .none } + var opacity: Double { let scale = colorScheme == .light ? 0.2 : 0.5 return Double((width + offset) / width) * scale diff --git a/EhPanda/View/Home/HomeView.swift b/EhPanda/View/Home/HomeView.swift index 43895b23..337535ca 100644 --- a/EhPanda/View/Home/HomeView.swift +++ b/EhPanda/View/Home/HomeView.swift @@ -122,7 +122,7 @@ private extension HomeView { } } var hasJumpPermission: Bool { - vcsCount == 1 && isTokenMatched + viewControllersCount == 1 && isTokenMatched && setting?.detectGalleryFromPasteboard == true } @@ -256,7 +256,7 @@ private extension HomeView { fetchFrontpageItemsIfNeeded() } func onBecomeActive() { - if vcsCount == 1 { + if viewControllersCount == 1 { detectPasteboard() fetchGreetingIfNeeded() } @@ -405,6 +405,12 @@ private extension HomeView { func replaceMangaCommentJumpID(gid: String?) { store.dispatch(.replaceMangaCommentJumpID(gid: gid)) } + func toggleNewDawn() { + store.dispatch(.toggleHomeViewSheetState(state: .newDawn)) + } + func updateViewControllersCount() { + store.dispatch(.updateViewControllersCount) + } func fetchGreetingIfNeeded() { func verifyDate(with updateTime: Date?) -> Bool { @@ -454,10 +460,6 @@ private extension HomeView { fetchFavoritesItems() } } - - func toggleNewDawn() { - store.dispatch(.toggleHomeViewSheetState(state: .newDawn)) - } } // MARK: GenericList