feat: Ipad app production readiness, Colony orchestration, Social posting
All checks were successful
Production Readiness / backend-contracts (pull_request) Successful in 3m19s
Production Readiness / webos-typecheck (pull_request) Successful in 2m38s
Production Readiness / ipad-parse (pull_request) Successful in 1m44s

This commit is contained in:
Sayan Datta
2026-05-03 18:28:04 +05:30
parent acfc602157
commit 6c93e31741
86 changed files with 20349 additions and 1655 deletions

View File

@@ -3,6 +3,7 @@ import CoreLocation
import CoreMotion
import SceneKit
import SwiftUI
import UIKit
// MARK: - ARSunOverlayView
@@ -22,6 +23,13 @@ struct ARSunOverlayView: UIViewRepresentable {
let config = ARWorldTrackingConfiguration()
config.worldAlignment = .gravityAndHeading // north = -Z axis
config.planeDetection = [.horizontal, .vertical]
if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) {
config.sceneReconstruction = .mesh
}
if ARWorldTrackingConfiguration.supportsFrameSemantics(.sceneDepth) {
config.frameSemantics.insert(.sceneDepth)
}
view.session.run(config)
context.coordinator.attach(to: view)
@@ -46,7 +54,9 @@ struct ARSunOverlayView: UIViewRepresentable {
// Scene node containers (replaced on each rebuild)
private var arcRootNode = SCNNode()
private var currentSunNode = SCNNode()
private var measurementRootNode = SCNNode()
private var isSceneBuilt = false
private var pendingMeasurementPoint: SCNVector3?
// Fallback timer for CoreMotion-only mode
private var fallbackTimer: Timer?
@@ -61,6 +71,10 @@ struct ARSunOverlayView: UIViewRepresentable {
self.sceneView = sceneView
sceneView.scene.rootNode.addChildNode(arcRootNode)
sceneView.scene.rootNode.addChildNode(currentSunNode)
sceneView.scene.rootNode.addChildNode(measurementRootNode)
let tap = UITapGestureRecognizer(target: self, action: #selector(handleMeasurementTap(_:)))
sceneView.addGestureRecognizer(tap)
}
func stop() {
@@ -107,6 +121,59 @@ struct ARSunOverlayView: UIViewRepresentable {
}
}
// MARK: - Measurement
@objc private func handleMeasurementTap(_ recognizer: UITapGestureRecognizer) {
guard let sceneView else { return }
let point = recognizer.location(in: sceneView)
guard let query = sceneView.raycastQuery(
from: point,
allowing: .estimatedPlane,
alignment: .any
),
let result = sceneView.session.raycast(query).first else { return }
let transform = result.worldTransform
let worldPoint = SCNVector3(transform.columns.3.x, transform.columns.3.y, transform.columns.3.z)
addMeasurementPoint(worldPoint)
}
private func addMeasurementPoint(_ point: SCNVector3) {
measurementRootNode.addChildNode(makeMeasurementMarker(at: point))
if let start = pendingMeasurementPoint {
let distance = start.distance(to: point)
measurementRootNode.addChildNode(makeLineNode(through: [start, point], color: UIColor.white.withAlphaComponent(0.82)))
let midpoint = SCNVector3(
(start.x + point.x) / 2,
(start.y + point.y) / 2 + 0.045,
(start.z + point.z) / 2
)
let label = makeTextNode(
text: "\(String(format: "%.2f m", Double(distance))) \(String(format: "%.1f ft", Double(distance * 3.28084)))",
color: .white,
fontSize: 0.052
)
label.position = midpoint
measurementRootNode.addChildNode(label)
pendingMeasurementPoint = nil
UIImpactFeedbackGenerator(style: .rigid).impactOccurred()
} else {
pendingMeasurementPoint = point
UIImpactFeedbackGenerator(style: .soft).impactOccurred()
}
}
private func makeMeasurementMarker(at position: SCNVector3) -> SCNNode {
let sphere = SCNSphere(radius: 0.018)
sphere.firstMaterial?.diffuse.contents = UIColor.white
sphere.firstMaterial?.emission.contents = UIColor.systemBlue.withAlphaComponent(0.65)
sphere.firstMaterial?.lightingModel = .constant
let node = SCNNode(geometry: sphere)
node.position = position
return node
}
// MARK: - Scene Building
private func buildScene() {
@@ -274,3 +341,12 @@ struct ARSunOverlayView: UIViewRepresentable {
private extension Double {
var radians: Double { self * .pi / 180.0 }
}
private extension SCNVector3 {
func distance(to other: SCNVector3) -> Float {
let dx = other.x - x
let dy = other.y - y
let dz = other.z - z
return sqrtf(dx * dx + dy * dy + dz * dz)
}
}