made some changes
This commit is contained in:
parent
4ad926722f
commit
1c3f4bd74e
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:FutureFlow">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:FutureFlowDemo/FutureFlowDemo.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,33 @@
|
|||
// swift-tools-version: 5.8
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "FutureFlow",
|
||||
platforms: [
|
||||
.iOS(.v14),
|
||||
.macOS(.v11),
|
||||
.tvOS(.v14),
|
||||
.watchOS(.v7)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "FutureFlow",
|
||||
targets: ["FutureFlow"]
|
||||
),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "FutureFlow",
|
||||
dependencies: [],
|
||||
path: "Sources"
|
||||
),
|
||||
.testTarget(
|
||||
name: "FutureFlowTests",
|
||||
dependencies: ["FutureFlow"],
|
||||
path: "Tests/FutureFlowTests"
|
||||
),
|
||||
],
|
||||
swiftLanguageVersions: [.v5]
|
||||
)
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// BlurView.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
#if os(iOS)
|
||||
import SwiftUI
|
||||
|
||||
internal struct BlurView: UIViewRepresentable {
|
||||
private var style: UIBlurEffect.Style
|
||||
|
||||
internal init(style: UIBlurEffect.Style) {
|
||||
self.style = style
|
||||
}
|
||||
|
||||
internal func makeUIView(context: Context) -> UIVisualEffectView {
|
||||
let view = UIVisualEffectView(effect: UIBlurEffect(style: style))
|
||||
return view
|
||||
}
|
||||
|
||||
internal func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
|
||||
uiView.effect = UIBlurEffect(style: style)
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// View.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Public API for FlowChunk ONLY
|
||||
public extension View {
|
||||
/// Prepares the current view to be highlighted by the spotlight effect, associating it with the specified `FlowChunk`.
|
||||
///
|
||||
/// This function should be used to mark individual child views within a parent view that has the `assembleSpotlightChunks` function applied to it.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - parentIdentifier: A unique string identifier for the parent view containing the spotlight effect.
|
||||
/// - chunk: The `FlowChunk` associated with the current view, which determines the spotlight shape, background, and other properties.
|
||||
///
|
||||
/// - Returns: The modified view with the matched geometry effect applied, allowing it to be highlighted by the spotlight effect.
|
||||
func configureChunkForSpotlight<Chunk: FlowChunk>(parentIdentifier: String, chunk: Chunk) -> some View {
|
||||
let namespace = getNamespace(from: parentIdentifier)
|
||||
|
||||
return self
|
||||
.matchedGeometryEffect(
|
||||
id: chunk.id,
|
||||
in: namespace,
|
||||
properties: .frame,
|
||||
anchor: .center,
|
||||
isSource: true
|
||||
)
|
||||
}
|
||||
|
||||
/// Sets up the parent view to contain the spotlight effect, using the provided `FlowChunk` instances.
|
||||
///
|
||||
/// This function should be used to wrap the parent view containing child views that have the `configureChunkForSpotlight` function applied to them.
|
||||
///
|
||||
/// The chunks provided must be of the same `FlowChunk` type as the one used by the child views, to ensure that the spotlight effect works as intended.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - uniqueIdentifier: A unique string identifier for the parent view. This identifier must be the same as the one provided to the `configureChunkForSpotlight` function for child views.
|
||||
/// - chunks: An array of `FlowChunk` instances associated with the child views to be highlighted by the spotlight effect.
|
||||
///
|
||||
/// - Returns: The modified view with the `HighlightingView` applied, containing the spotlight effect and its child views.
|
||||
func assembleSpotlightChunks<Chunk: FlowChunk>(uniqueIdentifier: String, chunks: [Chunk]) -> some View {
|
||||
let namespace = getNamespace(from: uniqueIdentifier)
|
||||
|
||||
return HighlightingView(
|
||||
namespace: namespace,
|
||||
showTutorial: .constant(true),
|
||||
chunks: chunks
|
||||
) {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
func convertToInstructionsView(position: InstructionsViewPosition) -> InstructionsView {
|
||||
InstructionsView(position: position) {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpful public extensions.
|
||||
/// These are core and not related to FlowChunk directly.
|
||||
public extension View {
|
||||
func eraseToAnyView() -> AnyView {
|
||||
AnyView(
|
||||
self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Helper Methods
|
||||
fileprivate extension View {
|
||||
func getNamespace(from identifier: String) -> Namespace.ID {
|
||||
if let existingNamespace = FutureFlowManager.currentNamespaces[identifier] {
|
||||
return existingNamespace
|
||||
} else {
|
||||
let newNamespace = Namespace().wrappedValue
|
||||
FutureFlowManager.currentNamespaces[identifier] = newNamespace
|
||||
return newNamespace
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// FlowChunk.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
public protocol FlowChunk: Hashable, Identifiable {
|
||||
var spotlightShape: SpotlightShape { get }
|
||||
var spotlightBackground: SpotlightBackground { get }
|
||||
|
||||
var instructionsViewType: InstructionsViewType? { get }
|
||||
}
|
||||
|
||||
public extension FlowChunk {
|
||||
var id: Int {
|
||||
self.hashValue
|
||||
}
|
||||
|
||||
var spotlightShape: SpotlightShape {
|
||||
return .rectangle()
|
||||
}
|
||||
|
||||
var spotlightBackground: SpotlightBackground {
|
||||
return .black
|
||||
}
|
||||
|
||||
var instructionsViewType: InstructionsViewType? {
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// FutureFlowManager.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
internal class FutureFlowManager {
|
||||
internal static var currentNamespaces: [String:Namespace.ID] = [:]
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
//
|
||||
// HighlightingView.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
internal struct HighlightingView<Content: View, Chunk: FlowChunk>: View {
|
||||
// Binding variables
|
||||
@Binding var showTutorial: Bool
|
||||
|
||||
// Private variables
|
||||
let namespace: Namespace.ID
|
||||
let chunks: [Chunk]
|
||||
let content: Content
|
||||
|
||||
#if DEBUG
|
||||
// State variables (TODO: Delete)
|
||||
@State private var currentIndex: Int = 0
|
||||
#endif
|
||||
|
||||
@Namespace private var namespace2
|
||||
|
||||
internal init(namespace: Namespace.ID, showTutorial: Binding<Bool>, chunks: [Chunk], @ViewBuilder content: () -> Content) {
|
||||
self.namespace = namespace
|
||||
self._showTutorial = showTutorial
|
||||
self.chunks = chunks
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
internal var body: some View {
|
||||
ZStack {
|
||||
self.content
|
||||
|
||||
SpotlightView(
|
||||
chunk: self.chunks[self.currentIndex],
|
||||
namespace: self.namespace,
|
||||
namespace2: self.namespace2
|
||||
)
|
||||
.opacity(self.showTutorial ? 1 : 0)
|
||||
.animation(
|
||||
.easeOut,
|
||||
value: self.showTutorial ? self.currentIndex : nil
|
||||
)
|
||||
.overlay(
|
||||
GeometryReader { reader in
|
||||
instructionsOverlay(reader: reader)
|
||||
.animation(.easeOut, value: self.showTutorial ? self.currentIndex : nil)
|
||||
// Text("\(reader.size.width) X \(reader.size.height)")
|
||||
// ZStack {
|
||||
// Color.blue
|
||||
// }
|
||||
}
|
||||
.matchedGeometryEffect(id: 10000, in: self.namespace2, isSource: false)
|
||||
// .overlay(
|
||||
// GeometryReader { reader in
|
||||
// Text("\(reader.size.width) X \(reader.size.height)")
|
||||
// }
|
||||
// )
|
||||
)
|
||||
|
||||
|
||||
//#if DEBUG
|
||||
// Button(action: {
|
||||
// if self.currentIndex < self.chunks.count - 1{
|
||||
// self.currentIndex += 1
|
||||
// } else {
|
||||
// self.currentIndex = 0
|
||||
// }
|
||||
// }) {
|
||||
// Text("NEXT")
|
||||
// }
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension HighlightingView {
|
||||
func advance() {
|
||||
if self.currentIndex < self.chunks.count - 1{
|
||||
self.currentIndex += 1
|
||||
} else {
|
||||
self.currentIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
func previous() {
|
||||
if self.currentIndex > 0 {
|
||||
self.currentIndex -= 1
|
||||
} else {
|
||||
self.currentIndex = self.chunks.count - 1
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder func instructionsOverlay(reader: GeometryProxy) -> some View {
|
||||
if let instructionsViewType = self.chunks[self.currentIndex].instructionsViewType {
|
||||
let v = instructionsViewType
|
||||
.body(
|
||||
currentIndex: self.$currentIndex,
|
||||
maxCount: self.chunks.count,
|
||||
advance: self.advance,
|
||||
previous: self.previous
|
||||
)
|
||||
ZStack {
|
||||
// TODO: Find a better way than this hacky method
|
||||
v
|
||||
.opacity(0)
|
||||
}
|
||||
.overlay(
|
||||
GeometryReader { rr in
|
||||
v
|
||||
.frame(width: UIScreen.main.bounds.size.width)
|
||||
.offset(
|
||||
x: -(UIScreen.main.bounds.size.width - reader.size.width) / 2,
|
||||
y: self.getYOffset(position: v.position, in: v.position == .below ? reader.size : rr.size)
|
||||
)
|
||||
}
|
||||
|
||||
)
|
||||
// v
|
||||
// .overlay(
|
||||
// Text("\(reader.size.height)").allowsHitTesting(false))
|
||||
|
||||
// .offset(
|
||||
// x: -(UIScreen.main.bounds.size.width - reader.size.width) / 2,
|
||||
// y: self.getYOffset(position: v.position, in: reader.size)
|
||||
// )
|
||||
|
||||
// y: self.getYOffset(position: v.position, in: reader.size)
|
||||
// )
|
||||
}
|
||||
// ZStack {
|
||||
|
||||
// if let sle
|
||||
|
||||
// if(self.chunks[self.currentIndex].instruction != nil) {
|
||||
// SimpleInstructionsBubble(text: "TEST")
|
||||
// .frame(width: 200, height: 100, alignment: .center)
|
||||
// self.chunks[self.currentIndex].instruction!.bubble.body(instruction: self.chunks[self.currentIndex].instruction!)
|
||||
// }
|
||||
// .offset(x: 0, y: reader.size.height + 20)
|
||||
|
||||
// if let instruction = self.chunks[self.currentIndex].instruction {
|
||||
// self
|
||||
// .chunks[self.currentIndex]
|
||||
// .instructionsViewType!
|
||||
//// .inWithEnum()
|
||||
// .body(adv: self.advance, prev: self.previous)
|
||||
// .instructionsView(advance: self.advance, previous: self.previous)
|
||||
// instruction.bubble.body(instruction: instruction)
|
||||
// .padding(.horizontal, 15)
|
||||
// .frame(width: UIScreen.main.bounds.size.width)
|
||||
//// .offset(x: 0, y: 400)
|
||||
// .offset(
|
||||
// x: -(UIScreen.main.bounds.size.width - reader.size.width) / 2,
|
||||
// y: self.getYOffset(position: instruction.position, in: reader.size)
|
||||
// )
|
||||
// }
|
||||
|
||||
// if (self.chunk.instructionsBubble != nil) {
|
||||
// self.chunk.instructionsBubble!.body
|
||||
// .padding(.horizontal)
|
||||
// .frame(width: UIScreen.main.bounds.size.width)
|
||||
// .offset(x: 0, y: self.getYOffset(position: self.chunk.instructionsBubble!.position, in: reader.size))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
func getYOffset(position: InstructionsViewPosition, in frame: CGSize) -> CGFloat {
|
||||
switch position {
|
||||
case .above:
|
||||
return -(frame.height + 20)
|
||||
default:
|
||||
return (frame.height + 20)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// InstructionsView.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
public struct InstructionsView : View {
|
||||
internal let position: InstructionsViewPosition
|
||||
private let content: AnyView
|
||||
|
||||
internal init<Content: View>
|
||||
(
|
||||
position: InstructionsViewPosition = .below,
|
||||
@ViewBuilder _ content: () -> Content
|
||||
) {
|
||||
self.position = position
|
||||
self.content = content().eraseToAnyView()
|
||||
}
|
||||
|
||||
@_spi(Private)
|
||||
public var body: some View {
|
||||
self.content
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// InstructionsViewPosition.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
public enum InstructionsViewPosition {
|
||||
case above
|
||||
case below
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
//
|
||||
// InstructionsViewType.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/26/23.
|
||||
//
|
||||
|
||||
public enum InstructionsViewType {
|
||||
case simple(instructions: [String], position: InstructionsViewPosition = .below)
|
||||
case custom(view: (_ advance: @escaping () -> (), _ previous: @escaping () -> ()) -> InstructionsView)
|
||||
|
||||
internal func body(
|
||||
currentIndex: Binding<Int>,
|
||||
maxCount: Int,
|
||||
advance: @escaping () -> (),
|
||||
previous: @escaping () -> ()
|
||||
) -> InstructionsView {
|
||||
switch self {
|
||||
case .simple(let instructions, let position):
|
||||
return SimpleInstructionsViewWrapper(currentGlobalIndex: currentIndex,
|
||||
globalMaxCount: maxCount,
|
||||
advance: advance,
|
||||
previous: previous,
|
||||
instructions: instructions)
|
||||
.convertToInstructionsView(position: position)
|
||||
case .custom(let view):
|
||||
return view(advance, previous)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rework this piece
|
||||
import SwiftUI
|
||||
|
||||
internal struct SimpleInstructionsViewWrapper: View {
|
||||
// Global instructions
|
||||
@Binding var currentGlobalIndex: Int
|
||||
var globalMaxCount: Int
|
||||
let advance: () -> ()
|
||||
let previous: () -> ()
|
||||
|
||||
private(set) var instructions: [String]
|
||||
@State private var currentInstructionIndex: Int = 0
|
||||
@State private var showPrevious: Bool = false
|
||||
@State private var showNext: Bool = false
|
||||
|
||||
var body: some View {
|
||||
SimpleInstructionsView(
|
||||
text: self.instructions[self.currentInstructionIndex],
|
||||
showPrevious: .init (
|
||||
get: {
|
||||
return (self.currentGlobalIndex > 0 && self.globalMaxCount > 0) || (self.currentInstructionIndex > 0 && self.instructions.count > 0)
|
||||
},
|
||||
set: { _ in}
|
||||
),
|
||||
showNext: .init(
|
||||
get: {
|
||||
return self.currentInstructionIndex < instructions.count - 1 || self.currentGlobalIndex < self.globalMaxCount - 1
|
||||
},
|
||||
set: { _ in }
|
||||
)
|
||||
)
|
||||
.onTapNext {
|
||||
guard currentInstructionIndex == instructions.count - 1 else {
|
||||
currentInstructionIndex += 1
|
||||
return
|
||||
}
|
||||
|
||||
advance()
|
||||
self.currentInstructionIndex = 0
|
||||
}
|
||||
.onTapPrev {
|
||||
guard currentInstructionIndex == 0 else {
|
||||
currentInstructionIndex -= 1
|
||||
return
|
||||
}
|
||||
// guard self.currentInstructionIndex > 0 else {
|
||||
// return
|
||||
// }
|
||||
// self.currentInstructionIndex -= 1
|
||||
self.currentInstructionIndex = 0
|
||||
previous()
|
||||
// self.currentInstructionIndex = instructions.count
|
||||
|
||||
}
|
||||
.overlay(
|
||||
VStack {
|
||||
Text("\(self.globalMaxCount)")
|
||||
Text("\(self.currentGlobalIndex)")
|
||||
Text("\(self.instructions.count)")
|
||||
Text("\(self.currentInstructionIndex)")
|
||||
}
|
||||
.offset(x: 0, y: 100)
|
||||
)
|
||||
.padding(.horizontal, 15)
|
||||
// .onChange(of: self.currentInstructionIndex, perform: { newValue in
|
||||
// // For the next button
|
||||
// if(newValue < instructions.count - 1 || currentGlobalIndex < globalMaxCount - 1) {
|
||||
// self.showNext = true
|
||||
// } else {
|
||||
// self.showNext = false
|
||||
// }
|
||||
//
|
||||
// if(newValue > 0 && self.instructions.count > 0) {
|
||||
// self.showPrevious = true
|
||||
// } else {
|
||||
// self.showPrevious = false
|
||||
// }
|
||||
// })
|
||||
.onAppear {
|
||||
// Next
|
||||
if(currentInstructionIndex < instructions.count - 1 || currentGlobalIndex < globalMaxCount) {
|
||||
self.showNext = true
|
||||
} else {
|
||||
self.showNext = false
|
||||
}
|
||||
// if(currentInstructionIndex < instructions.count - 1) {
|
||||
// self.showNext = true
|
||||
// } else {
|
||||
// self.showNext = false
|
||||
// }
|
||||
//
|
||||
if(currentInstructionIndex > 0 && self.instructions.count > 0) {
|
||||
self.showPrevious = true
|
||||
} else {
|
||||
self.showPrevious = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct SimpleInstructionsViewWrapper_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// SimpleInstructionsViewWrapper(instructions: ["Hello", "World", "askdlfjalk shfjlka dhfkj ahsdfkhdj"])
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,146 @@
|
|||
//
|
||||
// SimpleInstructionsView.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SimpleInstructionsView: View {
|
||||
private var text: String
|
||||
private var nextTapped: () -> ()
|
||||
private var prevTapped: () -> ()
|
||||
|
||||
@Binding var showPrevious: Bool
|
||||
@Binding var showNext: Bool
|
||||
|
||||
public init(
|
||||
text: String,
|
||||
showPrevious: Binding<Bool> = .constant(false),
|
||||
showNext: Binding<Bool> = .constant(false)
|
||||
) {
|
||||
self.text = text
|
||||
self.nextTapped = { }
|
||||
self.prevTapped = { }
|
||||
self._showPrevious = showPrevious
|
||||
self._showNext = showNext
|
||||
}
|
||||
|
||||
fileprivate init(
|
||||
text: String,
|
||||
nextTapped: @escaping () -> (),
|
||||
prevTapped: @escaping () -> (),
|
||||
showPrevious: Binding<Bool> = .constant(false),
|
||||
showNext: Binding<Bool> = .constant(false)
|
||||
) {
|
||||
self.text = text
|
||||
self.nextTapped = nextTapped
|
||||
self.prevTapped = prevTapped
|
||||
self._showPrevious = showPrevious
|
||||
self._showNext = showNext
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
// Color.purple
|
||||
VStack(alignment:.leading, spacing: 20) {
|
||||
HStack(alignment: .top, spacing: 10) {
|
||||
Image(systemName: "lightbulb.circle.fill")
|
||||
.font(.system(size: 32))
|
||||
.foregroundColor(.blue)
|
||||
|
||||
Text(self.text)
|
||||
.font(.body)
|
||||
}
|
||||
|
||||
if (self.showPrevious || self.showNext) {
|
||||
HStack(alignment: .center, spacing:15) {
|
||||
Spacer()
|
||||
if(self.showPrevious) {
|
||||
Button(action: {
|
||||
self.prevTapped()
|
||||
}) {
|
||||
Text("Previous")
|
||||
.font(.callout)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
}
|
||||
|
||||
if(self.showNext) {
|
||||
|
||||
Button(action: {
|
||||
self.nextTapped()
|
||||
}) {
|
||||
Text("Next")
|
||||
.font(.callout)
|
||||
.fontWeight(.semibold)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 5)
|
||||
.background(Color.blue)
|
||||
.cornerRadius(3)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 15)
|
||||
.background(Color.white)
|
||||
.cornerRadius(10)
|
||||
.shadow(color: .black.opacity(0.2), radius: 5, x: 0, y: 0)
|
||||
}
|
||||
|
||||
func onTapNext(_ callback: @escaping () -> ()) -> Self {
|
||||
return .init(
|
||||
text: self.text,
|
||||
nextTapped: callback,
|
||||
prevTapped: self.prevTapped,
|
||||
showPrevious: self.$showPrevious,
|
||||
showNext: self.$showNext
|
||||
)
|
||||
}
|
||||
|
||||
func onTapPrev(_ callback: @escaping () -> ()) -> Self {
|
||||
return .init(
|
||||
text: self.text,
|
||||
nextTapped: self.nextTapped,
|
||||
prevTapped: callback,
|
||||
showPrevious: self.$showPrevious,
|
||||
showNext: self.$showNext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct SimpleInstructionsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ZStack {
|
||||
Color.white
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
|
||||
VStack(spacing: 5) {
|
||||
SimpleInstructionsView(text: "This is just a tutorial asjdkfhla sdfhlakjsd hflkajsd hflkjasdhf lkjasdhf kljasd lajsdfh lkjsdhf lakjsdhf akjsl hfakjsd hadffajsdkfhlkajs hflkjas hfklja hsdjkfl haljskd fhljasdfhlaksd hflas dhfklj asdh fljasdlfjsdhfl.")
|
||||
|
||||
SimpleInstructionsView(text: "This is just a tutorial asjdkfhla sdfhlakjsd hflkajsd hflkjasdhf lkjasdhf kljasd lajsdfh lkjsdhf lakjsdhf akjsl hfakjsd hadffajsdkfhlkajs hflkjas hfklja hsdjkfl haljskd fhljasdfhlaksd hflas dhfklj asdh fljasdlfjsdhfl.", showNext: .constant(true))
|
||||
.onTapNext {
|
||||
print("Next Tapped")
|
||||
}
|
||||
|
||||
SimpleInstructionsView(text: "This is just a tutorial asjdkfhla sdfhlakjsd hflkajsd hflkjasdhf lkjasdhf kljasd lajsdfh lkjsdhf lakjsdhf akjsl hfakjsd hadffajsdkfhlkajs hflkjas hfklja hsdjkfl haljskd fhljasdfhlaksd hflas dhfklj asdh fljasdlfjsdhfl.", showPrevious: .constant(true))
|
||||
.onTapPrev {
|
||||
print("Previous Tapped")
|
||||
}
|
||||
|
||||
SimpleInstructionsView(text: "This is just a tutorial asjdkfhla sdfhlakjsd hflkajsd hflkjasdhf lkjasdhf kljasd lajsdfh lkjsdhf lakjsdhf akjsl hfakjsd hadffajsdkfhlkajs hflkjas hfklja hsdjkfl haljskd fhljasdfhlaksd hflas dhfklj asdh fljasdlfjsdhfl.", showPrevious: .constant(true), showNext: .constant(true))
|
||||
.onTapNext {
|
||||
print("Next Tapped")
|
||||
}
|
||||
.onTapPrev {
|
||||
print("Previous Tapped")
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// SpotlightBackground.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
fileprivate let MATCHED_GEOMETRY_ID: Int = 9999
|
||||
|
||||
public enum SpotlightBackground {
|
||||
case ultraThinMaterial
|
||||
|
||||
case black
|
||||
|
||||
case customColor (
|
||||
_ color: Color,
|
||||
opacity: CGFloat = 0.5
|
||||
)
|
||||
|
||||
case custom(
|
||||
view: () -> AnyView
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Internal API
|
||||
internal extension SpotlightBackground {
|
||||
func body(_ namespace: Namespace.ID) -> some View {
|
||||
ZStack {
|
||||
switch self {
|
||||
case .ultraThinMaterial:
|
||||
self.defaultUltraThinMaterial(namespace)
|
||||
case .black:
|
||||
self.defaultBlackBackground(namespace)
|
||||
|
||||
case .customColor(let color, let opacity):
|
||||
self.defaultCustomColorBackground(namespace, color: color, opacity: opacity)
|
||||
|
||||
case .custom(let av):
|
||||
av()
|
||||
.matchedGeometryEffect(id: MATCHED_GEOMETRY_ID,
|
||||
in: namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Default Backgrounds
|
||||
private extension SpotlightBackground {
|
||||
func defaultUltraThinMaterial(_ namespace: Namespace.ID) -> some View {
|
||||
if #available(iOS 15, macOS 12, *) {
|
||||
return Color.clear
|
||||
.matchedGeometryEffect(id: MATCHED_GEOMETRY_ID,
|
||||
in: namespace)
|
||||
.background(.ultraThinMaterial)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
} else {
|
||||
#if os(iOS)
|
||||
return BlurView(style: .extraLight)
|
||||
#else
|
||||
return self.defaultBlackBackground(namespace)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
func defaultBlackBackground(_ namespace: Namespace.ID) -> some View {
|
||||
return defaultCustomColorBackground(namespace, color: .black, opacity: 0.5)
|
||||
}
|
||||
|
||||
func defaultCustomColorBackground(_ namespace: Namespace.ID, color: Color, opacity: CGFloat) -> some View {
|
||||
color
|
||||
.matchedGeometryEffect(id: MATCHED_GEOMETRY_ID,
|
||||
in: namespace)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.opacity(opacity)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// SpotlightShape.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
fileprivate let MATCHED_GEOMETRY_ID: Int = 9998
|
||||
|
||||
public enum SpotlightShape {
|
||||
case rectangle (
|
||||
color: Color = .white,
|
||||
blurRadius: CGFloat = 1.0
|
||||
)
|
||||
|
||||
case circle (
|
||||
color: Color = .white,
|
||||
blurRadius: CGFloat = 1.0
|
||||
)
|
||||
|
||||
case custom (
|
||||
view: () -> AnyView
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Internal API
|
||||
internal extension SpotlightShape {
|
||||
func body(_ namespace: Namespace.ID) -> some View {
|
||||
ZStack {
|
||||
switch self {
|
||||
case .rectangle(let color, let blurRadius):
|
||||
self.defaultRectangle(namespace, foregroundColor: color, blurRadius: blurRadius)
|
||||
case .circle(let color, let blurRadius):
|
||||
self.defaultCircle(namespace, foregroundColor: color, blurRadius: blurRadius)
|
||||
case .custom(let av):
|
||||
av()
|
||||
.matchedGeometryEffect(id: MATCHED_GEOMETRY_ID,
|
||||
in: namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Default Shapes
|
||||
private extension SpotlightShape {
|
||||
func defaultRectangle(_ namespace: Namespace.ID, foregroundColor: Color, blurRadius: CGFloat) -> some View {
|
||||
Rectangle()
|
||||
.matchedGeometryEffect(id: MATCHED_GEOMETRY_ID,
|
||||
in: namespace)
|
||||
.foregroundColor(foregroundColor)
|
||||
.blur(radius: blurRadius)
|
||||
}
|
||||
|
||||
func defaultCircle(_ namespace: Namespace.ID, foregroundColor: Color, blurRadius: CGFloat) -> some View {
|
||||
Circle()
|
||||
.matchedGeometryEffect(id: MATCHED_GEOMETRY_ID,
|
||||
in: namespace)
|
||||
.foregroundColor(foregroundColor)
|
||||
.blur(radius: blurRadius)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// SpotlightView.swift
|
||||
//
|
||||
//
|
||||
// Created by Muhand Jumah on 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
internal struct SpotlightView<Chunk: FlowChunk>: View {
|
||||
private var chunk: Chunk
|
||||
private var namespace: Namespace.ID
|
||||
private var namespace2: Namespace.ID
|
||||
|
||||
internal init(chunk: Chunk, namespace: Namespace.ID, namespace2: Namespace.ID) {
|
||||
self.chunk = chunk
|
||||
self.namespace = namespace
|
||||
self.namespace2 = namespace2
|
||||
}
|
||||
|
||||
internal var body: some View {
|
||||
ZStack {
|
||||
self.chunk.spotlightBackground.body(self.namespace)
|
||||
|
||||
// GeometryReader { reader in
|
||||
self.chunk.spotlightShape.body(self.namespace)
|
||||
.blendMode(.destinationOut)
|
||||
.matchedGeometryEffect(id: 10000, in: self.namespace2, isSource: true)
|
||||
// .overlay(
|
||||
// instructionsOverlay(reader: reader),
|
||||
// alignment: .top
|
||||
// )
|
||||
// }
|
||||
.matchedGeometryEffect(
|
||||
id: self.chunk.id,
|
||||
in: namespace,
|
||||
properties: .frame, anchor: .center,
|
||||
isSource: false
|
||||
)
|
||||
// .blendMode(.destinationOut)
|
||||
}
|
||||
.compositingGroup()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helper Methods
|
||||
//private extension SpotlightView {
|
||||
// func instructionsOverlay(reader: GeometryProxy) -> some View {
|
||||
// ZStack {
|
||||
// if(self.chunk.instructions.count > 0) {
|
||||
// Text("TEST")
|
||||
// }
|
||||
//// if (self.chunk.instructionsBubble != nil) {
|
||||
//// self.chunk.instructionsBubble!.body
|
||||
//// .padding(.horizontal)
|
||||
//// .frame(width: UIScreen.main.bounds.size.width)
|
||||
//// .offset(x: 0, y: self.getYOffset(position: self.chunk.instructionsBubble!.position, in: reader.size))
|
||||
//// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func getYOffset(position: InstructionsBubblePosition, in frame: CGSize) -> CGFloat {
|
||||
// switch position {
|
||||
// case .above:
|
||||
// return -(frame.height + 20)
|
||||
// default:
|
||||
// return (frame.height + 20)
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,622 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
B69AAB1829F31CF300026789 /* FutureFlowDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69AAB1729F31CF300026789 /* FutureFlowDemoApp.swift */; };
|
||||
B69AAB1A29F31CF300026789 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69AAB1929F31CF300026789 /* ContentView.swift */; };
|
||||
B69AAB1C29F31CF400026789 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B69AAB1B29F31CF400026789 /* Assets.xcassets */; };
|
||||
B69AAB1F29F31CF400026789 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B69AAB1E29F31CF400026789 /* Preview Assets.xcassets */; };
|
||||
B69AAB2929F31CF500026789 /* FutureFlowDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69AAB2829F31CF500026789 /* FutureFlowDemoTests.swift */; };
|
||||
B69AAB3329F31CF500026789 /* FutureFlowDemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69AAB3229F31CF500026789 /* FutureFlowDemoUITests.swift */; };
|
||||
B69AAB3529F31CF500026789 /* FutureFlowDemoUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69AAB3429F31CF500026789 /* FutureFlowDemoUITestsLaunchTests.swift */; };
|
||||
B69AAB4529F31E6700026789 /* FutureFlow in Frameworks */ = {isa = PBXBuildFile; productRef = B69AAB4429F31E6700026789 /* FutureFlow */; };
|
||||
B69AAB4729F42F8900026789 /* Demo2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69AAB4629F42F8900026789 /* Demo2.swift */; };
|
||||
B69AAB4929F44D2A00026789 /* Demo10.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69AAB4829F44D2A00026789 /* Demo10.swift */; };
|
||||
B6C55E9729F5C75200E9E281 /* Demo11.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C55E9629F5C75200E9E281 /* Demo11.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
B69AAB2529F31CF500026789 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B69AAB0C29F31CF300026789 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = B69AAB1329F31CF300026789;
|
||||
remoteInfo = FutureFlowDemo;
|
||||
};
|
||||
B69AAB2F29F31CF500026789 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B69AAB0C29F31CF300026789 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = B69AAB1329F31CF300026789;
|
||||
remoteInfo = FutureFlowDemo;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
B69AAB1429F31CF300026789 /* FutureFlowDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FutureFlowDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B69AAB1729F31CF300026789 /* FutureFlowDemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FutureFlowDemoApp.swift; sourceTree = "<group>"; };
|
||||
B69AAB1929F31CF300026789 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
B69AAB1B29F31CF400026789 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
B69AAB1E29F31CF400026789 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
B69AAB2429F31CF500026789 /* FutureFlowDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FutureFlowDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B69AAB2829F31CF500026789 /* FutureFlowDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FutureFlowDemoTests.swift; sourceTree = "<group>"; };
|
||||
B69AAB2E29F31CF500026789 /* FutureFlowDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FutureFlowDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B69AAB3229F31CF500026789 /* FutureFlowDemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FutureFlowDemoUITests.swift; sourceTree = "<group>"; };
|
||||
B69AAB3429F31CF500026789 /* FutureFlowDemoUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FutureFlowDemoUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||
B69AAB4629F42F8900026789 /* Demo2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Demo2.swift; sourceTree = "<group>"; };
|
||||
B69AAB4829F44D2A00026789 /* Demo10.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Demo10.swift; sourceTree = "<group>"; };
|
||||
B6C55E9629F5C75200E9E281 /* Demo11.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Demo11.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
B69AAB1129F31CF300026789 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B69AAB4529F31E6700026789 /* FutureFlow in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B69AAB2129F31CF500026789 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B69AAB2B29F31CF500026789 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
B69AAB0B29F31CF300026789 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B69AAB1629F31CF300026789 /* FutureFlowDemo */,
|
||||
B69AAB2729F31CF500026789 /* FutureFlowDemoTests */,
|
||||
B69AAB3129F31CF500026789 /* FutureFlowDemoUITests */,
|
||||
B69AAB1529F31CF300026789 /* Products */,
|
||||
B69AAB4329F31E6700026789 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B69AAB1529F31CF300026789 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B69AAB1429F31CF300026789 /* FutureFlowDemo.app */,
|
||||
B69AAB2429F31CF500026789 /* FutureFlowDemoTests.xctest */,
|
||||
B69AAB2E29F31CF500026789 /* FutureFlowDemoUITests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B69AAB1629F31CF300026789 /* FutureFlowDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B69AAB1729F31CF300026789 /* FutureFlowDemoApp.swift */,
|
||||
B69AAB1929F31CF300026789 /* ContentView.swift */,
|
||||
B69AAB4629F42F8900026789 /* Demo2.swift */,
|
||||
B69AAB1D29F31CF400026789 /* Preview Content */,
|
||||
B69AAB1B29F31CF400026789 /* Assets.xcassets */,
|
||||
B69AAB4829F44D2A00026789 /* Demo10.swift */,
|
||||
B6C55E9629F5C75200E9E281 /* Demo11.swift */,
|
||||
);
|
||||
path = FutureFlowDemo;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B69AAB1D29F31CF400026789 /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B69AAB1E29F31CF400026789 /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B69AAB2729F31CF500026789 /* FutureFlowDemoTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B69AAB2829F31CF500026789 /* FutureFlowDemoTests.swift */,
|
||||
);
|
||||
path = FutureFlowDemoTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B69AAB3129F31CF500026789 /* FutureFlowDemoUITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B69AAB3229F31CF500026789 /* FutureFlowDemoUITests.swift */,
|
||||
B69AAB3429F31CF500026789 /* FutureFlowDemoUITestsLaunchTests.swift */,
|
||||
);
|
||||
path = FutureFlowDemoUITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B69AAB4329F31E6700026789 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
B69AAB1329F31CF300026789 /* FutureFlowDemo */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B69AAB3829F31CF500026789 /* Build configuration list for PBXNativeTarget "FutureFlowDemo" */;
|
||||
buildPhases = (
|
||||
B69AAB1029F31CF300026789 /* Sources */,
|
||||
B69AAB1129F31CF300026789 /* Frameworks */,
|
||||
B69AAB1229F31CF300026789 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FutureFlowDemo;
|
||||
packageProductDependencies = (
|
||||
B69AAB4429F31E6700026789 /* FutureFlow */,
|
||||
);
|
||||
productName = FutureFlowDemo;
|
||||
productReference = B69AAB1429F31CF300026789 /* FutureFlowDemo.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
B69AAB2329F31CF500026789 /* FutureFlowDemoTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B69AAB3B29F31CF500026789 /* Build configuration list for PBXNativeTarget "FutureFlowDemoTests" */;
|
||||
buildPhases = (
|
||||
B69AAB2029F31CF500026789 /* Sources */,
|
||||
B69AAB2129F31CF500026789 /* Frameworks */,
|
||||
B69AAB2229F31CF500026789 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
B69AAB2629F31CF500026789 /* PBXTargetDependency */,
|
||||
);
|
||||
name = FutureFlowDemoTests;
|
||||
productName = FutureFlowDemoTests;
|
||||
productReference = B69AAB2429F31CF500026789 /* FutureFlowDemoTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
B69AAB2D29F31CF500026789 /* FutureFlowDemoUITests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B69AAB3E29F31CF500026789 /* Build configuration list for PBXNativeTarget "FutureFlowDemoUITests" */;
|
||||
buildPhases = (
|
||||
B69AAB2A29F31CF500026789 /* Sources */,
|
||||
B69AAB2B29F31CF500026789 /* Frameworks */,
|
||||
B69AAB2C29F31CF500026789 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
B69AAB3029F31CF500026789 /* PBXTargetDependency */,
|
||||
);
|
||||
name = FutureFlowDemoUITests;
|
||||
productName = FutureFlowDemoUITests;
|
||||
productReference = B69AAB2E29F31CF500026789 /* FutureFlowDemoUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
B69AAB0C29F31CF300026789 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1430;
|
||||
LastUpgradeCheck = 1430;
|
||||
TargetAttributes = {
|
||||
B69AAB1329F31CF300026789 = {
|
||||
CreatedOnToolsVersion = 14.3;
|
||||
};
|
||||
B69AAB2329F31CF500026789 = {
|
||||
CreatedOnToolsVersion = 14.3;
|
||||
TestTargetID = B69AAB1329F31CF300026789;
|
||||
};
|
||||
B69AAB2D29F31CF500026789 = {
|
||||
CreatedOnToolsVersion = 14.3;
|
||||
TestTargetID = B69AAB1329F31CF300026789;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = B69AAB0F29F31CF300026789 /* Build configuration list for PBXProject "FutureFlowDemo" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = B69AAB0B29F31CF300026789;
|
||||
productRefGroup = B69AAB1529F31CF300026789 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
B69AAB1329F31CF300026789 /* FutureFlowDemo */,
|
||||
B69AAB2329F31CF500026789 /* FutureFlowDemoTests */,
|
||||
B69AAB2D29F31CF500026789 /* FutureFlowDemoUITests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
B69AAB1229F31CF300026789 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B69AAB1F29F31CF400026789 /* Preview Assets.xcassets in Resources */,
|
||||
B69AAB1C29F31CF400026789 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B69AAB2229F31CF500026789 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B69AAB2C29F31CF500026789 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
B69AAB1029F31CF300026789 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B69AAB1A29F31CF300026789 /* ContentView.swift in Sources */,
|
||||
B69AAB4729F42F8900026789 /* Demo2.swift in Sources */,
|
||||
B6C55E9729F5C75200E9E281 /* Demo11.swift in Sources */,
|
||||
B69AAB4929F44D2A00026789 /* Demo10.swift in Sources */,
|
||||
B69AAB1829F31CF300026789 /* FutureFlowDemoApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B69AAB2029F31CF500026789 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B69AAB2929F31CF500026789 /* FutureFlowDemoTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B69AAB2A29F31CF500026789 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B69AAB3529F31CF500026789 /* FutureFlowDemoUITestsLaunchTests.swift in Sources */,
|
||||
B69AAB3329F31CF500026789 /* FutureFlowDemoUITests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
B69AAB2629F31CF500026789 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = B69AAB1329F31CF300026789 /* FutureFlowDemo */;
|
||||
targetProxy = B69AAB2529F31CF500026789 /* PBXContainerItemProxy */;
|
||||
};
|
||||
B69AAB3029F31CF500026789 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = B69AAB1329F31CF300026789 /* FutureFlowDemo */;
|
||||
targetProxy = B69AAB2F29F31CF500026789 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
B69AAB3629F31CF500026789 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B69AAB3729F31CF500026789 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B69AAB3929F31CF500026789 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"FutureFlowDemo/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = 3Q76DGNCRR;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.xyfuture.FutureFlowDemo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B69AAB3A29F31CF500026789 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"FutureFlowDemo/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = 3Q76DGNCRR;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.xyfuture.FutureFlowDemo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B69AAB3C29F31CF500026789 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 3Q76DGNCRR;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.xyfuture.FutureFlowDemoTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FutureFlowDemo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/FutureFlowDemo";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B69AAB3D29F31CF500026789 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 3Q76DGNCRR;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.xyfuture.FutureFlowDemoTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FutureFlowDemo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/FutureFlowDemo";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B69AAB3F29F31CF500026789 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 3Q76DGNCRR;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.xyfuture.FutureFlowDemoUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_TARGET_NAME = FutureFlowDemo;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B69AAB4029F31CF500026789 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 3Q76DGNCRR;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.xyfuture.FutureFlowDemoUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_TARGET_NAME = FutureFlowDemo;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
B69AAB0F29F31CF300026789 /* Build configuration list for PBXProject "FutureFlowDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B69AAB3629F31CF500026789 /* Debug */,
|
||||
B69AAB3729F31CF500026789 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B69AAB3829F31CF500026789 /* Build configuration list for PBXNativeTarget "FutureFlowDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B69AAB3929F31CF500026789 /* Debug */,
|
||||
B69AAB3A29F31CF500026789 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B69AAB3B29F31CF500026789 /* Build configuration list for PBXNativeTarget "FutureFlowDemoTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B69AAB3C29F31CF500026789 /* Debug */,
|
||||
B69AAB3D29F31CF500026789 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B69AAB3E29F31CF500026789 /* Build configuration list for PBXNativeTarget "FutureFlowDemoUITests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B69AAB3F29F31CF500026789 /* Debug */,
|
||||
B69AAB4029F31CF500026789 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
B69AAB4429F31E6700026789 /* FutureFlow */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = FutureFlow;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = B69AAB0C29F31CF300026789 /* Project object */;
|
||||
}
|
7
FutureFlowDemo/FutureFlowDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
FutureFlowDemo/FutureFlowDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B69AAB1329F31CF300026789"
|
||||
BuildableName = "FutureFlowDemo.app"
|
||||
BlueprintName = "FutureFlowDemo"
|
||||
ReferencedContainer = "container:FutureFlowDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B69AAB2329F31CF500026789"
|
||||
BuildableName = "FutureFlowDemoTests.xctest"
|
||||
BlueprintName = "FutureFlowDemoTests"
|
||||
ReferencedContainer = "container:FutureFlowDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B69AAB2D29F31CF500026789"
|
||||
BuildableName = "FutureFlowDemoUITests.xctest"
|
||||
BlueprintName = "FutureFlowDemoUITests"
|
||||
ReferencedContainer = "container:FutureFlowDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B69AAB1329F31CF300026789"
|
||||
BuildableName = "FutureFlowDemo.app"
|
||||
BlueprintName = "FutureFlowDemo"
|
||||
ReferencedContainer = "container:FutureFlowDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B69AAB1329F31CF300026789"
|
||||
BuildableName = "FutureFlowDemo.app"
|
||||
BlueprintName = "FutureFlowDemo"
|
||||
ReferencedContainer = "container:FutureFlowDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B69AAB2329F31CF500026789"
|
||||
BuildableName = "FutureFlowDemoTests.xctest"
|
||||
BlueprintName = "FutureFlowDemoTests"
|
||||
ReferencedContainer = "container:FutureFlowDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B69AAB2D29F31CF500026789"
|
||||
BuildableName = "FutureFlowDemoUITests.xctest"
|
||||
BlueprintName = "FutureFlowDemoUITests"
|
||||
ReferencedContainer = "container:FutureFlowDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// ContentView.swift
|
||||
// FutureFlowDemo
|
||||
//
|
||||
// Created by Muhand Jumah on 4/21/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import FutureFlow
|
||||
|
||||
|
||||
enum TutorialChunks: FlowChunk, CaseIterable {
|
||||
case red
|
||||
case green
|
||||
case yellow
|
||||
|
||||
var spotlightShape: SpotlightShape {
|
||||
switch self {
|
||||
case .yellow:
|
||||
return .circle()
|
||||
default:
|
||||
return .rectangle()
|
||||
}
|
||||
}
|
||||
|
||||
var spotlightBackground: SpotlightBackground {
|
||||
switch self {
|
||||
case .green:
|
||||
return .ultraThinMaterial
|
||||
default:
|
||||
return .black
|
||||
}
|
||||
}
|
||||
|
||||
var instructionsViewType: InstructionsViewType? {
|
||||
switch self {
|
||||
case .red:
|
||||
return .simple(instructions: ["Text1"], position: .below)
|
||||
case .green:
|
||||
return .simple(instructions: ["Text2", "Text22", "Text222", "Text2222"], position: .below)
|
||||
case .yellow:
|
||||
return .simple(instructions: ["Text3"], position: .above)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
private var uniqueIdentifier: String = UUID().uuidString
|
||||
private var tutorial: [TutorialChunks] =
|
||||
[
|
||||
.red,
|
||||
.green,
|
||||
.yellow
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 50) {
|
||||
Rectangle()
|
||||
.frame(width: 256, height: 256, alignment: .center)
|
||||
.foregroundColor(Color.red)
|
||||
.configureChunkForSpotlight(
|
||||
parentIdentifier: self.uniqueIdentifier,
|
||||
chunk: self.tutorial[0]
|
||||
)
|
||||
|
||||
Rectangle()
|
||||
.frame(width: 64, height: 128, alignment: .center)
|
||||
.foregroundColor(Color.green)
|
||||
.configureChunkForSpotlight(
|
||||
parentIdentifier: self.uniqueIdentifier,
|
||||
chunk: self.tutorial[1]
|
||||
)
|
||||
|
||||
Circle()
|
||||
.frame(width: 128, height: 128, alignment: .center)
|
||||
.foregroundColor(.yellow)
|
||||
.configureChunkForSpotlight(
|
||||
parentIdentifier: self.uniqueIdentifier,
|
||||
chunk: self.tutorial[2]
|
||||
)
|
||||
}
|
||||
.padding()
|
||||
.assembleSpotlightChunks(uniqueIdentifier: self.uniqueIdentifier, chunks: Array(TutorialChunks.allCases))
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
//
|
||||
// Demo3.swift
|
||||
// FutureFlowDemo
|
||||
//
|
||||
// Created by Muhand Jumah on 4/22/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Demo10: View {
|
||||
enum Highlight: Identifiable {
|
||||
case first
|
||||
case second
|
||||
case third
|
||||
|
||||
var id: Int {
|
||||
self.hashValue
|
||||
}
|
||||
}
|
||||
@State private var sw: Bool = false
|
||||
@State private var currentHighlight: Highlight = .first
|
||||
|
||||
@Namespace private var namespace
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
ZStack {
|
||||
VStack(spacing:50) {
|
||||
// if(!sw) {
|
||||
Rectangle()
|
||||
.fill(.red)
|
||||
.matchedGeometryEffect(id: Highlight.first.id,
|
||||
in: namespace,
|
||||
properties: .frame,
|
||||
anchor: .center,
|
||||
isSource: true)
|
||||
.frame(width: 100, height: 200)
|
||||
|
||||
Rectangle()
|
||||
.fill(.orange)
|
||||
.matchedGeometryEffect(id: Highlight.second.id,
|
||||
in: namespace,
|
||||
properties: .frame,
|
||||
anchor: .center,
|
||||
isSource: true)
|
||||
.frame(width: 50, height: 50)
|
||||
|
||||
|
||||
Circle()
|
||||
.fill(.black)
|
||||
.matchedGeometryEffect(id: Highlight.third.id,
|
||||
in: namespace,
|
||||
properties: .frame,
|
||||
anchor: .center,
|
||||
isSource: true)
|
||||
.frame(width: 200, height: 200)
|
||||
}
|
||||
}
|
||||
|
||||
// Spotlight goes here
|
||||
|
||||
self.currentHighlight.shape(self.namespace)
|
||||
.matchedGeometryEffect(id: self.currentHighlight.id,
|
||||
in: namespace,
|
||||
properties: .frame,
|
||||
anchor: .center,
|
||||
isSource: false)
|
||||
|
||||
|
||||
}
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
if(self.currentHighlight == .first) {
|
||||
self.currentHighlight = .second
|
||||
} else if (self.currentHighlight == .second){
|
||||
self.currentHighlight = .third
|
||||
} else {
|
||||
self.currentHighlight = .first
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Demo10_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Demo10()
|
||||
}
|
||||
}
|
||||
|
||||
extension Demo10.Highlight {
|
||||
func shape(_ ns: Namespace.ID) -> some View {
|
||||
ZStack {
|
||||
switch self {
|
||||
|
||||
case .first:
|
||||
Rectangle()
|
||||
.foregroundColor(.purple)
|
||||
.matchedGeometryEffect(id: 998, in: ns)
|
||||
|
||||
case .second:
|
||||
|
||||
Rectangle()
|
||||
.foregroundColor(.purple)
|
||||
.matchedGeometryEffect(id: 998, in: ns)
|
||||
|
||||
case .third:
|
||||
Circle()
|
||||
.foregroundColor(.purple)
|
||||
.matchedGeometryEffect(id: 998, in: ns)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//import SwiftUI
|
||||
//
|
||||
//struct Demo10: View {
|
||||
// enum TestEnum {
|
||||
// case first
|
||||
// case second
|
||||
//
|
||||
// func shape(ns: Namespace.ID) -> some View {
|
||||
// ZStack {
|
||||
// switch self {
|
||||
// case .first:
|
||||
// Rectangle()
|
||||
// .foregroundColor(.purple)
|
||||
// .matchedGeometryEffect(id: 0, in: ns)
|
||||
// .frame(width: 100, height: 100)
|
||||
//
|
||||
// case .second:
|
||||
// Circle()
|
||||
// .foregroundColor(.red)
|
||||
// .matchedGeometryEffect(id: 0, in: ns)
|
||||
// .frame(width: 300, height: 300)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Namespace private var ns
|
||||
//
|
||||
// @State private var currentShape:TestEnum = .first
|
||||
// @State private var sw: Bool = false
|
||||
//
|
||||
// var body: some View {
|
||||
// VStack {
|
||||
// VStack(spacing: 0) {
|
||||
// Button(action: {
|
||||
// withAnimation {
|
||||
// if(self.currentShape == .first) {
|
||||
// self.currentShape = .second
|
||||
// } else {
|
||||
// self.currentShape = .first
|
||||
// }
|
||||
// }
|
||||
// }) {
|
||||
// Text("Switch")
|
||||
// }
|
||||
// .frame(height: 50)
|
||||
//
|
||||
// self.currentShape.shape(ns: self.ns)
|
||||
// }
|
||||
// .frame(maxWidth: 300, maxHeight: 350, alignment: .center)
|
||||
// .border(Color.blue, width: 2)
|
||||
//
|
||||
// Divider()
|
||||
//
|
||||
// VStack(spacing: 0) {
|
||||
// Button(action: {
|
||||
// withAnimation {
|
||||
// self.sw.toggle()
|
||||
// }
|
||||
// }) {
|
||||
// Text("Switch")
|
||||
// }
|
||||
// .frame(height: 50)
|
||||
//
|
||||
// if(!self.sw) {
|
||||
// Rectangle()
|
||||
// .foregroundColor(.purple)
|
||||
// .frame(width: 100, height: 100)
|
||||
// } else {
|
||||
// Circle()
|
||||
// .foregroundColor(.red)
|
||||
// .frame(width: 300, height: 300)
|
||||
// }
|
||||
// }
|
||||
// .frame(maxWidth: 300, maxHeight: 350, alignment: .center)
|
||||
// .border(Color.green, width: 2)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct Demo10_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// Demo10()
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,19 @@
|
|||
////
|
||||
//// Demo11.swift
|
||||
//// FutureFlowDemo
|
||||
////
|
||||
//// Created by Muhand Jumah on 4/23/23.
|
||||
////
|
||||
//
|
||||
//import SwiftUI
|
||||
//
|
||||
//struct Demo11: View {
|
||||
//
|
||||
//}
|
||||
//
|
||||
//struct Demo11_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
//
|
||||
//
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,257 @@
|
|||
//
|
||||
// Demo2.swift
|
||||
// FutureFlowDemo
|
||||
//
|
||||
// Created by Muhand Jumah on 4/22/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct User: Identifiable, Equatable {
|
||||
let id: UUID = UUID()
|
||||
let name: String
|
||||
var message: String = ""
|
||||
}
|
||||
|
||||
var users: [User] = [
|
||||
.init(name: "Muhand", message: "This is just a test message, akjsdfh al ladsjf l;aksdj fl;ksajf;lasdfkfjksjfh"),
|
||||
.init(name: "Hussam"),
|
||||
.init(name: "Jareny"),
|
||||
.init(name: "Mays"),
|
||||
.init(name: "Nahla"),
|
||||
.init(name: "Abbas"),
|
||||
.init(name: "Jumah"),
|
||||
.init(name: "Mathry"),
|
||||
.init(name: "Katie"),
|
||||
.init(name: "Valeria"),
|
||||
.init(name: "Johanna")
|
||||
]
|
||||
|
||||
struct DemoRoot: View {
|
||||
enum DemoRootViews {
|
||||
case Demo2
|
||||
case Demo3
|
||||
}
|
||||
|
||||
@Namespace private var rootNamespace
|
||||
@Namespace private var namespace
|
||||
@State private var currentDemoView: DemoRootViews = .Demo2
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
// Button(action: {
|
||||
//// .onTapGesture {
|
||||
// self.currentDemoView = .Demo3
|
||||
//// }
|
||||
// }) {
|
||||
// Text("SWITCH")
|
||||
// }
|
||||
switch self.currentDemoView {
|
||||
case .Demo2:
|
||||
VStack {
|
||||
HStack {
|
||||
Demo2(namespace: self.namespace)
|
||||
// .matchedGeometryEffect(id: 0, in: self.rootNamespace)
|
||||
.frame(maxWidth: UIScreen.main.bounds.size.width * 0.7)
|
||||
.padding(.horizontal, 15)
|
||||
.onTapGesture {
|
||||
self.switchViews()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
case .Demo3:
|
||||
Demo3(namespace: self.namespace)
|
||||
// .matchedGeometryEffect(id: 0, in: self.rootNamespace)
|
||||
.onTapGesture {
|
||||
self.switchViews()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func switchViews() {
|
||||
withAnimation(.spring()) {
|
||||
switch self.currentDemoView {
|
||||
case .Demo2:
|
||||
self.currentDemoView = .Demo3
|
||||
case .Demo3:
|
||||
self.currentDemoView = .Demo2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Demo2: View {
|
||||
var namespace: Namespace.ID
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment:.leading, spacing: 10) {
|
||||
HStack(alignment:.center, spacing: 5) {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(alignment: .center, spacing:0) {
|
||||
ForEach(users, id:\.id) { user in
|
||||
if
|
||||
let last = users.last,
|
||||
user == last {
|
||||
Text("\(user.name)")
|
||||
.matchedGeometryEffect(id: "\(user.id)_name", in: self.namespace)
|
||||
} else {
|
||||
Text("\(user.name), ")
|
||||
.matchedGeometryEffect(id: "\(user.id)_name", in: self.namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(alignment:.top, spacing:5) {
|
||||
ForEach(users, id:\.id) { user in
|
||||
ZStack {
|
||||
Circle()
|
||||
.matchedGeometryEffect(id: "\(user.id)_profile_image", in: self.namespace)
|
||||
.frame(width: 32, height: 32, alignment: .center)
|
||||
|
||||
Text("\(String(user.name.prefix(1)))")
|
||||
.foregroundColor(Color.white)
|
||||
.matchedGeometryEffect(id: "\(user.id)_letter", in: self.namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.zIndex(500)
|
||||
}
|
||||
|
||||
Divider()
|
||||
.matchedGeometryEffect(id: "divider", in: self.namespace)
|
||||
|
||||
HStack(alignment:.top, spacing:0) {
|
||||
Text(users[0].message)
|
||||
.matchedGeometryEffect(id: "\(users[0].id)_msg", in: self.namespace)
|
||||
.lineLimit(1)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("10:51 pm")
|
||||
.matchedGeometryEffect(id: "\(users[0].id)_msg_time", in: self.namespace)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 15)
|
||||
.stroke(Color.black, lineWidth: 1),
|
||||
alignment: .center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct Demo3: View {
|
||||
var namespace: Namespace.ID
|
||||
var body: some View {
|
||||
VStack(spacing:0) {
|
||||
Spacer()
|
||||
|
||||
VStack(spacing:0) {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(spacing: 5) {
|
||||
ForEach(users, id:\.id) { user in
|
||||
VStack(spacing:5) {
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(.black)
|
||||
.matchedGeometryEffect(id: "\(user.id)_profile_image", in: self.namespace)
|
||||
.frame(width: 64, height: 64)
|
||||
|
||||
Text("\(String(user.name.prefix(1)))")
|
||||
.foregroundColor(Color.white)
|
||||
.matchedGeometryEffect(id: "\(user.id)_letter", in: self.namespace)
|
||||
}
|
||||
|
||||
Text(user.name)
|
||||
.matchedGeometryEffect(id: "\(user.id)_name", in: self.namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.zIndex(500) // end of scrollview
|
||||
|
||||
Divider()
|
||||
.matchedGeometryEffect(id: "divider", in: self.namespace)
|
||||
|
||||
ScrollView(.vertical, showsIndicators: true) {
|
||||
VStack(alignment:.leading, spacing:0) {
|
||||
VStack(alignment: .leading, spacing:5) {
|
||||
HStack(spacing:5) {
|
||||
Circle()
|
||||
.matchedGeometryEffect(id: "\(users[0].id)_profile_image", in: self.namespace)
|
||||
.frame(width: 24, height: 24)
|
||||
|
||||
Text("\(users[0].name)")
|
||||
.matchedGeometryEffect(id: "\(users[0].id)_name", in: self.namespace)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("10:51 pm")
|
||||
.matchedGeometryEffect(id: "\(users[0].id)_msg_time", in: self.namespace)
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
Text("\(users[0].message)")
|
||||
.matchedGeometryEffect(id: "\(users[0].id)_msg", in: self.namespace)
|
||||
}
|
||||
.padding(.horizontal, 15)
|
||||
.padding(.vertical, 8)
|
||||
.frame(
|
||||
maxWidth: .infinity,
|
||||
minHeight: 100,
|
||||
maxHeight: 100,
|
||||
alignment: .topLeading
|
||||
)
|
||||
.background(Color.white)
|
||||
.cornerRadius(15)
|
||||
}
|
||||
.rotationEffect(.degrees(-180))
|
||||
}
|
||||
.rotationEffect(.degrees(-180))
|
||||
.padding(.horizontal, 15)
|
||||
.frame(
|
||||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 300,
|
||||
idealHeight: 300,
|
||||
maxHeight: 300,
|
||||
alignment:.topLeading
|
||||
)
|
||||
.background(Color.green)
|
||||
.padding(.horizontal, -15)
|
||||
}
|
||||
.padding(.horizontal, 15) // end of vstack
|
||||
}
|
||||
.frame(minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
minHeight: 0,
|
||||
maxHeight: .infinity,
|
||||
alignment: .top)
|
||||
.background(Color.red)
|
||||
}
|
||||
}
|
||||
|
||||
struct Demo2_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let prevNamespcae: Namespace.ID = Namespace().wrappedValue
|
||||
Group {
|
||||
DemoRoot()
|
||||
.previewDisplayName("DemoRoot")
|
||||
|
||||
Demo2(namespace: prevNamespcae)
|
||||
.padding()
|
||||
.previewDisplayName("Demo2")
|
||||
|
||||
Demo3(namespace: prevNamespcae)
|
||||
.previewDisplayName("Demo3")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// FutureFlowDemoApp.swift
|
||||
// FutureFlowDemo
|
||||
//
|
||||
// Created by Muhand Jumah on 4/21/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct FutureFlowDemoApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
// Demo10()
|
||||
// Demo2()
|
||||
// DemoRoot()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// FutureFlowDemoTests.swift
|
||||
// FutureFlowDemoTests
|
||||
//
|
||||
// Created by Muhand Jumah on 4/21/23.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import FutureFlowDemo
|
||||
|
||||
final class FutureFlowDemoTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
// Any test you write for XCTest can be annotated as throws and async.
|
||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// FutureFlowDemoUITests.swift
|
||||
// FutureFlowDemoUITests
|
||||
//
|
||||
// Created by Muhand Jumah on 4/21/23.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class FutureFlowDemoUITests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||
continueAfterFailure = false
|
||||
|
||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// UI tests must launch the application that they test.
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testLaunchPerformance() throws {
|
||||
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
|
||||
// This measures how long it takes to launch your application.
|
||||
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
||||
XCUIApplication().launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// FutureFlowDemoUITestsLaunchTests.swift
|
||||
// FutureFlowDemoUITests
|
||||
//
|
||||
// Created by Muhand Jumah on 4/21/23.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class FutureFlowDemoUITestsLaunchTests: XCTestCase {
|
||||
|
||||
override class var runsForEachTargetApplicationUIConfiguration: Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
|
||||
func testLaunch() throws {
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Insert steps here to perform after app launch but before taking a screenshot,
|
||||
// such as logging into a test account or navigating somewhere in the app
|
||||
|
||||
let attachment = XCTAttachment(screenshot: app.screenshot())
|
||||
attachment.name = "Launch Screen"
|
||||
attachment.lifetime = .keepAlways
|
||||
add(attachment)
|
||||
}
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
//print("Hello, world!")
|
||||
|
||||
//protocol TutorialSteps {
|
||||
//
|
||||
//}
|
||||
//
|
||||
//import SwiftUI
|
||||
//
|
||||
//extension View {
|
||||
// func tut() {
|
||||
//
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
public final class FutureFlow {
|
||||
public init() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Just a test
|
||||
enum Tutorial: FlowChunk {
|
||||
case settings
|
||||
case listening
|
||||
case soundwave
|
||||
|
||||
var spotLightShape: AnyView {
|
||||
switch self {
|
||||
case .listening:
|
||||
return listeningSpotlight
|
||||
case .settings:
|
||||
return rectangleShape
|
||||
default:
|
||||
return defaultSpotLight
|
||||
}
|
||||
}
|
||||
|
||||
var spotlightBackground: AnyView {
|
||||
switch self {
|
||||
default:
|
||||
return self.defaultSpotlightBackground
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Tutorial {
|
||||
fileprivate var defaultSpotLight: AnyView {
|
||||
AnyView(
|
||||
Rectangle()
|
||||
.foregroundColor(.white)
|
||||
.blur(radius: 1)
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate var listeningSpotlight: AnyView {
|
||||
AnyView(
|
||||
Circle()
|
||||
.foregroundColor(.white)
|
||||
.blur(radius: 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
// End of the test
|
||||
|
||||
|
||||
protocol FlowChunk: Hashable {
|
||||
var spotLightShape: AnyView { get }
|
||||
var spotlightBackground: AnyView { get }
|
||||
}
|
||||
|
||||
extension FlowChunk {
|
||||
fileprivate var rectangleShape: AnyView {
|
||||
AnyView (
|
||||
Rectangle()
|
||||
.foregroundColor(Color.white)
|
||||
.blur(radius: 1)
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate var circleShape: AnyView {
|
||||
AnyView (
|
||||
Circle()
|
||||
.foregroundColor(Color.white)
|
||||
.blur(radius: 1)
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate var defaultSpotlightBackground: AnyView {
|
||||
AnyView (
|
||||
Color.black
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
func test<Chunk: FlowChunk>(parentIdentifier: String, chunk: Chunk) -> some View {
|
||||
// let namespace = Namespace()
|
||||
// FutureFlowManager.currentNamespaces[uniqueIdentifier] = namespace
|
||||
var namespace: Namespace!
|
||||
if let namespace2 = FutureFlowManager.currentNamespaces[parentIdentifier] {
|
||||
namespace = namespace2
|
||||
} else {
|
||||
namespace = Namespace()
|
||||
FutureFlowManager.currentNamespaces[parentIdentifier] = namespace
|
||||
}
|
||||
|
||||
return self
|
||||
.matchedGeometryEffect(
|
||||
id: chunk.hashValue,
|
||||
in: namespace.wrappedValue,
|
||||
properties: .frame,
|
||||
anchor: .center,
|
||||
isSource: true
|
||||
)
|
||||
}
|
||||
|
||||
func test3<Chunk: FlowChunk>(uniqueIdentifier: String, chunks: [Chunk]) -> some View {
|
||||
return HighlightingView(showTutorial: .constant(true),
|
||||
chunks: chunks) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct SpotlightView<Chunk: FlowChunk>: View {
|
||||
internal var chunk: Chunk
|
||||
internal var namespace: Namespace.ID
|
||||
|
||||
internal var body: some View {
|
||||
ZStack {
|
||||
self.chunk.spotlightBackground
|
||||
|
||||
self.chunk.spotLightShape
|
||||
.matchedGeometryEffect(
|
||||
id: self.chunk.hashValue,
|
||||
in: namespace,
|
||||
properties: .frame, anchor: .center,
|
||||
isSource: false
|
||||
)
|
||||
.blendMode(.destinationOut)
|
||||
}
|
||||
.compositingGroup()
|
||||
}
|
||||
}
|
||||
|
||||
internal struct HighlightingView<Content: View, Chunk: FlowChunk>: View {
|
||||
@Namespace private var namespace
|
||||
|
||||
@Binding var showTutorial: Bool
|
||||
let chunks: [Chunk]
|
||||
let content: Content
|
||||
|
||||
@State private var currentIndex: Int = 0
|
||||
|
||||
init(showTutorial: Binding<Bool>, chunks: [Chunk], @ViewBuilder content: () -> Content) {
|
||||
self._showTutorial = showTutorial
|
||||
self.chunks = chunks
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
self.content
|
||||
|
||||
SpotlightView(
|
||||
chunk: self.chunks[self.currentIndex],
|
||||
namespace: self.namespace
|
||||
)
|
||||
.opacity(self.showTutorial ? 0.5 : 0)
|
||||
.animation(
|
||||
.easeOut,
|
||||
value: self.showTutorial ? self.currentIndex : nil
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var tuts: [Tutorial] =
|
||||
[
|
||||
.listening,
|
||||
.settings,
|
||||
.soundwave
|
||||
]
|
||||
|
||||
private let uniqueIdentifier: String = UUID().uuidString
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Text("TEST")
|
||||
.test(parentIdentifier: self.uniqueIdentifier, chunk: self.tuts[0])//, chunk: self.tuts[0])
|
||||
}
|
||||
.test3(uniqueIdentifier: self.uniqueIdentifier, chunks: self.tuts)
|
||||
}
|
||||
}
|
||||
|
||||
internal class FutureFlowManager {
|
||||
internal static var currentNamespaces: [String:Namespace] = [:]
|
||||
}
|
Loading…
Reference in New Issue