From c2f57700a5af6ce29e2acaf5ed25a943e5e4636f Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 19 Jul 2023 15:55:29 +1000 Subject: [PATCH] infinite loop carousel --- .../MessageInfoView.swift | 2 +- .../SessionCarouselView+SwiftUI.swift | 70 ++++++++++++------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/Session/Media Viewing & Editing/MessageInfoView.swift b/Session/Media Viewing & Editing/MessageInfoView.swift index 4a08b7209..379ee9aa6 100644 --- a/Session/Media Viewing & Editing/MessageInfoView.swift +++ b/Session/Media Viewing & Editing/MessageInfoView.swift @@ -54,7 +54,7 @@ struct MessageInfoView: View { } // TODO: Attachment carousel view - SessionCarouselView_SwiftUI(colors: [.orange, .gray, .blue, .yellow]) + SessionCarouselView_SwiftUI(contentInfos: [.orange, .gray, .blue, .yellow]) .frame( maxWidth: .infinity, maxHeight: .infinity, diff --git a/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift b/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift index 84d2f42d2..5558592b9 100644 --- a/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift +++ b/SessionUIKit/Components/SessionCarouselView+SwiftUI.swift @@ -3,36 +3,44 @@ import SwiftUI public struct SessionCarouselView_SwiftUI: View { - @State var index = 0 + @State var index = 1 - var colors: [Color] + var contentInfos: [Color] + let numberOfPages: Int - public init(colors: [Color]) { - self.colors = colors + public init(contentInfos: [Color]) { + self.contentInfos = contentInfos + self.numberOfPages = contentInfos.count + + let first = self.contentInfos.first! + let last = self.contentInfos.last! + self.contentInfos.append(first) + self.contentInfos.insert(last, at: 0) } public var body: some View { HStack(spacing: 0) { - ArrowView(value: $index.animation(.easeInOut), range: 0...(colors.count - 1), type: .decrement) + ArrowView(index: $index, numberOfPages: numberOfPages, type: .decrement) .zIndex(1) - PageView(index: $index.animation(), maxIndex: colors.count - 1) { - ForEach(self.colors, id: \.self) { color in + PageView(index: $index, numberOfPages: self.numberOfPages) { + ForEach(self.contentInfos, id: \.self) { color in Rectangle() .foregroundColor(color) } } .aspectRatio(1, contentMode: .fit) - ArrowView(value: $index.animation(.easeInOut), range: 0...(colors.count - 1), type: .increment) + ArrowView(index: $index, numberOfPages: numberOfPages, type: .increment) .zIndex(1) } } } struct ArrowView: View { - @Binding var value: Int - let range: ClosedRange + @Binding var index: Int + let numberOfPages: Int + let maxIndex: Int let type: ArrowType enum ArrowType { @@ -40,9 +48,10 @@ struct ArrowView: View { case decrement } - init(value: Binding, range: ClosedRange, type: ArrowType) { - self._value = value - self.range = range + init(index: Binding, numberOfPages: Int, type: ArrowType) { + self._index = index + self.numberOfPages = numberOfPages + self.maxIndex = numberOfPages + 1 self.type = type } @@ -63,36 +72,40 @@ struct ArrowView: View { } func decrement() { - if value > range.lowerBound { - value -= 1 + withAnimation(.easeOut) { + self.index -= 1 } - if value < range.lowerBound { - value = range.lowerBound + + if self.index == 0 { + self.index = self.maxIndex - 1 } } func increment() { - if value < range.upperBound { - value += 1 + withAnimation(.easeOut) { + self.index += 1 } - if value > range.upperBound { - value = range.upperBound + + if self.index == self.maxIndex { + self.index = 1 } } } struct PageView: View where Content: View { @Binding var index: Int + let numberOfPages: Int let maxIndex: Int let content: () -> Content @State private var offset = CGFloat.zero @State private var dragging = false - init(index: Binding, maxIndex: Int, @ViewBuilder content: @escaping () -> Content) { + init(index: Binding, numberOfPages: Int, @ViewBuilder content: @escaping () -> Content) { self._index = index - self.maxIndex = maxIndex + self.numberOfPages = numberOfPages self.content = content + self.maxIndex = numberOfPages + 1 } var body: some View { @@ -120,12 +133,17 @@ struct PageView: View where Content: View { withAnimation(.easeOut) { self.dragging = false } + switch self.index { + case 0: self.index = self.maxIndex - 1 + case self.maxIndex: self.index = 1 + default: break + } } ) } .clipped() - PageControl(index: $index, maxIndex: maxIndex) + PageControl(index: $index, maxIndex: numberOfPages - 1) .padding(EdgeInsets(top: 0, leading: 0, bottom: 8, trailing: 0)) } } @@ -157,7 +175,7 @@ struct PageControl: View { HStack(spacing: 4) { ForEach(0...maxIndex, id: \.self) { index in Circle() - .fill(index == self.index ? Color.white : Color.gray) + .fill(index == ((self.index - 1) % (self.maxIndex + 1)) ? Color.white : Color.gray) .frame(width: 6.62, height: 6.62) } } @@ -180,7 +198,7 @@ struct SessionCarouselView_SwiftUI_Previews: PreviewProvider { Color.black } - SessionCarouselView_SwiftUI(colors: [.red, .orange, .blue]) + SessionCarouselView_SwiftUI(contentInfos: [.red, .orange, .blue]) } } }