chore: added media panning 19a47a6d
Steve · 2026-01-06 19:30 1 file(s) · +50 −26
Titan/Views/MediaPreviewView.swift +50 −26
124 124
    let data: Data
125 125
    @State private var scale: CGFloat = 1.0
126 126
    @State private var lastScale: CGFloat = 1.0
127 +
    @State private var offset: CGSize = .zero
128 +
    @State private var lastOffset: CGSize = .zero
127 129
128 130
    var body: some View {
129 131
        if let uiImage = UIImage(data: data) {
130 -
            Image(uiImage: uiImage)
131 -
                .resizable()
132 -
                .aspectRatio(contentMode: .fit)
133 -
                .scaleEffect(scale)
134 -
                .gesture(
135 -
                    MagnificationGesture()
136 -
                        .onChanged { value in
137 -
                            scale = lastScale * value
138 -
                        }
139 -
                        .onEnded { _ in
140 -
                            lastScale = scale
141 -
                            if scale < 1.0 {
142 -
                                withAnimation {
143 -
                                    scale = 1.0
144 -
                                    lastScale = 1.0
132 +
            GeometryReader { geometry in
133 +
                Image(uiImage: uiImage)
134 +
                    .resizable()
135 +
                    .aspectRatio(contentMode: .fit)
136 +
                    .scaleEffect(scale)
137 +
                    .offset(offset)
138 +
                    .frame(width: geometry.size.width, height: geometry.size.height)
139 +
                    .gesture(
140 +
                        MagnificationGesture()
141 +
                            .onChanged { value in
142 +
                                scale = lastScale * value
143 +
                            }
144 +
                            .onEnded { _ in
145 +
                                lastScale = scale
146 +
                                if scale < 1.0 {
147 +
                                    withAnimation {
148 +
                                        scale = 1.0
149 +
                                        lastScale = 1.0
150 +
                                        offset = .zero
151 +
                                        lastOffset = .zero
152 +
                                    }
145 153
                                }
146 154
                            }
147 -
                        }
148 -
                )
149 -
                .onTapGesture(count: 2) {
150 -
                    withAnimation {
151 -
                        if scale > 1.0 {
152 -
                            scale = 1.0
153 -
                            lastScale = 1.0
154 -
                        } else {
155 -
                            scale = 2.0
156 -
                            lastScale = 2.0
155 +
                            .simultaneously(with:
156 +
                                DragGesture()
157 +
                                    .onChanged { value in
158 +
                                        if scale > 1.0 {
159 +
                                            offset = CGSize(
160 +
                                                width: lastOffset.width + value.translation.width,
161 +
                                                height: lastOffset.height + value.translation.height
162 +
                                            )
163 +
                                        }
164 +
                                    }
165 +
                                    .onEnded { _ in
166 +
                                        lastOffset = offset
167 +
                                    }
168 +
                            )
169 +
                    )
170 +
                    .onTapGesture(count: 2) {
171 +
                        withAnimation {
172 +
                            if scale > 1.0 {
173 +
                                scale = 1.0
174 +
                                lastScale = 1.0
175 +
                                offset = .zero
176 +
                                lastOffset = .zero
177 +
                            } else {
178 +
                                scale = 2.0
179 +
                                lastScale = 2.0
180 +
                            }
157 181
                        }
158 182
                    }
159 -
                }
183 +
            }
160 184
        } else {
161 185
            VStack(spacing: 16) {
162 186
                Image(systemName: "photo.badge.exclamationmark")