Compare commits

..

No commits in common. "09ffa5f8e25af7f1b77c3bfaeefbb0d86157d7ec" and "2c9da90662fff4411cb6676733fdcfdb24c964cf" have entirely different histories.

27 changed files with 681 additions and 2727 deletions

View File

@ -1,2 +0,0 @@
*.json
*.xcodeproj/*

View File

@ -1,55 +0,0 @@
//
// BackButton.swift
// gloss
//
// Created by Saint on 5/27/24.
//
import Foundation
import SwiftUI
struct BackArrow: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let width = rect.size.width
let height = rect.size.height
path.move(to: CGPoint(x: 0.83333*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.45833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.closeSubpath()
return path
}
}

View File

@ -1,52 +0,0 @@
//
// BookmarkIcon.swift
// gloss
//
// Created by Saint on 6/4/24.
//
import Foundation
import SwiftUI
struct BookmarkIcon: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let width = rect.size.width
let height = rect.size.height
path.move(to: CGPoint(x: 0.75*width, y: 0.08333*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.08333*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.16667*height))
path.addLine(to: CGPoint(x: 0.74998*width, y: 0.16667*height))
path.addLine(to: CGPoint(x: 0.74998*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.66666*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.66666*width, y: 0.75*height))
path.addLine(to: CGPoint(x: 0.58332*width, y: 0.75*height))
path.addLine(to: CGPoint(x: 0.58332*width, y: 0.66667*height))
path.addLine(to: CGPoint(x: 0.41666*width, y: 0.66667*height))
path.addLine(to: CGPoint(x: 0.41666*width, y: 0.75*height))
path.addLine(to: CGPoint(x: 0.33332*width, y: 0.75*height))
path.addLine(to: CGPoint(x: 0.33332*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.24999*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.24999*width, y: 0.08334*height))
path.addLine(to: CGPoint(x: 0.16666*width, y: 0.08334*height))
path.addLine(to: CGPoint(x: 0.16666*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.24999*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.24999*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.33332*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.33332*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.41666*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.41666*width, y: 0.75*height))
path.addLine(to: CGPoint(x: 0.58332*width, y: 0.75*height))
path.addLine(to: CGPoint(x: 0.58332*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.66666*width, y: 0.83333*height))
path.addLine(to: CGPoint(x: 0.66666*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.74998*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.74998*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.83331*width, y: 0.91667*height))
path.addLine(to: CGPoint(x: 0.83331*width, y: 0.08334*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.08334*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.08333*height))
path.closeSubpath()
return path
}
}

File diff suppressed because it is too large Load Diff

216
Fenestra.swift Normal file
View File

@ -0,0 +1,216 @@
//
// Fenestra.swift
// gloss
//
// Created by Saint on 5/20/24.
//
import Foundation
import SwiftUI
import WrappingHStack
struct SegRow: View {
var seg: SegDenorm
var ribbonId: Int64
@State var highlights = Set<Int>()
var body: some View {
var segSplit = seg.body.components(separatedBy: ";;")
let decoder = JSONDecoder()
var retView = WrappingHStack(alignment: .leading, horizontalSpacing: 0) {
ForEach(0 ..< segSplit.count, id: \.self) { segIndex in
let verse = try! decoder.decode(Verse.self, from: segSplit[segIndex].data(using: .utf8)!)
let arrayOfText = verse.body.components(separatedBy: " ")
let lineHeight = CGFloat(30)
let fontSize = CGFloat(20)
let highlightColor = "470000"
ForEach(0 ..< arrayOfText.count, id: \.self) { index in
HStack(spacing: 0) {
if index == 0 {
Text("")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
VStack(spacing: 0) {
ZStack {
Text(" ")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
Text(String(verse.verse))
.font(Font.custom("AveriaSerifLibre-Regular", size: 10))
.padding(.horizontal, 0)
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
}
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
}
}
Text(arrayOfText[index])
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.padding(.horizontal, 1.5) // intra word spacing
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
.foregroundColor(Color.white)
.onTapGesture {
Print(arrayOfText[index])
Print(verse.verse)
if self.highlights.contains(verse.verse) {
self.highlights.remove(verse.verse)
} else {
self.highlights.insert(verse.verse)
}
}
}
.frame(height: 16) // intra line spacing
.padding(.vertical, 0)
}
}
}
return retView
}
}
// struct Fenestra: View {
// @State var segs: [SegDenorm]
// @State var selectedRibbon: [Ribbon]
// @State var dragOffset = CGFloat()
// @State var refresh: Bool = false
// @State var refresh2: Bool = false
// // var handleVisibilityChanged: (String, VisibilityChange, VisibilityTracker<String>) -> Void
// var body: some View {
// ScrollViewReader { proxy in
// VisibilityTrackingScrollView(action: handleVisibilityChanged) {
// LazyVStack {
// ForEach(segs) { seg in
// SegRow(seg: seg,
// ribbonId: selectedRibbon[0].id!)
// .id("\(seg.id)")
// .offset(x: -dragOffset)
// .padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
// .trackVisibility(id: "\(seg.id)")
// }
// }
// .background(Color(red: 0.18, green: 0.18, blue: 0.18))
// }
// .onAppear {
// Print("APPEAR")
// goToRibbon(selectedRibbon: selectedRibbon[0],
// destRibbon: selectedRibbon[0],
// scrollId: $scrollId,
// scrollOffset: $scrollOffset,
// refresh: $refresh,
// showOverlay: $showOverlay,
// appDatabase: appDatabase,
// loading: true)
// }
// .onChange(of: refresh) { _ in
// Task {
// DispatchQueue.main.async {
// Print("scroll Id target: \(scrollId)")
// proxy.scrollTo(scrollId!, anchor: .top)
// DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// Print(" scroll id target", scrollId)
// Print(" current id ", currentId)
// Print(gTracker!.sortedViewIDs)
// if currentId! != scrollId! {
// Print("NO MATCH")
// }
// Print(" current offset ", gTracker!.visibleViews[scrollId!])
// var curOffset = gTracker!.visibleViews[scrollId!]
// Print(" stats", gTracker!.visibleViews)
// if curOffset != nil {
// setScrollOffset = CGFloat(Int(scrollOffset!) - Int(curOffset!))
// Print("applying scroll offset \(setScrollOffset)")
// refresh2.toggle()
// } else {
// var adjust = (Int(scrollId!)! - Int(currentId!)!) * 200
// Print("adjusting \(adjust)")
// setScrollOffset = CGFloat(adjust)
// refresh.toggle()
// }
// }
// }
// }
// }
// .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in Print("introspect")
// if setScrollOffset != nil {
// DispatchQueue.main.async {
// scrollView.contentOffset.y = scrollView.contentOffset.y + setScrollOffset!
// setScrollOffset = nil
// withAnimation {
// showOverlay = false
// }
// }
// }
// }
// .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(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
// }
// }
// }
// .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
// }
// }
// )
// }
// func handleVisibilityChanged(_: String, change _: VisibilityChange, tracker: VisibilityTracker<String>) {
// // var printRate: Int64 = 10
// gTracker = tracker
// 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!]!
// }
// }

View File

@ -1,56 +0,0 @@
//
// ForwardArrow.swift
// gloss
//
// Created by Saint on 5/27/24.
//
import Foundation
import SwiftUI
struct ForwardArrow: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let width = rect.size.width
let height = rect.size.height
path.move(to: CGPoint(x: 0.16667*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.45833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.closeSubpath()
return path
}
}

View File

@ -1,116 +0,0 @@
import GRDB
import GRDBQuery
import Foundation
import SwiftUI
struct NaviBar: View {
@ObservedObject var paneConnector: PaneConnector
@Query(RibbonRequest(dir: .prev, groupId: 1)) private var backRibbon: [Ribbon]
@Query(RibbonRequest(dir: .next, groupId: 1)) private var nextRibbon: [Ribbon]
@Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon]
@Environment(\.appDatabase) private var appDatabase
var body: some View {
var iconSize = CGFloat(25)
VStack {
HStack(spacing: 30) {
BackArrow()
.frame(width: iconSize, height: iconSize)
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
.if(paneConnector.hasMoved) { $0.foregroundColor(Color.black) }
.if(!paneConnector.hasMoved) { $0.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))) }
.onTapGesture {
Task {
var br = backRibbon
var sr = selectedRibbon
do {
if paneConnector.hasMoved {
print("has moved")
let updatedRibbon = try await createUndoState(selectedRibbon: sr[0],
appDatabase: appDatabase,
paneConnector: paneConnector)
goToRibbon(selectedRibbon: sr[0],
destRibbon: sr[0],
appDatabase: appDatabase,
paneConnector: paneConnector,
loading: false)
} else {
if backRibbon.count == 0 {
return
}
try await appDatabase.undoRibbon(&sr[0])
goToRibbon(selectedRibbon: sr[0],
destRibbon: br[0],
appDatabase: appDatabase,
paneConnector: paneConnector,
loading: false)
}
} catch {
print("Back Arrow Error info: \(error)")
}
}
}
BookmarkIcon()
.frame(width: iconSize, height: iconSize)
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
ForwardArrow()
.frame(width: iconSize, height: iconSize)
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
.onTapGesture {
if nextRibbon.count == 0 {
return
}
Task {
var sr = selectedRibbon[0]
var nr = nextRibbon[0]
try await appDatabase.redoRibbon(&sr)
goToRibbon(selectedRibbon: sr,
destRibbon: nr,
appDatabase: appDatabase,
paneConnector: paneConnector,
loading: false)
}
}
// Rectangle()
// .fill(Color(red: 0.1, green: 0.1, blue: 0.1))
// .frame(width: iconSize, height: iconSize)
// BackArrow()
// .frame(width: iconSize, height: iconSize)
// .background(Color(red: 0.1, green: 0.1, blue: 0.1))
// BookmarkIcon()
// .frame(width: iconSize, height: iconSize)
// .background(Color(red: 0.1, green: 0.1, blue: 0.1))
// .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
// ForwardArrow()
// .frame(width: iconSize, height: iconSize)
// .background(Color(red: 0.1, green: 0.1, blue: 0.1))
// .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
}
.cornerRadius(5)
}
}
}

View File

@ -1,287 +0,0 @@
//
// Fenestra.swift
// gloss
//
// Created by Saint on 5/20/24.
//
import GRDB
import GRDBQuery
import Foundation
import SwiftUI
import WrappingHStack
struct SegRow: View {
var seg: SegDenorm
var ribbonId: Int64
var width: CGFloat
@State var highlights = Set<Int>()
@ObservedObject var showTitle: ShowTitle
let intraWordSpacing = CGFloat(1.6)
var body: some View {
var segSplit = seg.body.components(separatedBy: ";;")
let decoder = JSONDecoder()
var retView = VStack {
Text("\(seg.chap)")
.frame(width: width)
.padding(.vertical, 10)
.if(showTitle.chapVisible) { $0.foregroundColor(mainTextColor) }
.if(!showTitle.chapVisible) { $0.foregroundColor(secondBackgroundColor) }
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.background(secondBackgroundColor)
// .background(mainBackgroundColor)
.onTapGesture {
showTitle.chapVisible.toggle()
}
WrappingHStack(alignment: .leading, horizontalSpacing: 0) {
ForEach(0 ..< segSplit.count, id: \.self) { segIndex in
let verse = try! decoder.decode(Verse.self, from: segSplit[segIndex].data(using: .utf8)!)
let arrayOfText = verse.body.components(separatedBy: " ")
let lineHeight = CGFloat(30)
let fontSize = CGFloat(18)
let highlightColor = "470000"
ForEach(0 ..< arrayOfText.count, id: \.self) { index in
HStack(spacing: 0) {
if index == 0 {
Text("")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
VStack(spacing: 0) {
ZStack {
Text(" ")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
Text(String(verse.verse))
.font(Font.custom("AveriaSerifLibre-Regular", size: 10))
.padding(.horizontal, 0)
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
}
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
}
}
Text(arrayOfText[index])
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.padding(.horizontal, intraWordSpacing) // intra word spacing
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
.foregroundColor(Color.white)
.onTapGesture {
Print(arrayOfText[index])
Print(verse.verse)
if self.highlights.contains(verse.verse) {
self.highlights.remove(verse.verse)
} else {
self.highlights.insert(verse.verse)
}
}
}
.frame(height: 16) // intra line spacing
.padding(.vertical, 0)
}
}
}
}
return retView
}
}
class ShowTitle: NSObject, ObservableObject {
@Published var chapVisible = false
}
struct Pane: View {
@ObservedObject var paneConnector: PaneConnector
@StateObject var showTitle = ShowTitle()
// @State var chapVisible = false
@State var selectedRibbon: [Ribbon]
@State var width: CGFloat
@State var height: CGFloat
var dragOffset = CGFloat()
@State var refresh: Bool = false
@Query(SegDenormRequest(book: "bible.mark")) private var segs: [SegDenorm]
@Environment(\.appDatabase) private var appDatabase
var body: some View {
var adjustedHeight = height - paneConnector.vertSep
ZStack {
ScrollViewReader { proxy in
VisibilityTrackingScrollView(action: handleVisibilityChanged) {
LazyVStack {
ForEach(segs) { seg in
SegRow(seg: seg,
ribbonId: selectedRibbon[0].id!,
width: width,
showTitle: showTitle
)
.id("\(seg.id)")
.offset(x: -dragOffset)
.padding(EdgeInsets(top: 10, leading: 20, bottom: 20, trailing: 20))
.trackVisibility(id: "\(seg.id)")
}
}
.background(Color(red: 0.18, green: 0.18, blue: 0.18))
}
.onAppear {
goToRibbon(selectedRibbon: selectedRibbon[0],
destRibbon: selectedRibbon[0],
appDatabase: appDatabase,
paneConnector: paneConnector,
loading: true)
}
.onChange(of: paneConnector.refresh) { _ in
print("inside change")
print("on change")
Task {
DispatchQueue.main.async {
if paneConnector.visibilityTracker == nil {
return
}
let gTracker = paneConnector.visibilityTracker!
Print("scroll Id target: \(paneConnector.scrollId)")
proxy.scrollTo(paneConnector.scrollId, anchor: .top)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Print(" scroll id target", paneConnector.scrollId)
Print(" current id ", paneConnector.currentId)
Print(gTracker.sortedViewIDs)
if paneConnector.currentId != paneConnector.scrollId {
Print("NO MATCH")
}
Print(" current offset ", gTracker.visibleViews[paneConnector.scrollId])
var curOffset = gTracker.visibleViews[paneConnector.scrollId]
Print(" stats", gTracker.visibleViews)
if curOffset != nil {
paneConnector.setScrollOffset = CGFloat(Int(paneConnector.scrollOffset) - Int(curOffset!))
// setScrollOffset = CGFloat(Int(paneConnector.scrollOffset) - Int(curOffset!))
// setScrollOffset = CGFloat(Int(paneConnector.scrollOffset) - Int(curOffset!))
Print("applying scroll offset \(paneConnector.setScrollOffset)")
// paneConnector = paneConnector.copy() as! PaneConnector
self.refresh.toggle()
} else {
var adjust = (Int(paneConnector.scrollId)! - Int(paneConnector.currentId)!) * 200
Print("adjusting \(adjust)")
paneConnector.setScrollOffset = CGFloat(adjust)
refresh.toggle()
}
}
}
}
}
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in
Print("introspect")
// Weird hack for reactivity
if self.refresh {
let reactive = self.refresh
}
// if self.paneConnector != nil {
// let reactive = self.paneConnector
// }
DispatchQueue.main.async {
if paneConnector.setScrollOffset != nil {
scrollView.contentOffset.y = scrollView.contentOffset.y + paneConnector.setScrollOffset!
paneConnector.setScrollOffset = nil
withAnimation(.easeIn(duration: 0.2)) {
paneConnector.showOverlay = false
self.refresh.toggle()
}
}
}
Print("end introspect")
}
.listStyle(PlainListStyle())
}
.zIndex(1)
.background(Color(red: 0.2, green: 0.2, blue: 0.2))
.frame(width: width, height: adjustedHeight)
if self.paneConnector.showOverlay {
Rectangle()
// .frame(width: width, height: height + 200)
.background(.ultraThinMaterial)
.opacity(0.98)
.offset(y: -50)
.frame(width: width, height: adjustedHeight + 100)
// .blur(radius: 0.8)
// .opacity(1)
.transition(.opacity)
// .frame(width: geometry.size.width - 50)
// .offset(x: pulledOut.width)
// .offset(x: viewState.width, y: viewState.height)
.zIndex(2)
}
}
.frame(width: width, height: adjustedHeight)
}
func handleVisibilityChanged(_: String, change _: VisibilityChange, tracker: VisibilityTracker<String>) {
// var printRate: Int64 = 10
// gTracker = tracker
self.paneConnector.visibilityTracker = tracker
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 self.paneConnector.currentId != tracker.sortedViewIDs[0] {
self.paneConnector.currentId = tracker.sortedViewIDs[0]
}
self.paneConnector.currentOffset = tracker.visibleViews[currentId!]!
if self.paneConnector.currentId == self.paneConnector.scrollId
&& abs(self.paneConnector.currentOffset - self.paneConnector.scrollOffset) < 10 {
if self.paneConnector.hasMoved {
self.paneConnector.hasMoved = false
}
} else {
if !self.paneConnector.hasMoved {
self.paneConnector.hasMoved = true
}
}
}
}

View File

View File

@ -2,19 +2,30 @@ import Combine
import GRDB import GRDB
import GRDBQuery import GRDBQuery
/// A player request can be used with the `@Query` property wrapper in order to
/// feed a view with a list of players.
///
/// For example:
///
/// struct MyView: View {
/// @Query(RibbonRequest(ordering: .byName)) private var players: [Ribbon]
///
/// var body: some View {
/// List(players) { player in ... )
/// }
/// }
var idColumn = Column("id") var idColumn = Column("id")
struct RibbonRequest: Queryable { struct RibbonRequest: Queryable {
enum UndoDir { // enum Ordering {
case prev // case byScore
case next // case byName
case current // }
}
/// The ordering used by the player request. /// The ordering used by the player request.
// var ordering: Ordering // var ordering: Ordering
var id: Int64! var id: Int64!
var dir: UndoDir?
var groupId: Int?
// MARK: - Queryable Implementation // MARK: - Queryable Implementation
@ -38,108 +49,12 @@ struct RibbonRequest: Queryable {
// This method is not required by Queryable, but it makes it easier // This method is not required by Queryable, but it makes it easier
func fetchValue(_ db: Database) throws -> [Ribbon] { func fetchValue(_ db: Database) throws -> [Ribbon] {
if (id == nil) {
var ret: [Ribbon] return try Ribbon.order(Column("pos")).fetchAll(db)
var sql: String } else {
return try Ribbon.filter(idColumn == id).fetchAll(db)
// this has to be a global variable
let totalLevels = 3
do {
if dir != nil && groupId != nil {
sql = """
SELECT * FROM Ribbon \
WHERE groupId = ?
LIMIT 1
"""
ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId])
let currentLevel = ret[0].currentLevel
let minLevel = ret[0].minLevel
let maxLevel = ret[0].maxLevel
if dir == .current {
sql = """
SELECT * FROM Ribbon \
WHERE groupId = ?
AND undoLevel = ?
LIMIT 1
"""
ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId, currentLevel])
return ret
}
var newCurrentLevel = (currentLevel - 1) %% totalLevels
// probably need more error checking to check
// if current level gets into an error state
// between minLevel and maxLevel somehow but there
// are probably a bunch of edge cases casue of the
// mod stuff
if dir == .prev {
print("calling ribbon request prev")
// no back undo steps left
if currentLevel == minLevel {
return []
}
} else if dir == .next {
// no forward redo steps left
if currentLevel == maxLevel {
return []
} else {
newCurrentLevel = (currentLevel + 1) %% totalLevels
}
}
sql = """
SELECT * FROM Ribbon \
WHERE groupId = ? AND
undoLevel = ?
LIMIT 1
"""
ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId, newCurrentLevel])
print("dog returning: \(ret)")
return ret
} else {
if groupId != nil {
let sql = """
SELECT * from Ribbon r1 \
WHERE r1.groupId = ?
ORDER BY undoLevel ASC
"""
var ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId])
print("all fetching ribbons: \(ret)")
return ret
} else {
let sql = """
select distinct r1.* from Ribbon r1 join Ribbon r2 ON \
r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC
"""
var ret = try Ribbon.fetchAll(db, sql: sql)
print("xxxxx fetching ribbons")
print(ret)
return ret
}
}
} catch {
print(error.localizedDescription)
print(error)
print("Error")
return []
} }
// if id == nil {
// return try Ribbon.order(Column("pos")).fetchAll(db)
// } else {
// return try Ribbon.filter(idColumn == id).fetchAll(db)
// }
// {
// if book == "" { // if book == "" {
// return try Ribbon.filter(bookColumn == Ribbon.randomBook()).fetchAll(db) // return try Ribbon.filter(bookColumn == Ribbon.randomBook()).fetchAll(db)
// } else { // } else {
@ -154,14 +69,3 @@ struct RibbonRequest: Queryable {
// } // }
} }
} }
infix operator %%
extension Int {
static func %% (_ left: Int, _ right: Int) -> Int {
let mod = left % right
return mod >= 0 ? mod : mod + right
}
}

View File

@ -11,7 +11,6 @@ struct SegDenorm: Identifiable, Equatable {
var body: String var body: String
// var lineIds: [Int64] // var lineIds: [Int64]
var book: String var book: String
var chap: Int64
} }
extension SegDenorm { extension SegDenorm {

View File

@ -24,49 +24,15 @@ struct SegDenormRequest: Queryable {
} }
func fetchValue(_ db: Database) throws -> [SegDenorm] { func fetchValue(_ db: Database) throws -> [SegDenorm] {
// print("woof segs denorm fetching for \(book)") print("WOOOOOOF")
// print(book) var sql = "select seg_id as id, seg.book as book, group_concat(line.body, ';;') as body from seg join line on seg.line_id = line.rowid WHERE seg.book = 'bible.john' group by seg.seg_id"
do {
do var ret = try SegDenorm.fetchAll(db, sql: sql) // [Player]
{
print("fetching segs")
var ret = try Ribbon.fetchAll(db, sql: """
SELECT Ribbon.* FROM SelectedRibbon \
JOIN (select distinct r1.* from Ribbon r1 join Ribbon r2 ON \
r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC) as Ribbon \
ON SelectedRibbon.ribbonGroupId = Ribbon.groupId \
WHERE SelectedRibbon.rowId = 1
""")
// print("Selected Ribbon query result: \(ret)")
var book = ret[0].book
var sql = """
select seg_id as id, line.chap as chap, seg.book as book, group_concat(line.body, ';;') as body from \
(select * from seg where seg.book = '\(book)') as seg \
join (select * from line where line.book = '\(book)') as line \
on seg.line_id = line.line_id group by seg.seg_id
"""
var ret2 = try SegDenorm.fetchAll(db, sql: sql)
// print("SEGS DENORM") // print("SEGS DENORM")
// print(ret[0]) // print(ret)
return ret
// var sql2 = """
// select count(1) from seg where seg.book = '\(book)'
// """
// var ret2 = try SegDenorm.fetchAll(db, sql: sql2)
// print("test sql result")
// print(ret2[0])
return ret2
} catch let error { } catch let error {
print(error.localizedDescription) print(error.localizedDescription)
print(error) print(error)

View File

@ -1,26 +0,0 @@
@State var selection = 0
var body: some View {
HStack {
BackArrow()
.frame(width: CGFloat(30), height: CGFloat(30))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
.if(selection == 0) { $0.background(Color.white) }
.if(selection != 0) { $0.background(Color.black) }
.onTapGesture {
withAnimation(.spring(response: 0.5)) {
self.selection = 0
}
}
ForwardArrow()
.frame(width: CGFloat(30), height: CGFloat(30))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
.if(selection == 1) { $0.background(Color.white) }
.if(selection != 1) { $0.background(Color.black) }
.onTapGesture {
withAnimation(.spring(response: 0.5)) {
self.selection = 1
}
}
}
}

View File

@ -17,7 +17,7 @@ struct SelectedRibbon: Identifiable, Equatable {
/// Int64 is the recommended type for auto-incremented database ids. /// Int64 is the recommended type for auto-incremented database ids.
/// Use nil for players that are not inserted yet in the database. /// Use nil for players that are not inserted yet in the database.
var id: Int64? var id: Int64?
var ribbonGroupId: Int64 var ribbonId: Int64
} }
extension SelectedRibbon { extension SelectedRibbon {
@ -32,7 +32,7 @@ extension SelectedRibbon: Codable, FetchableRecord, MutablePersistableRecord {
// Define database columns from CodingKeys // Define database columns from CodingKeys
fileprivate enum Columns { fileprivate enum Columns {
static let id = Column(CodingKeys.id) static let id = Column(CodingKeys.id)
static let ribbonGroupId = Column(CodingKeys.ribbonGroupId) static let ribbonId = Column(CodingKeys.ribbonId)
} }
/// Updates a player id after it has been inserted in the database. /// Updates a player id after it has been inserted in the database.

View File

@ -51,15 +51,11 @@ struct SelectedRibbonRequest: Queryable {
// var ret3 = try Ribbon.fetchAll(db, sql: "SELECT * FROM Ribbon") // [Player] // var ret3 = try Ribbon.fetchAll(db, sql: "SELECT * FROM Ribbon") // [Player]
// print(ret3) // print(ret3)
// print("FETCH JOIN RIBBON") // print("FETCH JOIN RIBBON")
var ret = try Ribbon.fetchAll(db, sql: """ var ret = try Ribbon.fetchAll(db, sql: "SELECT Ribbon.* FROM SelectedRibbon join Ribbon on SelectedRibbon.ribbonId = ribbon.rowId WHERE SelectedRibbon.rowId = 1") // [Player]
SELECT Ribbon.* FROM SelectedRibbon \ // print(ret)
JOIN (select distinct r1.* from Ribbon r1 join Ribbon r2 ON \
r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC) as Ribbon \
ON SelectedRibbon.ribbonGroupId = Ribbon.groupId \
WHERE SelectedRibbon.rowId = 1
""")
// print("Selected Ribbon query result: \(ret)")
return ret return ret
} }
} }

View File

@ -1,125 +0,0 @@
import GRDB
import GRDBQuery
import Foundation
import SwiftUI
var fontSize = CGFloat(12)
struct StatsPanel: View {
@ObservedObject var paneConnector: PaneConnector
@Query(RibbonRequest(dir: .prev, groupId: 1)) private var backRibbon: [Ribbon]
@Query(RibbonRequest(dir: .next, groupId: 1)) private var nextRibbon: [Ribbon]
@Query(RibbonRequest(groupId: 1)) private var allRibbons: [Ribbon]
@Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon]
@Environment(\.appDatabase) private var appDatabase
let columnCount = 2
var columns: [GridItem] {
Array(repeatElement(GridItem(.flexible()), count: columnCount))
}
var body: some View {
HStack(spacing: 5) {
VStack (spacing: 5) {
if backRibbon.count > 0 {
VStack {
Text("back Ribbon")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
RibbonDebug(ribbonDebug: RibbonDebugPrint(ribbon: backRibbon[0]))
}
}
VStack {
Text("next Ribbon")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
if nextRibbon.count > 0 {
RibbonDebug(ribbonDebug: RibbonDebugPrint(ribbon: nextRibbon[0]))
}
}
VStack {
Text("selected Ribbon")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
RibbonDebug(ribbonDebug: RibbonDebugPrint(ribbon: selectedRibbon[0]))
}
VStack {
Text("pc offset: \(paneConnector.currentOffset)")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
}
VStack {
Text("pc id: \(paneConnector.currentId)")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
}
}
VStack(spacing: 5) {
let fr = allRibbons[0]
let currentPos = (fr.currentLevel - fr.minLevel) %% totalLevels
let text = "current pos: \(currentPos)"
Text(text)
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
ForEach(RibbonMap(ribbons: allRibbons), id: \.self) { ribbon in
RibbonDebug(ribbonDebug: ribbon)
}
}
}
}
}
func RibbonMap(ribbons: [Ribbon]) -> [[String]] {
var retStrings = [[String]]()
for r in ribbons {
var debugString = RibbonDebugPrint(ribbon:r)
retStrings.append(debugString)
}
let sortedStats = retStrings.sorted {
Int($0[0])! > Int($1[0])!
}
return sortedStats
}
func RibbonDebugPrint(ribbon: Ribbon) -> [String] {
var ribbonStats = [String]()
let undoPos = (ribbon.undoLevel - ribbon.minLevel) %% totalLevels
ribbonStats.append("\(undoPos)")
ribbonStats.append("id: \(ribbon.id) ")
ribbonStats.append("scrollOffset: \(ribbon.scrollOffset)")
ribbonStats.append("scrollId: \(ribbon.scrollId)")
// ribbonStats.append("undoLevel: \(ribbon.undoLevel)")
// ribbonStats.append("currentLevel: \(ribbon.currentLevel)")
// ribbonStats.append("minLevel: \(ribbon.minLevel)")
// ribbonStats.append("maxLevel: \(ribbon.maxLevel)")
return ribbonStats
}
struct RibbonDebug: View {
var ribbonDebug: [String]
var body: some View {
VStack {
VStack {
// let ribbonStats = RibbonDebugPrint(ribbon: ribbon)
ForEach(ribbonDebug, id: \.self) {
Text($0)
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
}
}
}
}
}

View File

@ -1,19 +1 @@
{ {"argv":["/Users/saint/.local/share/xbase/xbase-sourcekit-helper"],"bspVersion":"0.2","languages":["swift","objective-c","objective-cpp","c","cpp"],"name":"XBase","version":"0.3"}
"argv": [
"/usr/local/bin/xcode-build-server"
],
"bspVersion": "2.0",
"languages": [
"c",
"cpp",
"objective-c",
"objective-cpp",
"swift"
],
"name": "xcode build server",
"version": "0.2",
"workspace": "/Users/saint/code/gloss/gloss.xcodeproj/project.xcworkspace",
"build_root": "/Users/saint/Library/Developer/Xcode/DerivedData/gloss-ajphzxkxxghgqicpumudnmcgeuwg",
"scheme": "gloss",
"kind": "xcode"
}

View File

@ -7,11 +7,6 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
851259B02C05281300BE70F8 /* BackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259AF2C05281300BE70F8 /* BackButton.swift */; };
851259B22C05299200BE70F8 /* ForwardArrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259B12C05299200BE70F8 /* ForwardArrow.swift */; };
851259B62C07560800BE70F8 /* NaviBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259B52C07560800BE70F8 /* NaviBar.swift */; };
851259B82C0A145500BE70F8 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259B72C0A145500BE70F8 /* Stats.swift */; };
851259BA2C0F355D00BE70F8 /* BookmarkIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259B92C0F355D00BE70F8 /* BookmarkIcon.swift */; };
8514D5BC299EFB780054F185 /* store.db in Resources */ = {isa = PBXBuildFile; fileRef = 8514D5BB299EFB780054F185 /* store.db */; }; 8514D5BC299EFB780054F185 /* store.db in Resources */ = {isa = PBXBuildFile; fileRef = 8514D5BB299EFB780054F185 /* store.db */; };
8514D5BF299F04710054F185 /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 8514D5BE299F04710054F185 /* GRDB */; }; 8514D5BF299F04710054F185 /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 8514D5BE299F04710054F185 /* GRDB */; };
852774C129A150B100458CA7 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852774C029A150B100458CA7 /* Line.swift */; }; 852774C129A150B100458CA7 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852774C029A150B100458CA7 /* Line.swift */; };
@ -27,7 +22,7 @@
85431A902905F4F600EE0760 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 85431A8F2905F4F600EE0760 /* Preview Assets.xcassets */; }; 85431A902905F4F600EE0760 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 85431A8F2905F4F600EE0760 /* Preview Assets.xcassets */; };
85431A922905F4F600EE0760 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85431A912905F4F600EE0760 /* Persistence.swift */; }; 85431A922905F4F600EE0760 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85431A912905F4F600EE0760 /* Persistence.swift */; };
85431A9C2905F5D800EE0760 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85431A9B2905F5D800EE0760 /* SwiftUIView.swift */; }; 85431A9C2905F5D800EE0760 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85431A9B2905F5D800EE0760 /* SwiftUIView.swift */; };
857C34492BFB7DC800661A63 /* Pane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 857C34482BFB7DC800661A63 /* Pane.swift */; }; 857C34492BFB7DC800661A63 /* Fenestra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 857C34482BFB7DC800661A63 /* Fenestra.swift */; };
8590D96729A183EE001EF84F /* AppDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590D96629A183EE001EF84F /* AppDatabase.swift */; }; 8590D96729A183EE001EF84F /* AppDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590D96629A183EE001EF84F /* AppDatabase.swift */; };
8590D96929A18A6D001EF84F /* LineRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590D96829A18A6C001EF84F /* LineRequest.swift */; }; 8590D96929A18A6D001EF84F /* LineRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590D96829A18A6C001EF84F /* LineRequest.swift */; };
8590D96C29A92146001EF84F /* JsonImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590D96B29A92146001EF84F /* JsonImport.swift */; }; 8590D96C29A92146001EF84F /* JsonImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590D96B29A92146001EF84F /* JsonImport.swift */; };
@ -42,7 +37,6 @@
85942EFE29B11C0B00307621 /* john_export.json in Resources */ = {isa = PBXBuildFile; fileRef = 85942EFC29B11C0A00307621 /* john_export.json */; }; 85942EFE29B11C0B00307621 /* john_export.json in Resources */ = {isa = PBXBuildFile; fileRef = 85942EFC29B11C0A00307621 /* john_export.json */; };
85942EFF29B11C0B00307621 /* mark_export.json in Resources */ = {isa = PBXBuildFile; fileRef = 85942EFD29B11C0B00307621 /* mark_export.json */; }; 85942EFF29B11C0B00307621 /* mark_export.json in Resources */ = {isa = PBXBuildFile; fileRef = 85942EFD29B11C0B00307621 /* mark_export.json */; };
8594ED982BF6845F001213F2 /* HexColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8594ED972BF6845F001213F2 /* HexColor.swift */; }; 8594ED982BF6845F001213F2 /* HexColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8594ED972BF6845F001213F2 /* HexColor.swift */; };
85AAAF572C1A0BC700FCB723 /* acts_export.json in Resources */ = {isa = PBXBuildFile; fileRef = 85AAAF562C1A0BC700FCB723 /* acts_export.json */; };
85E00E7C29F34D2D00FF9E78 /* ScrollState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */; }; 85E00E7C29F34D2D00FF9E78 /* ScrollState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */; };
85E00E7E29F34D3700FF9E78 /* ScrollStateRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E00E7D29F34D3700FF9E78 /* ScrollStateRequest.swift */; }; 85E00E7E29F34D3700FF9E78 /* ScrollStateRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E00E7D29F34D3700FF9E78 /* ScrollStateRequest.swift */; };
85F01DF82978787800F317B4 /* AveriaSerifLibre-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85F01DF72978787800F317B4 /* AveriaSerifLibre-Regular.ttf */; }; 85F01DF82978787800F317B4 /* AveriaSerifLibre-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 85F01DF72978787800F317B4 /* AveriaSerifLibre-Regular.ttf */; };
@ -51,11 +45,6 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
851259AF2C05281300BE70F8 /* BackButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackButton.swift; sourceTree = "<group>"; };
851259B12C05299200BE70F8 /* ForwardArrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardArrow.swift; sourceTree = "<group>"; };
851259B52C07560800BE70F8 /* NaviBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NaviBar.swift; sourceTree = "<group>"; };
851259B72C0A145500BE70F8 /* Stats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = "<group>"; };
851259B92C0F355D00BE70F8 /* BookmarkIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkIcon.swift; sourceTree = "<group>"; };
8514D5BB299EFB780054F185 /* store.db */ = {isa = PBXFileReference; lastKnownFileType = file; path = store.db; sourceTree = "<group>"; }; 8514D5BB299EFB780054F185 /* store.db */ = {isa = PBXFileReference; lastKnownFileType = file; path = store.db; sourceTree = "<group>"; };
852774C029A150B100458CA7 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; }; 852774C029A150B100458CA7 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
8528897429B2B86B003F2E16 /* CrownOfThorns.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrownOfThorns.swift; sourceTree = "<group>"; }; 8528897429B2B86B003F2E16 /* CrownOfThorns.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrownOfThorns.swift; sourceTree = "<group>"; };
@ -69,7 +58,7 @@
85431A8F2905F4F600EE0760 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; }; 85431A8F2905F4F600EE0760 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
85431A912905F4F600EE0760 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; }; 85431A912905F4F600EE0760 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
85431A9B2905F5D800EE0760 /* SwiftUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = "<group>"; }; 85431A9B2905F5D800EE0760 /* SwiftUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = "<group>"; };
857C34482BFB7DC800661A63 /* Pane.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pane.swift; sourceTree = "<group>"; }; 857C34482BFB7DC800661A63 /* Fenestra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fenestra.swift; sourceTree = "<group>"; };
8590D96629A183EE001EF84F /* AppDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDatabase.swift; sourceTree = "<group>"; }; 8590D96629A183EE001EF84F /* AppDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDatabase.swift; sourceTree = "<group>"; };
8590D96829A18A6C001EF84F /* LineRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineRequest.swift; sourceTree = "<group>"; }; 8590D96829A18A6C001EF84F /* LineRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineRequest.swift; sourceTree = "<group>"; };
8590D96B29A92146001EF84F /* JsonImport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonImport.swift; sourceTree = "<group>"; }; 8590D96B29A92146001EF84F /* JsonImport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonImport.swift; sourceTree = "<group>"; };
@ -84,7 +73,6 @@
85942EFC29B11C0A00307621 /* john_export.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = john_export.json; sourceTree = "<group>"; }; 85942EFC29B11C0A00307621 /* john_export.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = john_export.json; sourceTree = "<group>"; };
85942EFD29B11C0B00307621 /* mark_export.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = mark_export.json; sourceTree = "<group>"; }; 85942EFD29B11C0B00307621 /* mark_export.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = mark_export.json; sourceTree = "<group>"; };
8594ED972BF6845F001213F2 /* HexColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HexColor.swift; sourceTree = "<group>"; }; 8594ED972BF6845F001213F2 /* HexColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HexColor.swift; sourceTree = "<group>"; };
85AAAF562C1A0BC700FCB723 /* acts_export.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = acts_export.json; sourceTree = "<group>"; };
85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollState.swift; sourceTree = "<group>"; }; 85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollState.swift; sourceTree = "<group>"; };
85E00E7D29F34D3700FF9E78 /* ScrollStateRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollStateRequest.swift; sourceTree = "<group>"; }; 85E00E7D29F34D3700FF9E78 /* ScrollStateRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollStateRequest.swift; sourceTree = "<group>"; };
85F01DF72978787800F317B4 /* AveriaSerifLibre-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "AveriaSerifLibre-Regular.ttf"; sourceTree = "<group>"; }; 85F01DF72978787800F317B4 /* AveriaSerifLibre-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "AveriaSerifLibre-Regular.ttf"; sourceTree = "<group>"; };
@ -120,10 +108,7 @@
85431A7C2905F4F500EE0760 = { 85431A7C2905F4F500EE0760 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
851259B92C0F355D00BE70F8 /* BookmarkIcon.swift */, 857C34482BFB7DC800661A63 /* Fenestra.swift */,
851259B12C05299200BE70F8 /* ForwardArrow.swift */,
851259AF2C05281300BE70F8 /* BackButton.swift */,
857C34482BFB7DC800661A63 /* Pane.swift */,
8594ED972BF6845F001213F2 /* HexColor.swift */, 8594ED972BF6845F001213F2 /* HexColor.swift */,
85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */, 85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */,
85E00E7D29F34D3700FF9E78 /* ScrollStateRequest.swift */, 85E00E7D29F34D3700FF9E78 /* ScrollStateRequest.swift */,
@ -132,8 +117,6 @@
85942EEE29AEA18300307621 /* SelectedRibbonRequest.swift */, 85942EEE29AEA18300307621 /* SelectedRibbonRequest.swift */,
85942EF429B108C600307621 /* Seg.swift */, 85942EF429B108C600307621 /* Seg.swift */,
85942EF629B108EA00307621 /* SegDenormRequest.swift */, 85942EF629B108EA00307621 /* SegDenormRequest.swift */,
851259B52C07560800BE70F8 /* NaviBar.swift */,
851259B72C0A145500BE70F8 /* Stats.swift */,
85942EF829B1150B00307621 /* SegDenorm.swift */, 85942EF829B1150B00307621 /* SegDenorm.swift */,
85942EEA29AD55A400307621 /* RibbonRequest.swift */, 85942EEA29AD55A400307621 /* RibbonRequest.swift */,
85942EE329ACF54A00307621 /* ScrollableView.swift */, 85942EE329ACF54A00307621 /* ScrollableView.swift */,
@ -189,7 +172,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
85942EFC29B11C0A00307621 /* john_export.json */, 85942EFC29B11C0A00307621 /* john_export.json */,
85AAAF562C1A0BC700FCB723 /* acts_export.json */,
85942EFD29B11C0B00307621 /* mark_export.json */, 85942EFD29B11C0B00307621 /* mark_export.json */,
); );
path = json; path = json;
@ -286,7 +268,6 @@
85F01DFB2978790400F317B4 /* xe-Dogma-Bold.ttf in Resources */, 85F01DFB2978790400F317B4 /* xe-Dogma-Bold.ttf in Resources */,
85F01DF82978787800F317B4 /* AveriaSerifLibre-Regular.ttf in Resources */, 85F01DF82978787800F317B4 /* AveriaSerifLibre-Regular.ttf in Resources */,
8514D5BC299EFB780054F185 /* store.db in Resources */, 8514D5BC299EFB780054F185 /* store.db in Resources */,
85AAAF572C1A0BC700FCB723 /* acts_export.json in Resources */,
85942EFF29B11C0B00307621 /* mark_export.json in Resources */, 85942EFF29B11C0B00307621 /* mark_export.json in Resources */,
85942EFE29B11C0B00307621 /* john_export.json in Resources */, 85942EFE29B11C0B00307621 /* john_export.json in Resources */,
85431A8D2905F4F600EE0760 /* Assets.xcassets in Resources */, 85431A8D2905F4F600EE0760 /* Assets.xcassets in Resources */,
@ -301,11 +282,9 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
85431A922905F4F600EE0760 /* Persistence.swift in Sources */, 85431A922905F4F600EE0760 /* Persistence.swift in Sources */,
857C34492BFB7DC800661A63 /* Pane.swift in Sources */, 857C34492BFB7DC800661A63 /* Fenestra.swift in Sources */,
85942EEB29AD55A400307621 /* RibbonRequest.swift in Sources */, 85942EEB29AD55A400307621 /* RibbonRequest.swift in Sources */,
851259BA2C0F355D00BE70F8 /* BookmarkIcon.swift in Sources */,
85431A8B2905F4F500EE0760 /* ContentView.swift in Sources */, 85431A8B2905F4F500EE0760 /* ContentView.swift in Sources */,
851259B02C05281300BE70F8 /* BackButton.swift in Sources */,
85942EF529B108C600307621 /* Seg.swift in Sources */, 85942EF529B108C600307621 /* Seg.swift in Sources */,
85E00E7C29F34D2D00FF9E78 /* ScrollState.swift in Sources */, 85E00E7C29F34D2D00FF9E78 /* ScrollState.swift in Sources */,
8594ED982BF6845F001213F2 /* HexColor.swift in Sources */, 8594ED982BF6845F001213F2 /* HexColor.swift in Sources */,
@ -318,15 +297,12 @@
85942EEF29AEA18300307621 /* SelectedRibbonRequest.swift in Sources */, 85942EEF29AEA18300307621 /* SelectedRibbonRequest.swift in Sources */,
8590D96C29A92146001EF84F /* JsonImport.swift in Sources */, 8590D96C29A92146001EF84F /* JsonImport.swift in Sources */,
85942EED29AEA04200307621 /* SelectedRibbon.swift in Sources */, 85942EED29AEA04200307621 /* SelectedRibbon.swift in Sources */,
851259B82C0A145500BE70F8 /* Stats.swift in Sources */,
85431A892905F4F500EE0760 /* glossApp.swift in Sources */, 85431A892905F4F500EE0760 /* glossApp.swift in Sources */,
8528897C29BD69B2003F2E16 /* VisibilityTrackingScrollView.swift in Sources */, 8528897C29BD69B2003F2E16 /* VisibilityTrackingScrollView.swift in Sources */,
85942EF929B1150B00307621 /* SegDenorm.swift in Sources */, 85942EF929B1150B00307621 /* SegDenorm.swift in Sources */,
85431A9C2905F5D800EE0760 /* SwiftUIView.swift in Sources */, 85431A9C2905F5D800EE0760 /* SwiftUIView.swift in Sources */,
851259B22C05299200BE70F8 /* ForwardArrow.swift in Sources */,
8528897E29BD69B2003F2E16 /* VisibilityTracker.swift in Sources */, 8528897E29BD69B2003F2E16 /* VisibilityTracker.swift in Sources */,
85942EF729B108EA00307621 /* SegDenormRequest.swift in Sources */, 85942EF729B108EA00307621 /* SegDenormRequest.swift in Sources */,
851259B62C07560800BE70F8 /* NaviBar.swift in Sources */,
8528897D29BD69B2003F2E16 /* VisibilityTrackingModifier.swift in Sources */, 8528897D29BD69B2003F2E16 /* VisibilityTrackingModifier.swift in Sources */,
85942EE429ACF54A00307621 /* ScrollableView.swift in Sources */, 85942EE429ACF54A00307621 /* ScrollableView.swift in Sources */,
); );
@ -464,7 +440,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"gloss/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"gloss/Preview Content\"";
DEVELOPMENT_TEAM = C8XWX9329P; DEVELOPMENT_TEAM = V8B2B34W7R;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = gloss/Info.plist; INFOPLIST_FILE = gloss/Info.plist;
@ -502,7 +478,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"gloss/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"gloss/Preview Content\"";
DEVELOPMENT_TEAM = C8XWX9329P; DEVELOPMENT_TEAM = V8B2B34W7R;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = gloss/Info.plist; INFOPLIST_FILE = gloss/Info.plist;

