952 lines
38 KiB
Swift
952 lines
38 KiB
Swift
//
|
|
// ContentView.swift
|
|
// gloss
|
|
//
|
|
// Created by Saint on 10/23/22.
|
|
//
|
|
|
|
import SwiftUI
|
|
import GRDB
|
|
import GRDBQuery
|
|
import Introspect
|
|
import os
|
|
import SwiftUIReorderableForEach
|
|
|
|
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "network")
|
|
|
|
var currentId : String?
|
|
var currentOffset : CGFloat?
|
|
|
|
var gTracker: VisibilityTracker<String>?
|
|
var printCount: Int64 = 0
|
|
|
|
// var curBook = "John"
|
|
|
|
extension UserDefaults {
|
|
public func optionalInt(forKey defaultName: String) -> Int? {
|
|
let defaults = self
|
|
if let value = defaults.value(forKey: defaultName) {
|
|
return value as? Int
|
|
}
|
|
return nil
|
|
}
|
|
|
|
public func optionalBool(forKey defaultName: String) -> Bool? {
|
|
let defaults = self
|
|
if let value = defaults.value(forKey: defaultName) {
|
|
return value as? Bool
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
struct BlueButtonStyle: ButtonStyle {
|
|
func makeBody(configuration: Self.Configuration) -> some View {
|
|
configuration.label
|
|
.font(.headline)
|
|
.frame(width: 100)
|
|
.contentShape(Rectangle())
|
|
.foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.black)
|
|
.background(configuration.isPressed ? Color.purple.opacity(0.5) : Color.purple)
|
|
.listRowBackground(configuration.isPressed ? Color.blue.opacity(0.5) : Color.black)
|
|
}
|
|
}
|
|
|
|
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
|
|
// }
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
struct RibbonCrown : View {
|
|
var ribbon: Ribbon
|
|
@Binding var scrollId : String?
|
|
@Binding var scrollOffset : CGFloat?
|
|
@Binding var showOverlay : Bool
|
|
@Binding var refresh : 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)))
|
|
|
|
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)
|
|
.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)))
|
|
|
|
}
|
|
|
|
// Text(ribbon.title)
|
|
// .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
// // // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
|
|
// // .foregroundColor(.white))
|
|
// // .foregroundColor(.black)
|
|
// .frame(minWidth: CGFloat(75), maxWidth: CGFloat(75), minHeight: height, maxHeight: height, alignment: .center)
|
|
// // .background(.red)
|
|
// // .background(.yellow)
|
|
// .multilineTextAlignment(.center)
|
|
// // .minimumScaleFactor(0.5)
|
|
// .padding([.top, .bottom], 10)
|
|
// .font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(10)))
|
|
|
|
// .overlay( 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))))
|
|
|
|
// .offset(x: xOffset)
|
|
// .onTapGesture {
|
|
// Print("TAP")
|
|
// // selectedLine = seg.id
|
|
// // Print(selectedLine)
|
|
// }
|
|
|
|
|
|
// ForEach(sr) { selectedRibbon in
|
|
// let ribbonString = String(sr[0].id!) + " " + String(ribbon.id!) + " " + String(ribbon.scrollOffset) + " " + ribbon.scrollId
|
|
// Button(ribbonString,
|
|
// action: {
|
|
// Task {
|
|
// goToRibbon(selectedRibbon: sr[0],
|
|
// destRibbon: ribbon,
|
|
// scrollId: $scrollId,
|
|
// scrollOffset: $scrollOffset,
|
|
// refresh: $refresh,
|
|
// showOverlay: $showOverlay,
|
|
// appDatabase: appDatabase,
|
|
// loading: false)
|
|
// }
|
|
// }
|
|
|
|
// )
|
|
// .buttonStyle(BlueButtonStyle())
|
|
}
|
|
}
|
|
|
|
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()
|
|
segSplit.enumerated().forEach({ (index, item) in
|
|
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("")
|
|
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({ (index, 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)
|
|
// .frame(maxWidth: .infinity, alignment: .leading)
|
|
// .contentShape(Rectangle())
|
|
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
.font(Font.custom("AveriaSerifLibre-Regular", size: 20))
|
|
// .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)
|
|
//.onTapGesture {
|
|
// selectedLine = seg.id
|
|
//Print(selectedLine)
|
|
//}
|
|
|
|
// .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)
|
|
//}
|
|
})
|
|
// }
|
|
return retView
|
|
}
|
|
}
|
|
|
|
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 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
|
|
)
|
|
.onDrag {
|
|
self.draggedRibbon = ribbon
|
|
return NSItemProvider()
|
|
}
|
|
.onDrop(of: [.text],
|
|
delegate: DropViewDelegate(destinationItem: ribbon, draggedItem: $draggedRibbon, appDatabase: appDatabase)
|
|
)
|
|
}
|
|
|
|
|
|
// .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)
|
|
|
|
// 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) { 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 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("DRAG")
|
|
.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 { proxy 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(_ id: String, change: VisibilityChange, tracker: VisibilityTracker<String>) {
|
|
}
|
|
|
|
func handleVisibilityChanged(_ id: 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 DropViewDelegate: DropDelegate {
|
|
|
|
let destinationItem: Ribbon
|
|
// @Binding var colors: [Color]
|
|
@Binding var draggedItem: Ribbon?
|
|
let appDatabase: AppDatabase
|
|
|
|
func dropUpdated(info: DropInfo) -> DropProposal? {
|
|
return DropProposal(operation: .move)
|
|
}
|
|
|
|
func dropEntered(info: DropInfo) {
|
|
|
|
Task {
|
|
|
|
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 )
|
|
|
|
}
|
|
}
|
|
|
|
func performDrop(info: DropInfo) -> Bool {
|
|
draggedItem = nil
|
|
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()
|
|
}
|
|
}
|