963 lines
40 KiB
Swift
963 lines
40 KiB
Swift
//
|
|
// ContentView.swift
|
|
// gloss
|
|
//
|
|
// Created by Saint on 10/23/22.
|
|
//
|
|
|
|
import GRDB
|
|
import GRDBQuery
|
|
import SwiftUIIntrospect
|
|
import os
|
|
import SwiftUI
|
|
import WrappingHStack
|
|
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "network")
|
|
|
|
var currentId: String?
|
|
var currentOffset: CGFloat?
|
|
|
|
var gTracker: VisibilityTracker<String>?
|
|
var printCount: Int64 = 0
|
|
|
|
var disableDrop = false
|
|
|
|
// var curBook = "John"
|
|
|
|
public extension UserDefaults {
|
|
func optionalInt(forKey defaultName: String) -> Int? {
|
|
let defaults = self
|
|
if let value = defaults.value(forKey: defaultName) {
|
|
return value as? Int
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func optionalBool(forKey defaultName: String) -> Bool? {
|
|
let defaults = self
|
|
if let value = defaults.value(forKey: defaultName) {
|
|
return value as? Bool
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func goToRibbon(selectedRibbon: Ribbon,
|
|
destRibbon: Ribbon,
|
|
scrollId: Binding<String?>,
|
|
scrollOffset: Binding<CGFloat?>,
|
|
refresh: Binding<Bool>,
|
|
showOverlay: Binding<Bool>,
|
|
appDatabase: AppDatabase,
|
|
loading: Bool)
|
|
{
|
|
Task {
|
|
// print("SELECTED RIBBON", selectedRibbon)
|
|
var scrollOffsetToSave = currentOffset
|
|
var scrollIdToSave = currentId
|
|
|
|
var updatedRibbon = selectedRibbon
|
|
|
|
if selectedRibbon.id != destRibbon.id! || loading {
|
|
print("switching ribbons")
|
|
|
|
// withAnimation(.spring(response: 0.05)) {
|
|
// showOverlay.wrappedValue = true
|
|
showOverlay.wrappedValue = true
|
|
// }
|
|
|
|
if loading {
|
|
currentId = destRibbon.scrollId
|
|
// currentOffset = CGFloat(destRibbon.scrollOffset)
|
|
}
|
|
|
|
scrollId.wrappedValue = destRibbon.scrollId
|
|
// print("setting scroll offset")
|
|
scrollOffset.wrappedValue = CGFloat(destRibbon.scrollOffset)
|
|
// print(scrollOffset.wrappedValue)
|
|
// print("end setting scroll offset")
|
|
refresh.wrappedValue.toggle()
|
|
|
|
var updateSelectRibbon = SelectedRibbon(id: Int64(1), ribbonId: destRibbon.id!)
|
|
// print("Saving selected ribbon")
|
|
// print(updateSelectRibbon)
|
|
do {
|
|
_ = try await appDatabase.saveSelectedRibbon(&updateSelectRibbon)
|
|
} catch {
|
|
// Print("something wrong")
|
|
}
|
|
}
|
|
|
|
if !loading {
|
|
print("not loading")
|
|
updatedRibbon.scrollOffset = Int(floor(scrollOffsetToSave!))
|
|
updatedRibbon.scrollId = scrollIdToSave!
|
|
|
|
_ = try await appDatabase.saveRibbon(&updatedRibbon)
|
|
// print("saved updatedRibbon", updatedRibbon)
|
|
|
|
// print("UPDATED")
|
|
// scrollOffsetToSave = userDefaults.object(forKey: "currentOffset") as? CGFloat
|
|
// scrollIdToSave = userDefaults.object(forKey: "currentId") as? String
|
|
} else {
|
|
print("loading")
|
|
}
|
|
|
|
// print("scrollOffsetToSave: ", scrollOffsetToSave)
|
|
// print("scrollIdToSave: ", scrollIdToSave)
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
@ViewBuilder
|
|
func `if`<Transform: View>(_ condition: Bool, transform: (Self) -> Transform) -> some View {
|
|
if condition { transform(self) }
|
|
else { self }
|
|
}
|
|
}
|
|
|
|
struct RibbonCrown: View {
|
|
var ribbon: Ribbon
|
|
@Binding var scrollId: String?
|
|
@Binding var scrollOffset: CGFloat?
|
|
@Binding var showOverlay: Bool
|
|
@Binding var refresh: Bool
|
|
var draggedRibbon: Ribbon?
|
|
var isDragging: Bool
|
|
|
|
var height = CGFloat(45)
|
|
var xOffset = CGFloat(25)
|
|
var scale = 0.65
|
|
|
|
@Environment(\.appDatabase) private var appDatabase
|
|
|
|
@Query(SelectedRibbonRequest()) private var sr: [Ribbon]
|
|
|
|
@State var saveOffset = CGFloat()
|
|
var body: some View {
|
|
ZStack {
|
|
MyIcon().frame(
|
|
width: CGFloat(100 * 1.66 * scale),
|
|
height: CGFloat(100 * scale),
|
|
alignment: .center
|
|
).foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
|
|
.if(draggedRibbon != nil && draggedRibbon!.id == ribbon.id && isDragging) { $0.overlay(Color(red: 0.1, green: 0.1, blue: 0.1)) }
|
|
|
|
// .offset(x: 10)
|
|
|
|
Text(ribbon.title)
|
|
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
// .foregroundColor(.white))
|
|
// .foregroundColor(.black)
|
|
.frame(minWidth: CGFloat(70),
|
|
maxWidth: CGFloat(70),
|
|
minHeight: height,
|
|
maxHeight: height,
|
|
alignment: .center)
|
|
|
|
.if(draggedRibbon != nil && draggedRibbon!.id == ribbon.id && isDragging) { $0.overlay(Color(red: 0.1, green: 0.1, blue: 0.1)) }
|
|
|
|
// .if(!isDragging || draggedRibbon == nil || draggedRibbon!.id != ribbon.id) { $0.background(Color(red: 0.1, green: 0.1, blue: 0.1)) }
|
|
// .if(draggedRibbon != nil && draggedRibbon!.id == ribbon.id) { $0.background(.red) }
|
|
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
|
// .offset(x: 10)
|
|
// .background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
|
// .background(.red)
|
|
// .background(.yellow)
|
|
.multilineTextAlignment(.center)
|
|
// .minimumScaleFactor(0.5)
|
|
// .padding([.top, .bottom], 10)
|
|
.font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(10)))
|
|
}
|
|
.frame(width: CGFloat(100 * 1.66 * scale + 10), height: CGFloat(100 * scale + 5))
|
|
}
|
|
}
|
|
|
|
class Verse: NSObject, Codable {
|
|
var body: String
|
|
var verse: Int
|
|
}
|
|
|
|
func makeVerseView(seg: SegDenorm) -> some View {
|
|
var retView = Text("")
|
|
var segSplit = seg.body.components(separatedBy: ";;")
|
|
let decoder = JSONDecoder()
|
|
for (index, item) in segSplit.enumerated() {
|
|
let verse = try! decoder.decode(Verse.self, from: item.data(using: .utf8)!)
|
|
|
|
retView = retView + Text(String(verse.verse))
|
|
.font(Font.custom("AveriaSerifLibre-Regular", size: 6))
|
|
.baselineOffset(6.0)
|
|
.foregroundColor(Color.white)
|
|
|
|
retView = retView + Text(verse.body)
|
|
.foregroundColor(Color.white)
|
|
.font(Font.custom("AveriaSerifLibre-Regular", size: 15))
|
|
}
|
|
return retView
|
|
}
|
|
|
|
private struct SegRow: View {
|
|
var seg: SegDenorm
|
|
var ribbonId: Int64
|
|
|
|
var body: some View {
|
|
var retView = Text("")
|
|
// .onTapGesture {
|
|
// // selectedLine = seg.id
|
|
// // Print(selectedLine)
|
|
// Print("meow")
|
|
// // Print(verse.body)
|
|
// }
|
|
var segSplit = seg.body.components(separatedBy: ";;")
|
|
let decoder = JSONDecoder()
|
|
// Text(segSplit[0].body)
|
|
// .id(seg.id)
|
|
// VStack {
|
|
// ForEach(segSplit.indices) { i in
|
|
segSplit.enumerated().forEach { _, item in
|
|
let verse = try! decoder.decode(Verse.self, from: item.data(using: .utf8)!)
|
|
|
|
var attributedString: AttributedString {
|
|
// var result = AttributedString("Hello World!")
|
|
var result = AttributedString(verse.body)
|
|
// result.underlineStyle = Text.LineStyle(
|
|
// pattern: .dot, color: .white)
|
|
return result
|
|
}
|
|
|
|
retView = retView + Text(String(ribbonId))
|
|
// retView = retView + Text(attributedString)
|
|
// Text(seg.body)
|
|
// .contentShape(Rectangle())
|
|
.font(Font.custom("AveriaSerifLibre-Regular", size: 10))
|
|
.baselineOffset(6.0)
|
|
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
|
|
retView = retView +
|
|
Text(attributedString)
|
|
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
.font(Font.custom("AveriaSerifLibre-Regular", size: 20))
|
|
// .frame(maxWidth: .infinity, alignment: .leading)
|
|
// .contentShape(Rectangle())
|
|
|
|
// .listRowBackground(Color(red: 0.2, green: 0.8, blue: 0.2))
|
|
// .listRowInsets(EdgeInsets())
|
|
// .padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
|
|
// .listRowSeparator(.hidden)
|
|
// .id(String(seg.id) + "body" + String(i))
|
|
// .id(seg.id)
|
|
|
|
// .listRowBackground(Color(red: 0.2, green: 0.8, blue: 0.2))
|
|
// .listRowInsets(EdgeInsets())
|
|
// .padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
|
|
// .listRowSeparator(.hidden)
|
|
// .id(String(seg.id) + "verse" + String(i))
|
|
// .id(seg.id)
|
|
// .onTapGesture {
|
|
// selectedLine = seg.id
|
|
// Print(selectedLine)
|
|
// }
|
|
}
|
|
// }
|
|
|
|
let myText = "There was a man sent from God, whose name was John. This man came for a witness, to give testimony of the light, that all men might believe through him. He was not the light, but was to give testimony of the light. That was the true light, which enlighteneth every man that cometh into this world. He was in the world, and the world was made by him, and the world knew him not."
|
|
let arrayOfText = myText.components(separatedBy: " ")
|
|
|
|
|
|
|
|
var wordSelected = ""
|
|
var newView = WrappingHStack(alignment: .leading, horizontalSpacing: 3.5) {
|
|
ForEach(0..<arrayOfText.count, id: \.self) { index in
|
|
Text(arrayOfText[index])
|
|
|
|
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
.font(Font.custom("AveriaSerifLibre-Regular", size: 20))
|
|
|
|
.foregroundColor(Color.white)
|
|
// .background(Color.black)
|
|
.padding(.horizontal, 0)
|
|
|
|
.onTapGesture {
|
|
Print(arrayOfText[index])
|
|
Print(index)
|
|
}
|
|
}
|
|
}
|
|
// return retView
|
|
return newView } }
|
|
|
|
struct ContentView: View {
|
|
@State var viewState = CGSize.zero
|
|
@State var pulledOut = CGSize.zero
|
|
@State var taskTitle: String = "FIRST DOGGG"
|
|
@State var curBook: String = "Matthew"
|
|
@State var selectedLine: Int64?
|
|
|
|
@State var thisScrollView: UIScrollView?
|
|
@State var scrollUpdate = false
|
|
@State var initLoad = false
|
|
|
|
// set this to scroll to area
|
|
@State var scrollId: String?
|
|
@State var scrollOffset: CGFloat?
|
|
|
|
@State var setScrollOffset: CGFloat?
|
|
@State var showOverlay: Bool = false
|
|
|
|
@State var vertSep = CGFloat(20)
|
|
|
|
@Environment(\.appDatabase) private var appDatabase
|
|
@Query(SegDenormRequest(book: "bible.mark")) private var segs: [SegDenorm]
|
|
|
|
// @State var scrollDelegate: ScrollViewHandler
|
|
// @State var scrollDelegate = ScrollViewHandler()
|
|
|
|
// @State var selectedRibbonId = Int64(UserDefaults.standard.optionalInt(forKey: "selectedRibbonId") ?? 1)
|
|
|
|
// ribbon
|
|
// @Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon]
|
|
|
|
@State var endedDrag = true
|
|
|
|
@State var readOffset = CGPoint()
|
|
@State var dragOffset = CGFloat()
|
|
|
|
@State var refresh: Bool = false
|
|
|
|
@State var refresh2: Bool = false
|
|
|
|
@State var draggedRibbon: Ribbon?
|
|
@State var isDragging = false
|
|
|
|
@State var reorder = true
|
|
|
|
@Query(RibbonRequest()) private var ribbons: [Ribbon]
|
|
@Query<SelectedRibbonRequest> var selectedRibbon: [Ribbon]
|
|
|
|
// @Query(RibbonRequest(id: Int64(UserDefaults.standard.optionalInt(forKey: "lastRibbonId") ?? 1))) private var selectedRibbon: [Ribbon]
|
|
|
|
init() {
|
|
UITableView.appearance().backgroundColor = UIColor(Color(red: 0.2, green: 0.2, blue: 0.2))
|
|
_selectedRibbon = Query(SelectedRibbonRequest())
|
|
|
|
// self._scrollDelegate = State(initialValue: ScrollViewHandler())
|
|
}
|
|
|
|
var body: some View {
|
|
// Print("rendering")
|
|
|
|
var size1 = CGFloat(11)
|
|
var size2 = CGFloat(100)
|
|
var fontSize = CGFloat(15)
|
|
var scale = 0.65
|
|
var height = CGFloat(50)
|
|
var xOffset = CGFloat(25)
|
|
|
|
var width = CGFloat(100 * 1.66 * scale)
|
|
|
|
// ForEach(ribbons) { ribbon in
|
|
// data.append(ribbon)
|
|
// }
|
|
|
|
GeometryReader { geometry in
|
|
ZStack(alignment: .top) {
|
|
VStack(alignment: .leading) {
|
|
VStack {
|
|
// ReorderableForEach($data, allowReordering: $reorder) { item, isDragged in
|
|
ForEach(ribbons) { ribbon in
|
|
RibbonCrown(ribbon: ribbon,
|
|
scrollId: $scrollId,
|
|
scrollOffset: $scrollOffset,
|
|
showOverlay: $showOverlay,
|
|
refresh: $refresh,
|
|
draggedRibbon: draggedRibbon,
|
|
isDragging: isDragging)
|
|
.onDrag {
|
|
self.draggedRibbon = ribbon
|
|
return NSItemProvider()
|
|
}
|
|
.onDrop(of: [.item],
|
|
delegate: DropViewDelegate(destinationItem: ribbon,
|
|
draggedItem: $draggedRibbon,
|
|
isDragging: $isDragging,
|
|
appDatabase: appDatabase))
|
|
.offset(x: 6, y: 6)
|
|
}
|
|
|
|
// .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
}
|
|
.frame(width: geometry.size.width, height: geometry.size.height - 100, alignment: .topLeading)
|
|
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
|
.zIndex(0)
|
|
.animation(.default, value: ribbons)
|
|
.onDrop(of: [.item],
|
|
delegate: DropViewDelegate2(isDragging: $isDragging))
|
|
|
|
// Spacer()
|
|
|
|
// ForEach(ribbons) { ribbon in
|
|
// RibbonCrown(ribbon: ribbon,
|
|
// scrollId:$scrollId,
|
|
// scrollOffset:$scrollOffset,
|
|
// showOverlay: $showOverlay,
|
|
// refresh:$refresh
|
|
// )
|
|
// // .buttonStyle(BlueButtonStyle())
|
|
// // .frame(alignment: .topLeading)
|
|
|
|
// // .background(Color(red: 0.4, green: 0.4, blue: 0.1))
|
|
// .animation(nil)
|
|
// }
|
|
}
|
|
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
|
.frame(alignment: .topLeading)
|
|
// .animation(nil)
|
|
|
|
VStack {
|
|
ScrollViewReader { proxy in
|
|
VisibilityTrackingScrollView(action: handleVisibilityChanged) {
|
|
// ScrollView {
|
|
|
|
LazyVStack {
|
|
ForEach(segs) { seg in
|
|
SegRow(seg: seg,
|
|
ribbonId: selectedRibbon[0].id!)
|
|
.id("\(seg.id)")
|
|
.offset(x: -dragOffset)
|
|
// .offset(x: pulledOut.width)
|
|
|
|
.padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
|
|
.trackVisibility(id: "\(seg.id)")
|
|
|
|
// .onChange(of: geometry.frame(in: .named("scrollView"))) { imageRect in
|
|
// Print(imageRect)
|
|
// Print(outerProxy)
|
|
// if isInView(innerRect: imageRect, isIn: outerProxy) {
|
|
// visibleIndex.insert(item)
|
|
// } else {
|
|
// visibleIndex.remove(item)
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
.background(Color(red: 0.18, green: 0.18, blue: 0.18))
|
|
}
|
|
|
|
.onAppear {
|
|
Print("APPEAR")
|
|
// Print(selectedRibbon[0])
|
|
// scrollId = "3"
|
|
// scrollOffset = 103
|
|
// refresh.toggle()
|
|
|
|
goToRibbon(selectedRibbon: selectedRibbon[0],
|
|
destRibbon: selectedRibbon[0],
|
|
scrollId: $scrollId,
|
|
scrollOffset: $scrollOffset,
|
|
refresh: $refresh,
|
|
showOverlay: $showOverlay,
|
|
appDatabase: appDatabase,
|
|
loading: true)
|
|
}
|
|
.onChange(of: refresh) { _ in
|
|
// if let target = target {
|
|
// gTracker!.visibleViews["123123"] = CGFloat(100)
|
|
// Print("ON CHANGE", gTracker!.visibleViews)
|
|
// Print("removing", gTracker!.visibleViews.removeAll())
|
|
|
|
Task {
|
|
DispatchQueue.main.async {
|
|
Print("scroll Id target: \(scrollId)")
|
|
proxy.scrollTo(scrollId!, anchor: .top)
|
|
// proxy.scrollTo(String(Int(scrollId!)! + 1))
|
|
// currentId = scrollId!
|
|
// if (currentId != scrollId!) {
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
Print(" scroll id target", scrollId)
|
|
Print(" current id ", currentId)
|
|
Print(gTracker!.sortedViewIDs)
|
|
if currentId! != scrollId! {
|
|
Print("NO MATCH")
|
|
}
|
|
|
|
// Print(" scroll offset target", scrollOffset)
|
|
Print(" current offset ", gTracker!.visibleViews[scrollId!])
|
|
var curOffset = gTracker!.visibleViews[scrollId!]
|
|
Print(" stats", gTracker!.visibleViews)
|
|
// // setScrollOffset = CGFloat(Int(currentOffset!) * -1 + Int(scrollOffset!))
|
|
if curOffset != nil {
|
|
setScrollOffset = CGFloat(Int(scrollOffset!) - Int(curOffset!))
|
|
Print("applying scroll offset \(setScrollOffset)")
|
|
// // setScrollOffset = CGFloat(Int(scrollOffset!))
|
|
// Print("setting scroll offset", setScrollOffset)
|
|
refresh2.toggle()
|
|
} else {
|
|
var adjust = (Int(scrollId!)! - Int(currentId!)!) * 200
|
|
Print("adjusting \(adjust)")
|
|
|
|
setScrollOffset = CGFloat(adjust)
|
|
refresh.toggle()
|
|
}
|
|
// // currentId = scrollId!
|
|
|
|
// DispatchQueue.main.async {
|
|
|
|
// currentOffset = scrollOffset!
|
|
// currentId = scrollId!
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in Print("introspect")
|
|
// Print("Scroll delegate offset", scrollDelegate.scrollOffset)
|
|
|
|
if setScrollOffset != nil {
|
|
// Print("Setting scroll offset in introspect", setScrollOffset)
|
|
DispatchQueue.main.async {
|
|
scrollView.contentOffset.y = scrollView.contentOffset.y + setScrollOffset!
|
|
setScrollOffset = nil
|
|
|
|
// self.showOverlay = false
|
|
withAnimation {
|
|
showOverlay = false
|
|
}
|
|
}
|
|
}
|
|
|
|
// if (thisScrollView == nil) {
|
|
// Print("init scroll")
|
|
// thisScrollView = scrollView
|
|
// scrollView.contentOffset.y = CGFloat(selectedRibbon[0].scrollOffset)
|
|
// }
|
|
|
|
Print("end introspect")
|
|
}
|
|
.listStyle(PlainListStyle())
|
|
}
|
|
.zIndex(1)
|
|
.background(Color(red: 0.2, green: 0.2, blue: 0.2))
|
|
.frame(width: geometry.size.width - 50, height: geometry.size.height / 2 - vertSep)
|
|
.offset(x: 30, y: 0)
|
|
.offset(x: pulledOut.width)
|
|
.offset(x: viewState.width, y: viewState.height)
|
|
.gesture(
|
|
DragGesture()
|
|
.onChanged { gesture in
|
|
|
|
if endedDrag {
|
|
endedDrag = false
|
|
scrollOffset = readOffset.y - 20
|
|
// _ = Print("meow")
|
|
}
|
|
// logger.error("hello222")
|
|
// NSLog("hellooo")
|
|
Print(viewState.width)
|
|
if abs(gesture.translation.width) > 20 {
|
|
viewState.width = gesture.translation.width
|
|
if gesture.translation.width < -50, pulledOut.width == CGFloat(0) {
|
|
dragOffset = gesture.translation.width + 50
|
|
}
|
|
}
|
|
// offset.y = gesture.translation.width
|
|
// logger.log("hello")
|
|
}
|
|
.onEnded { _ in
|
|
endedDrag = true
|
|
var pulledOutWidth = CGFloat(0)
|
|
if viewState.width < 0 {
|
|
pulledOutWidth = CGFloat(0)
|
|
} else if abs(viewState.width + pulledOut.width) > 30 {
|
|
pulledOutWidth = CGFloat(200)
|
|
}
|
|
|
|
withAnimation(.spring(response: 0.2)) {
|
|
pulledOut.width = pulledOutWidth
|
|
viewState = .zero
|
|
dragOffset = .zero
|
|
}
|
|
}
|
|
)
|
|
|
|
Text("separator").foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
.gesture(
|
|
DragGesture()
|
|
.onChanged { gesture in
|
|
|
|
vertSep = vertSep - gesture.translation.height
|
|
Print(gesture.translation.width)
|
|
Print(gesture.translation.height)
|
|
|
|
Print("drag")
|
|
|
|
// if (endedDrag) {
|
|
// endedDrag = false
|
|
// scrollOffset = readOffset.y - 20
|
|
// // _ = Print("meow")
|
|
// }
|
|
//// logger.error("hello222")
|
|
//// NSLog("hellooo")
|
|
// Print(viewState.width)
|
|
// if (abs(gesture.translation.width) > 20) {
|
|
// viewState.width = gesture.translation.width
|
|
// }
|
|
////offset.y = gesture.translation.width
|
|
//// logger.log("hello")
|
|
}
|
|
// .onEnded { _ in
|
|
// endedDrag = true
|
|
// var pulledOutWidth = CGFloat(0)
|
|
// if (viewState.width < 0) {
|
|
// pulledOutWidth = CGFloat(0)
|
|
// }
|
|
// else if abs(viewState.width + pulledOut.width ) > 30 {
|
|
// pulledOutWidth = CGFloat(200)
|
|
// }
|
|
|
|
// withAnimation(.spring(response: 0.2)) {
|
|
// pulledOut.width = pulledOutWidth
|
|
// viewState = .zero
|
|
// }
|
|
// }
|
|
)
|
|
|
|
ScrollViewReader { _ in
|
|
VisibilityTrackingScrollView(action: handleVisibilityChanged2) {
|
|
// ScrollView {
|
|
|
|
LazyVStack {
|
|
ForEach(segs) { seg in
|
|
SegRow(seg: seg,
|
|
ribbonId: selectedRibbon[0].id!)
|
|
.id("\(seg.id)")
|
|
.padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
|
|
.trackVisibility(id: "\(seg.id)")
|
|
|
|
// .onChange(of: geometry.frame(in: .named("scrollView"))) { imageRect in
|
|
// Print(imageRect)
|
|
// Print(outerProxy)
|
|
// if isInView(innerRect: imageRect, isIn: outerProxy) {
|
|
// visibleIndex.insert(item)
|
|
// } else {
|
|
// visibleIndex.remove(item)
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
.background(Color(red: 0.18, green: 0.18, blue: 0.18))
|
|
}
|
|
|
|
.onAppear {
|
|
Print("APPEAR")
|
|
// Print(selectedRibbon[0])
|
|
// scrollId = "3"
|
|
// scrollOffset = 103
|
|
// refresh.toggle()
|
|
|
|
// goToRibbon(selectedRibbon: selectedRibbon[0],
|
|
// destRibbon: selectedRibbon[0],
|
|
// scrollId: $scrollId,
|
|
// scrollOffset: $scrollOffset,
|
|
// refresh: $refresh,
|
|
// showOverlay: $showOverlay,
|
|
// appDatabase: appDatabase,
|
|
// loading: true)
|
|
}
|
|
// .onChange(of: refresh) { target in
|
|
// //if let target = target {
|
|
// //gTracker!.visibleViews["123123"] = CGFloat(100)
|
|
// // Print("ON CHANGE", gTracker!.visibleViews)
|
|
// // Print("removing", gTracker!.visibleViews.removeAll())
|
|
|
|
// Task {
|
|
// DispatchQueue.main.async {
|
|
|
|
// Print("scroll Id target: \(scrollId)")
|
|
|
|
// proxy.scrollTo(scrollId! , anchor: .top)
|
|
|
|
// // proxy.scrollTo(String(Int(scrollId!)! + 1))
|
|
|
|
// // currentId = scrollId!
|
|
|
|
// // if (currentId != scrollId!) {
|
|
|
|
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
|
|
// Print(" scroll id target", scrollId)
|
|
// Print(" current id ", currentId)
|
|
// Print(gTracker!.sortedViewIDs)
|
|
// if (currentId! != scrollId!) {
|
|
// Print("NO MATCH")
|
|
// }
|
|
|
|
// // Print(" scroll offset target", scrollOffset)
|
|
// Print(" current offset ", gTracker!.visibleViews[scrollId!])
|
|
// var curOffset = gTracker!.visibleViews[scrollId!]
|
|
// Print(" stats", gTracker!.visibleViews)
|
|
// // // setScrollOffset = CGFloat(Int(currentOffset!) * -1 + Int(scrollOffset!))
|
|
// if (curOffset != nil) {
|
|
// setScrollOffset = CGFloat(Int(scrollOffset!) - Int(curOffset!))
|
|
// Print("applying scroll offset \(setScrollOffset)")
|
|
// // // setScrollOffset = CGFloat(Int(scrollOffset!))
|
|
// // Print("setting scroll offset", setScrollOffset)
|
|
// refresh2.toggle()
|
|
// } else {
|
|
// var adjust = (Int(scrollId!)! - Int(currentId!)!) * 200
|
|
// Print("adjusting \(adjust)")
|
|
|
|
// setScrollOffset = CGFloat(adjust)
|
|
// refresh.toggle()
|
|
|
|
// }
|
|
// // // currentId = scrollId!
|
|
|
|
// // DispatchQueue.main.async {
|
|
|
|
// // currentOffset = scrollOffset!
|
|
// // currentId = scrollId!
|
|
// // }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// .introspectScrollView { scrollView in
|
|
// Print("introspect")
|
|
// // scrollView.delegate = scrollDelegate
|
|
// //Print("Scroll delegate offset", scrollDelegate.scrollOffset)
|
|
|
|
// if (setScrollOffset != nil) {
|
|
// // Print("Setting scroll offset in introspect", setScrollOffset)
|
|
// DispatchQueue.main.async {
|
|
// scrollView.contentOffset.y = scrollView.contentOffset.y + setScrollOffset!
|
|
// setScrollOffset = nil
|
|
// withAnimation {
|
|
// showOverlay = false
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// // if (thisScrollView == nil) {
|
|
// // Print("init scroll")
|
|
// // thisScrollView = scrollView
|
|
// // scrollView.contentOffset.y = CGFloat(selectedRibbon[0].scrollOffset)
|
|
// // }
|
|
|
|
// Print("end instrospect")
|
|
// }
|
|
.listStyle(PlainListStyle())
|
|
}
|
|
.zIndex(1)
|
|
.background(Color(red: 0.2, green: 0.2, blue: 0.2))
|
|
.frame(width: geometry.size.width - 50)
|
|
.offset(x: 30, y: 0)
|
|
.offset(x: pulledOut.width)
|
|
.offset(x: viewState.width, y: viewState.height)
|
|
.gesture(
|
|
DragGesture()
|
|
.onChanged { gesture in
|
|
|
|
if endedDrag {
|
|
endedDrag = false
|
|
scrollOffset = readOffset.y - 20
|
|
// _ = Print("meow")
|
|
}
|
|
// logger.error("hello222")
|
|
// NSLog("hellooo")
|
|
Print(viewState.width)
|
|
if abs(gesture.translation.width) > 20 {
|
|
viewState.width = gesture.translation.width
|
|
}
|
|
// offset.y = gesture.translation.width
|
|
// logger.log("hello")
|
|
}
|
|
.onEnded { _ in
|
|
endedDrag = true
|
|
var pulledOutWidth = CGFloat(0)
|
|
if viewState.width < 0 {
|
|
pulledOutWidth = CGFloat(0)
|
|
} else if abs(viewState.width + pulledOut.width) > 30 {
|
|
pulledOutWidth = CGFloat(200)
|
|
}
|
|
|
|
withAnimation(.spring(response: 0.2)) {
|
|
pulledOut.width = pulledOutWidth
|
|
viewState = .zero
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
if showOverlay {
|
|
Rectangle()
|
|
.frame(width: geometry.size.width - 50, height: geometry.size.height + 200)
|
|
.background(.ultraThinMaterial)
|
|
|
|
// .blur(radius: 0.8)
|
|
.offset(x: 30, y: -100)
|
|
.opacity(0.98)
|
|
.transition(.opacity)
|
|
|
|
// .frame(width: geometry.size.width - 50)
|
|
.offset(x: pulledOut.width)
|
|
.offset(x: viewState.width, y: viewState.height)
|
|
.zIndex(2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func handleVisibilityChanged2(_: String, change _: VisibilityChange, tracker _: VisibilityTracker<String>) {}
|
|
|
|
func handleVisibilityChanged(_: String, change _: VisibilityChange, tracker: VisibilityTracker<String>) {
|
|
// var printRate: Int64 = 10
|
|
gTracker = tracker
|
|
|
|
// @Environment(\.appDatabase) var appDatabase
|
|
// switch change {
|
|
// case .shown: print("\(id) shown")
|
|
// case .hidden: print("\(id) hidden")
|
|
// }
|
|
// if (printCount % printRate == 0) {
|
|
// print("VISIBILITY CHANGED STARTED")
|
|
// print(tracker.visibleViews)
|
|
// print(tracker.sortedViewIDs)
|
|
// print("VISIBILITY CHANGED ENDED")
|
|
// }
|
|
// printCount += 1
|
|
|
|
// if (currentId != nil) {
|
|
// currentOffset = tracker.visibleViews[currentId!]!
|
|
// }
|
|
|
|
let visibleViews2 = Array(tracker.visibleViews.keys)
|
|
if visibleViews2.count == 0 {
|
|
return
|
|
}
|
|
|
|
// currentId = tracker.sortedViewIDs[tracker.sortedViewIDs.count - 1]
|
|
currentId = tracker.sortedViewIDs[0]
|
|
currentOffset = tracker.visibleViews[currentId!]!
|
|
// if (Int(currentOffset!) != -1 && Int(currentOffset!) < 0) {
|
|
// if (tracker.sortedViewIDs.count > 1) {
|
|
// currentId = tracker.sortedViewIDs[1]
|
|
// currentOffset = tracker.visibleViews[currentId!]!
|
|
// }
|
|
// }
|
|
// if (currentId != nil) {
|
|
// // if (printCount % printRate == 0) {
|
|
// // print(printCount)
|
|
// // print("cat current ID:", currentId)
|
|
// // }
|
|
// // print("got here")
|
|
// currentOffset = tracker.visibleViews[currentId!]!
|
|
// }
|
|
}
|
|
}
|
|
|
|
private let itemFormatter: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.dateStyle = .short
|
|
formatter.timeStyle = .medium
|
|
return formatter
|
|
}()
|
|
|
|
struct DropViewDelegate2: DropDelegate {
|
|
@Binding var isDragging: Bool
|
|
|
|
func dropUpdated(info _: DropInfo) -> DropProposal? {
|
|
return DropProposal(operation: .move)
|
|
}
|
|
|
|
func performDrop(info _: DropInfo) -> Bool {
|
|
isDragging = false
|
|
return true
|
|
}
|
|
|
|
func dropEntered(info _: DropInfo) {
|
|
isDragging = true
|
|
print("SECOND DROPPPOOO")
|
|
}
|
|
}
|
|
|
|
struct DropViewDelegate: DropDelegate {
|
|
let destinationItem: Ribbon
|
|
// @Binding var colors: [Color]
|
|
@Binding var draggedItem: Ribbon?
|
|
@Binding var isDragging: Bool
|
|
let appDatabase: AppDatabase
|
|
|
|
func dropUpdated(info _: DropInfo) -> DropProposal? {
|
|
return DropProposal(operation: .move)
|
|
}
|
|
|
|
func dropExited(info _: DropInfo) {
|
|
print("EXITED")
|
|
isDragging = false
|
|
}
|
|
|
|
func dropEntered(info _: DropInfo) {
|
|
Task {
|
|
isDragging = true
|
|
if draggedItem == nil {
|
|
return
|
|
}
|
|
|
|
if disableDrop {
|
|
return
|
|
}
|
|
|
|
var newRibbon = draggedItem!
|
|
var newDest = destinationItem
|
|
|
|
var oldPos = draggedItem!.pos
|
|
var newPos = destinationItem.pos
|
|
|
|
print("dragged item")
|
|
print(draggedItem)
|
|
print("dest item")
|
|
print(destinationItem)
|
|
|
|
if draggedItem!.id! == destinationItem.id! {
|
|
return
|
|
}
|
|
|
|
newRibbon.pos = destinationItem.pos
|
|
|
|
_ = try await appDatabase.updateRibbonPosition(&newRibbon, oldPos, newPos)
|
|
disableDrop = true
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
disableDrop = false
|
|
}
|
|
draggedItem!.pos = newPos
|
|
|
|
// draggedItem = nil
|
|
}
|
|
}
|
|
|
|
func performDrop(info _: DropInfo) -> Bool {
|
|
print("PERFORMED DROPPPP")
|
|
draggedItem = nil
|
|
isDragging = false
|
|
return true
|
|
}
|
|
}
|
|
|
|
struct ContentView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
ContentView()
|
|
|
|
ContentView().environment(\.appDatabase, .random())
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
func Print(_ vars: Any...) -> some View {
|
|
for v in vars {
|
|
print(v)
|
|
}
|
|
return EmptyView()
|
|
}
|
|
}
|