View File

@ -1,10 +1,10 @@
import Foundation import Foundation
import GRDB import GRDB
/// AppDatabase lets the application access the database.
///
let totalLevels = 3 /// It applies the pratices recommended at
/// <https://github.com/groue/GRDB.swift/blob/master/Documentation/GoodPracticesForDesigningRecordTypes.md>
struct AppDatabase { struct AppDatabase {
/// Creates an `AppDatabase`, and make sure the database schema is ready. /// Creates an `AppDatabase`, and make sure the database schema is ready.
init(_ dbWriter: any DatabaseWriter) throws { init(_ dbWriter: any DatabaseWriter) throws {
@ -39,7 +39,6 @@ struct AppDatabase {
t.autoIncrementedPrimaryKey("id") t.autoIncrementedPrimaryKey("id")
t.column("body", .text).notNull() t.column("body", .text).notNull()
t.column("chap", .integer).notNull() t.column("chap", .integer).notNull()
t.column("line_id", .integer).notNull()
t.column("book", .text).notNull() t.column("book", .text).notNull()
t.column("verse", .integer) t.column("verse", .integer)
} }
@ -54,13 +53,6 @@ struct AppDatabase {
try db.create(table: "Ribbon") { t in try db.create(table: "Ribbon") { t in
t.autoIncrementedPrimaryKey("id") t.autoIncrementedPrimaryKey("id")
t.column("pos", .integer).notNull() t.column("pos", .integer).notNull()
t.column("groupId", .integer).notNull()
t.column("undoLevel", .integer).notNull()
t.column("currentLevel", .integer).notNull()
t.column("minLevel", .integer).notNull()
t.column("maxLevel", .integer).notNull()
.defaults(to: 1)
t.column("title", .text).notNull() t.column("title", .text).notNull()
t.column("book", .text).notNull() t.column("book", .text).notNull()
t.column("scrollOffset", .integer).notNull() t.column("scrollOffset", .integer).notNull()
@ -69,7 +61,7 @@ struct AppDatabase {
try db.create(table: "SelectedRibbon") { t in try db.create(table: "SelectedRibbon") { t in
t.autoIncrementedPrimaryKey("id") t.autoIncrementedPrimaryKey("id")
t.column("ribbonGroupId", .integer).notNull() t.column("ribbonId", .integer).notNull()
} }
try db.create(table: "ScrollState") { t in try db.create(table: "ScrollState") { t in
@ -78,8 +70,7 @@ struct AppDatabase {
t.column("scrollOffset", .integer).notNull() t.column("scrollOffset", .integer).notNull()
} }
// change this to nuke/remake the database try db.create(table: "foo2") { t in
try db.create(table: "foo4") { t in
t.autoIncrementedPrimaryKey("id") t.autoIncrementedPrimaryKey("id")
t.column("ribbonId", .integer).notNull() t.column("ribbonId", .integer).notNull()
} }
@ -122,22 +113,6 @@ func load<T: Decodable>(_ filename: String) -> T {
extension AppDatabase { extension AppDatabase {
func getSelectedRibbon() async throws -> [Ribbon] {
try await dbWriter.write { db in
var sr = try Ribbon.fetchAll(db, sql: """
SELECT Ribbon.* FROM SelectedRibbon \
JOIN (select distinct r1.* from Ribbon r1 join Ribbon r2 ON \
r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC) as Ribbon \
ON SelectedRibbon.ribbonGroupId = Ribbon.groupId \
WHERE SelectedRibbon.rowId = 1
""")
print("meow get selected ribbon \(sr)")
return sr
}
}
func updateRibbonPosition(_ ribbon: inout Ribbon, _ oldPos: Int, _ newPos: Int) async throws { func updateRibbonPosition(_ ribbon: inout Ribbon, _ oldPos: Int, _ newPos: Int) async throws {
try await dbWriter.write { [ribbon] db in try await dbWriter.write { [ribbon] db in
@ -218,135 +193,6 @@ extension AppDatabase {
} }
} }
func redoRibbon(_ ribbon: inout Ribbon) async throws {
let currentLevel = ribbon.currentLevel
let minLevel = ribbon.maxLevel
if currentLevel == minLevel {
print("no where to redo")
return
}
let newCurrent = (ribbon.currentLevel + 1) %% totalLevels
do {
try await dbWriter.write { [ribbon] db in
try db.execute(sql: """
UPDATE Ribbon \
SET currentLevel = ? WHERE groupId = ?
""", arguments: [newCurrent, ribbon.groupId])
}
} catch {
print("Redo Ribbon Error info: \(error)")
}
}
// this sets the current undoLevel to the previous value
// if you can go back
func undoRibbon(_ ribbon: inout Ribbon) async throws {
let currentLevel = ribbon.currentLevel
let minLevel = ribbon.minLevel
if currentLevel == minLevel {
print("no where to undo")
return
}
let newCurrent = (ribbon.currentLevel - 1) %% totalLevels
do {
try await dbWriter.write { [ribbon] db in
try db.execute(sql: """
UPDATE Ribbon \
SET currentLevel = ? WHERE groupId = ?
""", arguments: [newCurrent, ribbon.groupId])
}
} catch {
print("Undo Ribbon Error info: \(error)")
}
}
// deletes all undo steps above the current undo level
// and adds new undo level at the new current level,
// adjusts the minLevel and maxLevel
func bumpRibbon(_ ribbon: inout Ribbon) async throws -> [Ribbon] {
var level = ribbon.currentLevel
let maxLevel = ribbon.maxLevel
// gets all the levels from the current to the max
// so they can be deleted
var delLevels2 = [Int]()
if level != maxLevel {
repeat {
level = (level + 1) %% totalLevels
delLevels2.append(level)
} while level != maxLevel
}
let delLevels = delLevels2
let newMax = (ribbon.currentLevel + 1) %% totalLevels
let newCurrent = newMax
let newMin = newMax == ribbon.minLevel ? (ribbon.minLevel + 1) %% totalLevels
: ribbon.minLevel
ribbon.minLevel = newMin
ribbon.maxLevel = newMax
ribbon.undoLevel = newCurrent
ribbon.currentLevel = newCurrent
ribbon.id = nil
do {
try await dbWriter.write { [ribbon] db in
for l in delLevels {
try db.execute(sql: """
DELETE FROM Ribbon \
WHERE groupId = ? \
AND undoLevel = ?
""", arguments: [ribbon.groupId, l])
}
try db.execute(sql: """
UPDATE Ribbon \
SET minLevel = ?, maxLevel = ?, currentLevel = ? WHERE groupId = ?
""", arguments: [newMin, newMax, newCurrent, ribbon.groupId])
// upsert
var ret = try Ribbon.fetchAll(db, sql: """
SELECT * from Ribbon WHERE groupId = ? AND undoLevel = ?
""", arguments: [ribbon.groupId, ribbon.undoLevel])
if ret.count == 0 {
// insert
_ = try ribbon.inserted(db)
} else {
var updatedRibbon = ret[0]
updatedRibbon.minLevel = newMin
updatedRibbon.maxLevel = newMax
updatedRibbon.undoLevel = newCurrent
updatedRibbon.currentLevel = newCurrent
updatedRibbon.scrollId = ribbon.scrollId
updatedRibbon.scrollOffset = ribbon.scrollOffset
try updatedRibbon.update(db)
}
ret = try Ribbon.fetchAll(db, sql: """
SELECT * from Ribbon WHERE groupId = ? AND undoLevel = ?
""", arguments: [ribbon.groupId, newCurrent])
return ret
}
} catch {
print("Error info: \(error)")
}
return []
}
func saveSelectedRibbon(_ selectedRibbon: inout SelectedRibbon) async throws { func saveSelectedRibbon(_ selectedRibbon: inout SelectedRibbon) async throws {
// if ribbon.name.isEmpty { // if ribbon.name.isEmpty {
// throw ValidationError.missingName // throw ValidationError.missingName
@ -366,108 +212,35 @@ extension AppDatabase {
} }
func importJson(_ filename: String, _ db: Database) throws { func importJson(_ filename: String, _ db: Database) throws {
let importJson: JsonImport = load(filename) let importJson : JsonImport = load(filename)
var x = 0 if try Line.all().isEmpty(db) {
// if try Line.all().isEmpty(db) { for l in importJson.lines {
for l in importJson.lines { print("importing Lines")
// print("importing Lines") _ = try l.inserted(db)
if x < 5 {
print(l)
x += 1
} }
_ = try l.inserted(db)
}
x = 0 for l in importJson.segs {
for l in importJson.segs { print("importing SEGS")
// print("importing SEGS") _ = try l.inserted(db)
if x < 5 {
print(l)
x += 1
} }
_ = try l.inserted(db)
} }
} }
/// Create random Lines if the database is empty. /// Create random Lines if the database is empty.
func initDatabase() throws { func initDatabase() throws {
do { try dbWriter.write { db in
try dbWriter.write { db in
if try Line.all().isEmpty(db)
{
try importJson("john_export.json", db)
try importJson("mark_export.json", db)
try importJson("acts_export.json", db)
_ = try Ribbon(id: 1,
groupId: 1,
pos: 1,
undoLevel: 0,
currentLevel: 0,
minLevel: 0,
maxLevel: 0,
title: "Gospel of John",
book: "bible.john",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try Ribbon(id: 2, if try Line.all().isEmpty(db) {
groupId: 2,
pos: 2,
undoLevel: 0,
currentLevel: 0,
minLevel: 0,
maxLevel: 0,
title: "Gospel according to Mark",
book: "bible.mark",
scrollId: "1",
scrollOffset: 300).inserted(db)
///// try importJson("john_export.json", db)
try importJson("mark_export.json", db)
_ = try Ribbon(id: 3, _ = try Ribbon(id: 1, pos: 1, title: "John", book: "bible.john", scrollId: "1", scrollOffset: 0).inserted(db)
groupId: 3, _ = try Ribbon(id: 2, pos: 2, title: "Gospel of Mark", book: "bible.mark", scrollId: "1", scrollOffset: 300).inserted(db)
pos: 3, _ = try Ribbon(id: 3, pos: 3, title: "John 2", book: "bible.john", scrollId: "1", scrollOffset: 0).inserted(db)
undoLevel: 0, _ = try SelectedRibbon(id: 1, ribbonId: 1).inserted(db)
currentLevel: 2,
minLevel: 0,
maxLevel: 2,
title: "Acts",
book: "bible.acts",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try Ribbon(id: 4,
groupId: 3,
pos: 3,
undoLevel: 1,
currentLevel: 2,
minLevel: 0,
maxLevel: 2,
title: "Acts",
book: "bible.acts",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try Ribbon(id: 5,
groupId: 3,
pos: 3,
undoLevel: 2,
currentLevel: 2,
minLevel: 0,
maxLevel: 2,
title: "Acts",
book: "bible.acts",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try SelectedRibbon(id: 1, ribbonGroupId: 1).inserted(db)
} }
} }
} catch {
print("Error info: \(error)")
}
} }
} }

View File

@ -16,12 +16,10 @@ let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "network
var currentId: String? var currentId: String?
var currentOffset: CGFloat? var currentOffset: CGFloat?
var disableDrop = false var gTracker: VisibilityTracker<String>?
var printCount: Int64 = 0
//TODO: move to globals file var disableDrop = false
let mainBackgroundColor = Color(red: 0.1, green: 0.1, blue: 0.1)
let mainTextColor = Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00))
let secondBackgroundColor = Color(red: 0.18, green: 0.18, blue: 0.18)
public extension UserDefaults { public extension UserDefaults {
func optionalInt(forKey defaultName: String) -> Int? { func optionalInt(forKey defaultName: String) -> Int? {
@ -41,78 +39,70 @@ public extension UserDefaults {
} }
} }
func createUndoState(selectedRibbon: Ribbon,
appDatabase : AppDatabase,
paneConnector : PaneConnector) async throws -> [Ribbon]
{
let updateThreshold = 30
var updatedRibbon = selectedRibbon
var scrollOffsetToSave = Int(floor(paneConnector.currentOffset))
var scrollIdToSave = paneConnector.currentId
var offsetDiff = abs(scrollOffsetToSave - updatedRibbon.scrollOffset) > 30
var idDiff = Int(updatedRibbon.scrollId) != Int(scrollIdToSave)
if idDiff || offsetDiff {
updatedRibbon.scrollId = scrollIdToSave
updatedRibbon.scrollOffset = scrollOffsetToSave
print("meow bumping")
let ret = try await appDatabase.bumpRibbon(&updatedRibbon)
return ret
}
print("meow no bump")
return []
}
func goToRibbon(selectedRibbon: Ribbon, func goToRibbon(selectedRibbon: Ribbon,
destRibbon: Ribbon, destRibbon: Ribbon,
scrollId: Binding<String?>,
scrollOffset: Binding<CGFloat?>,
refresh: Binding<Bool>,
showOverlay: Binding<Bool>,
appDatabase: AppDatabase, appDatabase: AppDatabase,
paneConnector: PaneConnector,
loading: Bool) loading: Bool)
{ {
print("meow goto ribbon - selected ribbon: \(selectedRibbon), dest ribbon: \(destRibbon) ") Task {
// print("SELECTED RIBBON", selectedRibbon)
var scrollOffsetToSave = currentOffset
var scrollIdToSave = currentId
DispatchQueue.main.asyncAfter(deadline: .now()) { var updatedRibbon = selectedRibbon
Task {
var scrollOffsetToSave = paneConnector.currentOffset
var scrollIdToSave = paneConnector.currentId
print("go to ribbon") if selectedRibbon.id != destRibbon.id! || loading {
print("\(selectedRibbon.id) \(destRibbon.id!)") print("switching ribbons")
// if selectedRibbon.id != destRibbon.id! || loading { // withAnimation(.spring(response: 0.05)) {
if true { // showOverlay.wrappedValue = true
print("switching ribbons") showOverlay.wrappedValue = true
// }
paneConnector.showOverlay = true if loading {
currentId = destRibbon.scrollId
if loading { // currentOffset = CGFloat(destRibbon.scrollOffset)
paneConnector.currentId = destRibbon.scrollId
}
paneConnector.scrollId = destRibbon.scrollId
paneConnector.scrollOffset = CGFloat(destRibbon.scrollOffset)
paneConnector.refresh.toggle()
print("toggling")
print("paneconnector: \(paneConnector.refresh)")
var updateSelectRibbon = SelectedRibbon(id: Int64(1), ribbonGroupId: Int64(destRibbon.groupId))
// print("Saving selected ribbon")
// print(updateSelectRibbon)
do {
_ = try await appDatabase.saveSelectedRibbon(&updateSelectRibbon)
} catch {
// Print("something wrong")
}
} }
} 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 { extension View {
@ -125,21 +115,21 @@ extension View {
struct RibbonCrown: View { struct RibbonCrown: View {
var ribbon: Ribbon var ribbon: Ribbon
@ObservedObject var paneConnector: PaneConnector @Binding var scrollId: String?
@Binding var scrollOffset: CGFloat?
@Binding var showOverlay: Bool
@Binding var refresh: Bool
var draggedRibbon: Ribbon? var draggedRibbon: Ribbon?
var isDragging: Bool var isDragging: Bool
var height = CGFloat(41) var height = CGFloat(45)
var width = CGFloat(70) var scale = 0.65
var scale = 0.70
@Environment(\.appDatabase) private var appDatabase @Environment(\.appDatabase) private var appDatabase
@Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon] @Query(SelectedRibbonRequest()) private var sr: [Ribbon]
@State var saveOffset = CGFloat() @State var saveOffset = CGFloat()
@Binding var refresh: Bool
var body: some View { var body: some View {
ZStack { ZStack {
MyIcon().frame( MyIcon().frame(
@ -152,8 +142,8 @@ struct RibbonCrown: View {
Text(ribbon.title) Text(ribbon.title)
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00))) .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.frame(minWidth: width, .frame(minWidth: CGFloat(70),
maxWidth: width, maxWidth: CGFloat(70),
minHeight: height, minHeight: height,
maxHeight: height, maxHeight: height,
alignment: .center) alignment: .center)
@ -167,29 +157,20 @@ struct RibbonCrown: View {
} }
.onTapGesture { .onTapGesture {
Task { Task {
let sr = selectedRibbon[0] goToRibbon(selectedRibbon: sr[0],
let updatedRibbon = try await createUndoState(selectedRibbon: sr, destRibbon: ribbon,
appDatabase: appDatabase, scrollId: $scrollId,
paneConnector: paneConnector) scrollOffset: $scrollOffset,
refresh: $refresh,
if sr.id == ribbon.id { showOverlay: $showOverlay,
paneConnector.scrollId = paneConnector.currentId appDatabase: appDatabase,
paneConnector.scrollOffset = paneConnector.currentOffset loading: false)
paneConnector.hasMoved = false }
} else {
goToRibbon(selectedRibbon: sr,
destRibbon: ribbon,
appDatabase: appDatabase,
paneConnector: paneConnector,
loading: false)
}
}
} }
.frame(width: CGFloat(100 * 1.66 * scale + 10), height: CGFloat(100 * scale + 5)) .frame(width: CGFloat(100 * 1.66 * scale + 10), height: CGFloat(100 * scale + 5))
} }
} }
// object used for JSON decoding of verses
class Verse: NSObject, Codable { class Verse: NSObject, Codable {
var body: String var body: String
var verse: Int var verse: Int
@ -214,56 +195,38 @@ func makeVerseView(seg: SegDenorm) -> some View {
return retView return retView
} }
class PaneConnector: NSObject, ObservableObject {
var showOverlay: Bool = false
@Published var refresh: Bool = false
@Published var vertSep = CGFloat(20)
var currentId = ""
var currentOffset = CGFloat()
var visibilityTracker: VisibilityTracker<String>?
@Published var scrollId = ""
@Published var scrollOffset = CGFloat()
@Published var hasMoved = false
var setScrollOffset: CGFloat?
}
struct ContentView: View { struct ContentView: View {
// this is for the whole view swiping @State var viewState = CGSize.zero
@State var mainSwipe = CGSize.zero
@State var pulledOut = CGSize.zero @State var pulledOut = CGSize.zero
@State var selection = 0 @State var thisScrollView: UIScrollView?
@State var scrollUpdate = false
@State var initLoad = false
@StateObject var paneConnector = PaneConnector() // set this to scroll to area
@State var scrollId: String?
@State var scrollOffset: CGFloat?
@State var refresh: Bool = false @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 endedDrag = true
@State var readOffset = CGPoint() @State var readOffset = CGPoint()
@State var dragOffset = CGFloat()
@Query(SegDenormRequest(book: "bible.john")) private var segs: [SegDenorm] @State var refresh: Bool = false
@State var refresh2: Bool = false
@State var draggedRibbon: Ribbon? @State var draggedRibbon: Ribbon?
@State var isDragging = false @State var isDragging = false
@State var dragOffset = CGFloat(0) @State var reorder = true
enum SwipeStartState {
case center
case right
case left
}
enum SwipeStartDir {
case left
case right
}
// @State var curSwipeState: SwipeState = .start
@State var startSwipeState: SwipeStartState?
@State var startSwipeDir: SwipeStartDir?
@Environment(\.appDatabase) private var appDatabase
@Query(RibbonRequest()) private var ribbons: [Ribbon] @Query(RibbonRequest()) private var ribbons: [Ribbon]
@Query<SelectedRibbonRequest> var selectedRibbon: [Ribbon] @Query<SelectedRibbonRequest> var selectedRibbon: [Ribbon]
@ -285,13 +248,14 @@ struct ContentView: View {
ZStack(alignment: .top) { ZStack(alignment: .top) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
VStack { VStack {
ForEach(ribbons) { ribbon in ForEach(ribbons) { ribbon in
RibbonCrown(ribbon: ribbon, RibbonCrown(ribbon: ribbon,
paneConnector: paneConnector, scrollId: $scrollId,
scrollOffset: $scrollOffset,
showOverlay: $showOverlay,
refresh: $refresh,
draggedRibbon: draggedRibbon, draggedRibbon: draggedRibbon,
isDragging: isDragging, isDragging: isDragging)
refresh: $refresh)
.onDrag { .onDrag {
self.draggedRibbon = ribbon self.draggedRibbon = ribbon
return NSItemProvider() return NSItemProvider()
@ -314,212 +278,266 @@ struct ContentView: View {
.background(Color(red: 0.1, green: 0.1, blue: 0.1)) .background(Color(red: 0.1, green: 0.1, blue: 0.1))
.frame(alignment: .topLeading) .frame(alignment: .topLeading)
VStack { VStack {
NaviBar(paneConnector: paneConnector) ScrollViewReader { proxy in
StatsPanel(paneConnector: paneConnector) VisibilityTrackingScrollView(action: handleVisibilityChanged) {
.offset(y:20) // ScrollView {
}
// .frame(maxWidth: 300)
.offset(x: geometry.size.width - 300)
VStack { LazyVStack {
// Top pane ForEach(segs) { seg in
SegRow(seg: seg,
ribbonId: selectedRibbon[0].id!)
.id("\(seg.id)")
.offset(x: -dragOffset)
// .offset(x: pulledOut.width)
Pane(paneConnector: paneConnector, .padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
selectedRibbon: selectedRibbon, .trackVisibility(id: "\(seg.id)")
width: geometry.size.width - 15,
height: geometry.size.height + 20,
dragOffset: dragOffset)
///////////////////////////////////
// Text("separator").foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
// .gesture(
// DragGesture()
// .onChanged { gesture in
// paneConnector.vertSep = paneConnector.vertSep - gesture.translation.height
// }
// )
// // Bottom pane
// 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)")
// }
// }
// .background(Color(red: 0.18, green: 0.18, blue: 0.18))
// }
// .onAppear {
// Print("APPEAR")
// }
// .listStyle(PlainListStyle())
// }
// .zIndex(1)
// .background(Color(red: 0.2, green: 0.2, blue: 0.2))
///////////////////////////////////
}
.offset(x: 20, y: 0)
.offset(x: pulledOut.width)
.offset(x: mainSwipe.width)
.gesture(
DragGesture()
.onChanged { value in
// Calculate the offset
let margin = CGFloat(30)
var newOffset = value.translation.width
if startSwipeState == nil {
if pulledOut.width == 0 {
startSwipeState = .center
} else if pulledOut.width < 0 {
startSwipeState = .left
} else {
startSwipeState = .right
}
print("start swipe meow: \(startSwipeState)")
}
if newOffset > 0 {
startSwipeDir = .right
} else {
startSwipeDir = .left
}
// Apply resistance if out of bounds
var maxOffsetRight: CGFloat = 110
var maxOffsetLeft: CGFloat = 200
if startSwipeState == .right {
if startSwipeDir == .right {
maxOffsetRight = .zero
maxOffsetLeft = .zero
} else if startSwipeDir == .left {
maxOffsetRight = CGFloat(110)
maxOffsetLeft = CGFloat(-30)
}
} else if startSwipeState == .left {
if startSwipeDir == .left {
maxOffsetLeft = .zero
maxOffsetRight = .zero
} else if startSwipeDir == .right {
maxOffsetLeft = CGFloat(200)
maxOffsetRight = CGFloat(10)
} }
} }
.background(Color(red: 0.18, green: 0.18, blue: 0.18))
}
if newOffset + pulledOut.width < -maxOffsetLeft { .onAppear {
if startSwipeState == .right && startSwipeDir == .left { Print("APPEAR")
newOffset = -maxOffsetLeft + rubberBandEffect(newOffset + maxOffsetLeft) - pulledOut.width // Print(selectedRibbon[0])
} else { // scrollId = "3"
newOffset = -maxOffsetLeft + rubberBandEffect(newOffset + maxOffsetLeft) // 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() + 1) {
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!
// }
}
} }
} else if newOffset + pulledOut.width > maxOffsetRight {
if startSwipeState == .left, startSwipeDir == .right {
newOffset = maxOffsetRight + rubberBandEffect(newOffset - maxOffsetRight) - pulledOut.width
} else {
newOffset = maxOffsetRight + rubberBandEffect(newOffset - maxOffsetRight)
}
}
self.mainSwipe.width = newOffset
// dragOffset is what is used to make the text be readable
// with the right pane being visible
// if mainSwipe.width < -margin && pulledOut.width <= 0 {
if mainSwipe.width < -margin && pulledOut.width <= 0 {
dragOffset = margin + mainSwipe.width + pulledOut.width
}
if mainSwipe.width > 0 && pulledOut.width < 0 {
dragOffset = margin + mainSwipe.width + pulledOut.width
} }
} }
.onEnded { _ in .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in Print("introspect")
var finalSwipe = CGFloat(0) if setScrollOffset != nil {
let swipeLeftFinal = CGFloat(-200) DispatchQueue.main.async {
let swipeRightFinal = CGFloat(110) scrollView.contentOffset.y = scrollView.contentOffset.y + setScrollOffset!
setScrollOffset = nil
let margin = CGFloat(30) // self.showOverlay = false
var setDragOffset = CGFloat(0) withAnimation {
showOverlay = false
if startSwipeState == .center { }
if startSwipeDir == .right {
finalSwipe = swipeRightFinal
} else {
finalSwipe = swipeLeftFinal
setDragOffset = margin + swipeLeftFinal
}
} else if startSwipeState == .right {
finalSwipe = .zero
if startSwipeDir == .left {
finalSwipe = .zero
} else {
finalSwipe = swipeRightFinal
}
} else if startSwipeState == .left {
if startSwipeDir == .left {
finalSwipe = swipeLeftFinal
setDragOffset = margin + swipeLeftFinal
} else {
finalSwipe = .zero
} }
} }
startSwipeState = nil Print("end introspect")
startSwipeDir = nil }
.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)
print("foo") Text("separator").foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.gesture(
DragGesture()
.onChanged { gesture in
// if mainSwipe.width < 0 && pulledOut.width > 0 { vertSep = vertSep - gesture.translation.height
// setPulledOutWith = CGFloat(0) Print(gesture.translation.width)
// } else if mainSwipe.width > 0 && pulledOut.width < 0 { Print(gesture.translation.height)
// setPulledOutWith = CGFloat(0)
// } else if (mainSwipe.width < 0 && pulledOut.width < 0) || Print("drag")
// (mainSwipe.width < 0 && pulledOut.width == 0) {
// setPulledOutWith = pulledOutRight // if (endedDrag) {
// setDragOffset = margin + setPulledOutWith // endedDrag = false
// } else if abs(mainSwipe.width + pulledOut.width) > 30 { // scrollOffset = readOffset.y - 20
// setPulledOutWith = pulledOutLeft // // _ = 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")
}
.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
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)) { withAnimation(.spring(response: 0.2)) {
pulledOut.width = finalSwipe pulledOut.width = pulledOutWidth
dragOffset = setDragOffset viewState = .zero
mainSwipe = .zero dragOffset = .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)
}
} }
} }
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
} }
func handleVisibilityChanged2(_: String, change _: VisibilityChange, tracker _: VisibilityTracker<String>) {} func handleVisibilityChanged2(_: String, change _: VisibilityChange, tracker _: VisibilityTracker<String>) {}
func rubberBandEffect(_ offset: CGFloat) -> CGFloat { func handleVisibilityChanged(_: String, change _: VisibilityChange, tracker: VisibilityTracker<String>) {
let resistance: CGFloat = 0.55 // var printRate: Int64 = 10
return resistance * pow(abs(offset), 0.7) * (offset < 0 ? -1 : 1) gTracker = tracker
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!]!
} }
} }
@ -620,7 +638,6 @@ struct ContentView_Previews: PreviewProvider {
} }
extension View { extension View {
@discardableResult
func Print(_ vars: Any...) -> some View { func Print(_ vars: Any...) -> some View {
for v in vars { for v in vars {
print(v) print(v)

View File

@ -1,17 +1,39 @@
import GRDB import GRDB
/// The Line struct. /// The Line struct.
///
/// Identifiable conformance supports SwiftUI list animations, and type-safe
/// GRDB primary key methods.
/// Equatable conformance supports tests.
struct Line: Identifiable, Equatable { struct Line: Identifiable, Equatable {
/// The player id.
///
/// Int64 is the recommended type for auto-incremented database ids.
/// Use nil for players that are not inserted yet in the database.
var id: Int64? var id: Int64?
var chap: Int var chap: Int
var line_id: Int // this is a line_id per book
var verse: Int var verse: Int
var body: String var body: String
var book: String var book: String
} }
extension Line { extension Line {
private static let books = [ private static let books = [
"John", "Matthew", "Imitation of Christ"] "John", "Matthew", "Imitation of Christ"]
/// Creates a new player with empty name and zero score
// static func new() -> Line {
// Line(id: nil, chap: 1, body: "")
// }
/// Returns a random score
static func randomScore() -> Int {
10 * Int.random(in: 0...100)
}
static func randomBook() -> String {
books.randomElement()!
}
} }
// MARK: - Persistence // MARK: - Persistence

View File

@ -49,12 +49,11 @@ struct LineRequest: Queryable {
// This method is not required by Queryable, but it makes it easier // This method is not required by Queryable, but it makes it easier
// to test LineRequest. // to test LineRequest.
func fetchValue(_ db: Database) throws -> [Line] { func fetchValue(_ db: Database) throws -> [Line] {
return try Line.filter(bookColumn == book).fetchAll(db) if book == "" {
// if book == "" { return try Line.filter(bookColumn == Line.randomBook()).fetchAll(db)
// return try Line.filter(bookColumn == Line.randomBook()).fetchAll(db) } else {
// } else { return try Line.filter(bookColumn == book).fetchAll(db)
// return try Line.filter(bookColumn == book).fetchAll(db) }
// }
// switch ordering { // switch ordering {
// case .byScore: // case .byScore:
// return try Line.all().fetchAll(db) // return try Line.all().fetchAll(db)

View File

@ -40,7 +40,6 @@ extension AppDatabase {
// // demo purpose. // // demo purpose.
// try appDatabase.createRandomPlayersIfEmpty() // try appDatabase.createRandomPlayersIfEmpty()
// } // }
print("initing database")
try appDatabase.initDatabase() try appDatabase.initDatabase()

View File

@ -17,12 +17,7 @@ struct Ribbon: Identifiable, Equatable {
/// Int64 is the recommended type for auto-incremented database ids. /// Int64 is the recommended type for auto-incremented database ids.
/// Use nil for players that are not inserted yet in the database. /// Use nil for players that are not inserted yet in the database.
var id: Int64? var id: Int64?
var groupId: Int
var pos: Int var pos: Int
var undoLevel: Int
var currentLevel: Int
var minLevel: Int
var maxLevel: Int
var title: String var title: String
var book: String var book: String
var scrollId: String var scrollId: String
@ -32,6 +27,7 @@ struct Ribbon: Identifiable, Equatable {
extension Ribbon { extension Ribbon {
} }
// MARK: - Persistence
/// Make Line a Codable Record. /// Make Line a Codable Record.
/// ///

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long