mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-25 20:44:38 +00:00
reset user scroll position on dismiss; cleanup
This commit is contained in:
@@ -59,12 +59,12 @@ struct ChatListView: View {
|
||||
destination: chatView
|
||||
) { chatListView }
|
||||
}
|
||||
SheetRepresentable(isPresented: $userPickerShown) {
|
||||
}
|
||||
.modifier(
|
||||
Sheet(isPresented: $userPickerShown) {
|
||||
UserPicker(userPickerShown: $userPickerShown, activeSheet: $activeUserPickerSheet)
|
||||
}
|
||||
.allowsHitTesting(userPickerShown)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
)
|
||||
.sheet(item: $activeUserPickerSheet) { sheet in
|
||||
if let currentUser = chatModel.currentUser {
|
||||
switch sheet {
|
||||
|
||||
@@ -17,6 +17,7 @@ struct UserPicker: View {
|
||||
@State private var currentUser: Int64?
|
||||
@State private var switchingProfile = false
|
||||
@State private var frameWidth: CGFloat = 0
|
||||
@State private var resetScroll = ResetScrollAction()
|
||||
|
||||
// Inset grouped list dimensions
|
||||
private let imageSize: CGFloat = 44
|
||||
@@ -34,7 +35,7 @@ struct UserPicker: View {
|
||||
let currentUserWidth = max(frameWidth - sectionHorizontalPadding - rowPadding * 2 - 14 - imageSize, 0)
|
||||
VStack(spacing: sectionSpacing) {
|
||||
if let user = m.currentUser {
|
||||
StickyScrollView {
|
||||
StickyScrollView(resetScroll: $resetScroll) {
|
||||
HStack(spacing: rowPadding) {
|
||||
HStack {
|
||||
ProfileImage(imageStr: user.image, size: imageSize, color: Color(uiColor: .tertiarySystemGroupedBackground))
|
||||
@@ -43,7 +44,7 @@ struct UserPicker: View {
|
||||
}
|
||||
.padding(rowPadding)
|
||||
.frame(width: otherUsers.isEmpty ? sectionWidth : currentUserWidth, alignment: .leading)
|
||||
.background(elevatedSecondarySystemGroupedBackground(colorScheme))
|
||||
.background(elevatedSecondarySystemGroupedBackground)
|
||||
.clipShape(sectionShape)
|
||||
.onTapGesture { activeSheet = .currentProfile }
|
||||
ForEach(otherUsers) { u in
|
||||
@@ -88,7 +89,7 @@ struct UserPicker: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(elevatedSecondarySystemGroupedBackground(colorScheme))
|
||||
.background(elevatedSecondarySystemGroupedBackground)
|
||||
.clipShape(sectionShape)
|
||||
.padding(.horizontal, sectionHorizontalPadding)
|
||||
.padding(.bottom, sectionSpacing)
|
||||
@@ -110,10 +111,20 @@ struct UserPicker: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
// .modifier(ThemedBackground(grouped: true))
|
||||
.onChange(of: userPickerShown) {
|
||||
if !$0 { resetScroll() }
|
||||
}
|
||||
.modifier(ThemedBackground(grouped: true))
|
||||
.disabled(switchingProfile)
|
||||
}
|
||||
|
||||
var elevatedSecondarySystemGroupedBackground: Color {
|
||||
switch colorScheme {
|
||||
case .dark: Color(0xFF2C2C2E)
|
||||
default: Color(0xFFFFFFFF)
|
||||
}
|
||||
}
|
||||
|
||||
private var listDivider: some View {
|
||||
Divider().padding(.leading, 52)
|
||||
}
|
||||
@@ -130,11 +141,10 @@ struct UserPicker: View {
|
||||
Text(u.user.displayName).font(.title2).lineLimit(1)
|
||||
}
|
||||
.padding(rowPadding)
|
||||
.background(elevatedSecondarySystemGroupedBackground(colorScheme))
|
||||
.background(elevatedSecondarySystemGroupedBackground)
|
||||
.clipShape(sectionShape)
|
||||
.onTapGesture {
|
||||
switchingProfile = true
|
||||
|
||||
Task {
|
||||
do {
|
||||
try await changeActiveUserAsync_(u.user.userId, viewPwd: nil)
|
||||
|
||||
@@ -10,17 +10,31 @@ import SwiftUI
|
||||
|
||||
private let sheetAnimationDuration: Double = 0.3
|
||||
|
||||
struct Sheet<SheetContent: View>: ViewModifier {
|
||||
@Binding var isPresented: Bool
|
||||
@ViewBuilder let sheetContent: () -> SheetContent
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
ZStack {
|
||||
content
|
||||
SheetRepresentable(isPresented: $isPresented, content: sheetContent())
|
||||
.allowsHitTesting(isPresented)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SheetRepresentable<Content: View>: UIViewControllerRepresentable {
|
||||
@Binding var isPresented: Bool
|
||||
@ViewBuilder let content: () -> Content
|
||||
let content: Content
|
||||
|
||||
func makeUIViewController(context: Context) -> Controller<Content> {
|
||||
Controller(content: content(), representer: self)
|
||||
Controller(content: content, representer: self)
|
||||
}
|
||||
|
||||
func updateUIViewController(_ sheetController: Controller<Content>, context: Context) {
|
||||
sheetController.animate(isPresented: isPresented)
|
||||
sheetController.hostingController.rootView = content()
|
||||
sheetController.hostingController.rootView = content
|
||||
}
|
||||
|
||||
class Controller<C: View>: UIViewController {
|
||||
@@ -55,14 +69,7 @@ struct SheetRepresentable<Content: View>: UIViewControllerRepresentable {
|
||||
addChild(hostingController)
|
||||
hostingController.didMove(toParent: self)
|
||||
if let sheet = hostingController.view {
|
||||
sheet.backgroundColor = UIColor { traits in
|
||||
let elevated = switch traits.userInterfaceStyle {
|
||||
case .dark: elevatedSystemGroupedBackground(.dark)
|
||||
default: elevatedSystemGroupedBackground(.light)
|
||||
}
|
||||
return elevated.cgColor.map { UIColor(cgColor: $0) }
|
||||
?? .secondarySystemBackground
|
||||
}
|
||||
sheet.clipsToBounds = true
|
||||
sheet.layer.cornerRadius = 10
|
||||
sheet.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
|
||||
sheet.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(pan(gesture:))))
|
||||
@@ -117,63 +124,3 @@ struct SheetRepresentable<Content: View>: UIViewControllerRepresentable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Sheet Colors
|
||||
|
||||
func elevatedSystemGroupedBackground(_ colorScheme: ColorScheme) -> Color {
|
||||
switch colorScheme {
|
||||
case .dark: Color(0xFF1C1C1E)
|
||||
default: Color(0xFFF2F2F7)
|
||||
}
|
||||
}
|
||||
|
||||
func elevatedSecondarySystemGroupedBackground(_ colorScheme: ColorScheme) -> Color {
|
||||
switch colorScheme {
|
||||
case .dark: Color(0xFF2C2C2E)
|
||||
default: Color(0xFFFFFFFF)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Extracting Sheet Colors Programatically
|
||||
///
|
||||
/// System colors are returned dynamically, depending on the context:
|
||||
///
|
||||
/// struct ColorResolverView: View {
|
||||
/// @Environment(\.self) var environment
|
||||
/// let colors: [Color]
|
||||
///
|
||||
/// var body: some View {
|
||||
/// HStack {
|
||||
/// column.environment(\.colorScheme, .dark)
|
||||
/// column.environment(\.colorScheme, .light)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// var column: some View {
|
||||
/// VStack {
|
||||
/// ForEach(colors, id: \.self) {
|
||||
/// Text("\($0.resolve(in: environment))")
|
||||
/// .frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
/// .background($0)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Place `ColorResolverView` inside a sheet to acquire elevated color versions:
|
||||
///
|
||||
/// struct ContentView: View {
|
||||
/// var body: some View {
|
||||
/// EmptyView()
|
||||
/// .sheet(isPresented: .constant(true)) {
|
||||
/// ColorResolverView(
|
||||
/// colors: [
|
||||
/// Color(.systemGroupedBackground),
|
||||
/// Color(.secondarySystemGroupedBackground)
|
||||
/// ]
|
||||
/// )
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct StickyScrollView<Content: View>: UIViewRepresentable {
|
||||
@Binding var resetScroll: ResetScrollAction
|
||||
@ViewBuilder let content: () -> Content
|
||||
|
||||
func makeUIView(context: Context) -> UIScrollView {
|
||||
@@ -18,6 +19,9 @@ struct StickyScrollView<Content: View>: UIViewRepresentable {
|
||||
sv.showsHorizontalScrollIndicator = false
|
||||
sv.addSubview(hc.view)
|
||||
sv.delegate = context.coordinator
|
||||
DispatchQueue.main.async {
|
||||
resetScroll = ResetScrollAction { sv.setContentOffset(.zero, animated: false) }
|
||||
}
|
||||
return sv
|
||||
}
|
||||
|
||||
@@ -50,3 +54,8 @@ struct StickyScrollView<Content: View>: UIViewRepresentable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ResetScrollAction {
|
||||
var action = { }
|
||||
func callAsFunction() { action() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user