Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
2862b45
feat: firebase initialization
benedictusyoga Nov 26, 2025
9dfd460
Merge remote-tracking branch 'refs/remotes/origin/feat/firebase-imple…
benedictusyoga Nov 26, 2025
1003cfd
feat: firebase initialization
benedictusyoga Nov 26, 2025
ed56072
Merge remote-tracking branch 'refs/remotes/origin/feat/firebase-imple…
benedictusyoga Nov 26, 2025
850679f
feat: add profile screen
destucr Nov 26, 2025
1fbb098
feat: add profile navigation in PregnancyTimelineView
destucr Nov 26, 2025
c96f620
feat: sign in with apple init
benedictusyoga Nov 26, 2025
65737d7
Merge remote-tracking branch 'refs/remotes/origin/feat/firebase-imple…
benedictusyoga Nov 26, 2025
92636cf
feat: room and mom init success
benedictusyoga Nov 26, 2025
3a8586e
Merge remote-tracking branch 'refs/remotes/origin/feat/firebase-imple…
benedictusyoga Nov 26, 2025
05d4a75
fix: account section in profile
destucr Nov 27, 2025
e9f64c0
fix: listening mode top text
destucr Nov 27, 2025
dced2ef
Merge pull request #91 from KullyTech/fix/listening-mode-text
destucr Nov 27, 2025
46cee0c
fix: profile in pregnancy timeline view
destucr Nov 27, 2025
03ba76d
fix: swiftlint violation
destucr Nov 27, 2025
71236ef
Merge pull request #92 from KullyTech/feat/profile
destucr Nov 27, 2025
ecf9ded
feat: heartbeat sync init
benedictusyoga Nov 26, 2025
06152cf
Merge remote-tracking branch 'refs/remotes/origin/feat/firebase-imple…
benedictusyoga Nov 27, 2025
248a8b5
feat: mom/dad sync works!
benedictusyoga Nov 27, 2025
c4bc9a1
Merge remote-tracking branch 'refs/remotes/origin/feat/firebase-imple…
benedictusyoga Nov 27, 2025
72905b1
fix: listening mode top text
destucr Nov 27, 2025
1d8b08a
feat: add profile screen
destucr Nov 26, 2025
ef43603
feat: updated provisioning profile
benedictusyoga Nov 27, 2025
0be004d
Merge remote-tracking branch 'refs/remotes/origin/feat/firebase-imple…
benedictusyoga Nov 28, 2025
49cd2db
feat: orb customization init
benedictusyoga Nov 28, 2025
643bf78
Merge remote-tracking branch 'refs/remotes/origin/feat/orb-customizat…
benedictusyoga Nov 28, 2025
701b034
fix: listening mode top text
destucr Nov 27, 2025
8e97557
feat: add profile screen
destucr Nov 26, 2025
05d5a67
fix: improved UI customization view
benedictusyoga Nov 28, 2025
fa10ed8
Merge remote-tracking branch 'refs/remotes/origin/feat/orb-customizat…
benedictusyoga Nov 28, 2025
fe4b29c
feat: add profile navigation in PregnancyTimelineView
destucr Nov 26, 2025
d2f8d9e
fix: profile in pregnancy timeline view
destucr Nov 27, 2025
a379a91
fix: swiftlint violation
destucr Nov 27, 2025
226ff20
hotfix: also implemented custom backgrounds on splash screen and auth…
benedictusyoga Nov 28, 2025
81c2a9f
Merge remote-tracking branch 'refs/remotes/origin/feat/orb-customizat…
benedictusyoga Nov 28, 2025
de7a696
fix: profile name input
destucr Nov 28, 2025
2675fd5
Merge branch 'development' into fix/profile-auth
destucr Nov 28, 2025
5760534
fix: swiftlint
destucr Nov 28, 2025
7bd971b
Merge pull request #93 from KullyTech/fix/profile-auth
destucr Nov 28, 2025
882040f
fix: listening mode top text
destucr Nov 27, 2025
dec523e
feat: add profile screen
destucr Nov 26, 2025
ca3cb16
feat: add profile navigation in PregnancyTimelineView
destucr Nov 26, 2025
91bde48
fix: profile in pregnancy timeline view
destucr Nov 27, 2025
8578778
fix: swiftlint violation
destucr Nov 27, 2025
e61a12e
fix: profile name input
destucr Nov 28, 2025
5501a05
feat: add profile navigation in PregnancyTimelineView
destucr Nov 26, 2025
28d621a
fix: account section in profile
destucr Nov 27, 2025
611e0d0
fix: swiftlint
destucr Nov 28, 2025
ef6e0dd
Merge branch 'development' into feat/custom-ui
destucr Nov 28, 2025
948e616
fix: swiftlint
destucr Nov 28, 2025
07e3fb4
Merge pull request #94 from KullyTech/feat/custom-ui
destucr Nov 28, 2025
2eadbc0
feat: animation timeline
revanzanrndra Nov 28, 2025
73f4625
fix: merge conflict development
revanzanrndra Nov 28, 2025
1760e9f
feat: add profile navigation in PregnancyTimelineView
destucr Nov 26, 2025
d87bccc
fix: playback issue
revanzanrndra Nov 29, 2025
e952371
Merge pull request #95 from KullyTech/feat/timeline-merge
revanzanrndra Nov 29, 2025
f3fa612
fix: swiftlint violation
destucr Nov 30, 2025
7953f4d
Merge pull request #96 from KullyTech/feat/merge-timeline-dev
destucr Nov 30, 2025
d9b3612
feat: add edit name and delete functionality for recording
revanzanrndra Nov 30, 2025
8548b6a
feat: add image function
revanzanrndra Nov 30, 2025
ea43150
Merge branch 'development' into feat/timeline-merge
destucr Nov 30, 2025
3ed1015
fix: swiftlint violations
destucr Nov 30, 2025
41ccc9a
Merge pull request #97 from KullyTech/feat/timeline-merge
destucr Nov 30, 2025
9a0bbe9
feat: add tutorial view
destucr Nov 30, 2025
95ef91c
fix: tabview indicator apppear in profile
destucr Nov 30, 2025
4476abc
fix: scroll in tutorialView
destucr Nov 30, 2025
f8c13a8
Merge pull request #98 from KullyTech/feat: add tutorial view & gestu…
destucr Nov 30, 2025
e03e5db
fix: top alert when save and delete behaviour
destucr Nov 30, 2025
69c33d0
feat: add haptic toogle
destucr Nov 30, 2025
ed93bba
Merge pull request #99 from KullyTech/fix: top alert when save and de…
destucr Nov 30, 2025
5e073f2
fix: room code background
destucr Nov 30, 2025
40daa60
fix: toogle and share button in saved recorded playback
destucr Nov 30, 2025
0d8ed6c
fix: add duration in saved recorded playback
destucr Nov 30, 2025
d16642e
Merge pull request #100 from KullyTech/feat: add haptic toogle and bu…
destucr Nov 30, 2025
947d2fe
fix: add background in room code display
destucr Nov 30, 2025
a830f2e
fix: show copied status
destucr Nov 30, 2025
df96514
Merge pull request #101 from KullyTech/fix: room code UI
destucr Dec 1, 2025
a3eb791
fix: delete heart and add disclaimer
destucr Dec 1, 2025
80de572
fix: coachmark position in orbLiveListenView
destucr Dec 1, 2025
82e5073
Merge pull request #104 from KullyTech/Fix: onboarding text
destucr Dec 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 227 additions & 8 deletions Tiny.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 28 additions & 3 deletions Tiny/App/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ import SwiftData
struct ContentView: View {
@AppStorage("hasShownOnboarding") var hasShownOnboarding: Bool = false
@StateObject private var heartbeatSoundManager = HeartbeatSoundManager()
@State private var showTimeline = false


@Environment(\.modelContext) private var modelContext
@EnvironmentObject var authService: AuthenticationService
@EnvironmentObject var syncManager: HeartbeatSyncManager

var body: some View {
Group {
if hasShownOnboarding {
HeartbeatMainView()
// After onboarding → always go to RootView (SignIn → Onboarding → Main)
RootView()
.environmentObject(heartbeatSoundManager)
.environmentObject(authService)
.environmentObject(syncManager)
} else {
// Onboarding only
OnBoardingView(hasShownOnboarding: $hasShownOnboarding)
}
}
Expand All @@ -31,6 +37,25 @@ struct ContentView: View {
}
}

struct RootView: View {
@EnvironmentObject var authService: AuthenticationService

var body: some View {
Group {
if !authService.isAuthenticated {
// Step 1: Landing screen with Sign in with Apple
SignInView()
} else if authService.currentUser?.role == nil {
// Step 2-4: Onboarding flow (role selection, name input, room code)
OnboardingCoordinator()
} else {
// Step 5: Main app - go to HeartbeatMainView
HeartbeatMainView()
}
}
}
}

#Preview {
ContentView()
.modelContainer(for: SavedHeartbeat.self, inMemory: true)
Expand Down
17 changes: 16 additions & 1 deletion Tiny/App/tinyApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,26 @@

import SwiftUI
import SwiftData
import FirebaseCore

@main
struct TinyApp: App {
@StateObject var heartbeatSoundManager = HeartbeatSoundManager()
@StateObject private var themeManager = ThemeManager()
@StateObject var authService = AuthenticationService()
@StateObject var syncManager = HeartbeatSyncManager()

@State private var isShowingSplashScreen: Bool = true // Add state to control splash screen

init() {
FirebaseApp.configure()
}

// Define the container configuration
var sharedModelContainer: ModelContainer = {
let schema = Schema([
SavedHeartbeat.self
SavedHeartbeat.self,
SavedMoment.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

Expand All @@ -31,10 +41,15 @@ struct TinyApp: App {
WindowGroup {
if isShowingSplashScreen {
SplashScreenView(isShowingSplashScreen: $isShowingSplashScreen)
.environmentObject(themeManager)
.preferredColorScheme(.dark)
} else {
ContentView()
.environmentObject(heartbeatSoundManager)
.environmentObject(authService)
.environmentObject(syncManager)
.environmentObject(themeManager)
.preferredColorScheme(.dark)
}
}
.modelContainer(sharedModelContainer)
Expand Down
97 changes: 97 additions & 0 deletions Tiny/Core/Animation/TimelineAnimationController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//
// TimelineAnimationController.swift
// Tiny
//
// Animation state management for timeline first-time experience
//

import SwiftUI
internal import Combine

enum AnimationPhase {
case empty
case drawingPath
case showingDots
case transformingOrb
case showingProfile
case complete
}

class TimelineAnimationController: ObservableObject {
@Published var currentPhase: AnimationPhase = .empty
@Published var pathProgress: CGFloat = 0.0
@Published var dotsVisible: [Bool] = [false, false, false]
@Published var orbVisible: Bool = false
@Published var profileVisible: Bool = false

// Timing constants (in seconds) - Slowed down for better visibility
private let pathDuration: Double = 2.5 // Was 1.5
private let dotDelay: Double = 0.9 // Was 0.33
private let dotDuration: Double = 0.9 // Was 0.3
private let transformDuration: Double = 1.0 // Was 0.7
private let profileDuration: Double = 0.8 // Was 0.6

func startAnimation() {
currentPhase = .drawingPath
animatePathDrawing()
}

private func animatePathDrawing() {
withAnimation(.easeInOut(duration: pathDuration)) {
pathProgress = 1.0
}

DispatchQueue.main.asyncAfter(deadline: .now() + pathDuration) {
self.currentPhase = .showingDots
self.animateDotsAppearing()
}
}

private func animateDotsAppearing() {
// Show dots sequentially
for index in 0..<3 {
DispatchQueue.main.asyncAfter(deadline: .now() + (Double(index) * dotDelay)) {
withAnimation(.easeOut(duration: self.dotDuration)) {
self.dotsVisible[index] = true
}
}
}

// After all dots appear, transform first dot to orb
let totalDotTime = Double(3) * dotDelay + dotDuration
DispatchQueue.main.asyncAfter(deadline: .now() + totalDotTime) {
self.currentPhase = .transformingOrb
self.animateOrbTransform()
}
}

private func animateOrbTransform() {
withAnimation(.spring(response: 0.6, dampingFraction: 0.75)) {
dotsVisible[0] = false
orbVisible = true
}

DispatchQueue.main.asyncAfter(deadline: .now() + transformDuration) {
self.currentPhase = .showingProfile
self.animateProfileAppear()
}
}

private func animateProfileAppear() {
withAnimation(.easeIn(duration: profileDuration)) {
profileVisible = true
}

DispatchQueue.main.asyncAfter(deadline: .now() + profileDuration) {
self.currentPhase = .complete
}
}

func skipAnimation() {
currentPhase = .complete
pathProgress = 1.0
dotsVisible = [false, false, false]
orbVisible = true
profileVisible = true
}
}
9 changes: 7 additions & 2 deletions Tiny/Core/Components/BokehEffectView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SwiftUI
internal import Combine

struct BokehEffectView: View {
@EnvironmentObject var themeManager: ThemeManager
@Binding var amplitude: Float

private var pulseOpacity: Double {
Expand All @@ -19,13 +20,17 @@ struct BokehEffectView: View {
private var pulseScale: CGFloat {
return 1.0 + CGFloat(amplitude) * 0.3
}

private var bokehColor: Color {
themeManager.selectedOrbStyle.bokehColor
}

var body: some View {
ZStack {
// Layer 1: The Base Glow (Shifted Left)
// This is the bottom layer, slightly less bright.
Circle()
.fill(Color.orbLightYellow)
.fill(bokehColor)
.frame(width: 30)
.opacity(pulseOpacity * 0.5)
.scaleEffect(pulseScale * 1)
Expand All @@ -34,7 +39,7 @@ struct BokehEffectView: View {
// Layer 2: The Core/Highlight (Shifted Right)
// *** We apply .blendMode(.screen) here to brighten the overlap ***
Circle()
.fill(Color.orbLightYellow)
.fill(bokehColor)
.frame(width: 30)
.opacity(pulseOpacity * 0.5)
.scaleEffect(pulseScale * 1.1)
Expand Down
Loading