Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
030a06d
animation wip
amonsalve1 Mar 23, 2026
fdaeda6
Merge main into anatoli/loading-animation
amonsalve1 Sep 2, 2026
b7d9f21
Merge branch 'main' of https://github.com/cuappdev/uplift-ios-swiftui…
ukaylee Sep 5, 2026
625534b
chore: added gradient background + appdev logo with fade in animatiom
ukaylee Sep 5, 2026
6f7722d
chore: chained introanimationview to signinview
ukaylee Sep 5, 2026
5bacdf7
(chore): transitioning between intro animation to sign in
ukaylee Sep 8, 2026
66c8091
chore: fixed appdev logo speed
ukaylee Sep 9, 2026
944f1c4
chore: refactoring introanimationview for readability
ukaylee Sep 9, 2026
c3d0606
feat: yay the animation works
ukaylee Sep 10, 2026
27c7db8
chore: cleaning up code
ukaylee Sep 10, 2026
f4bfa41
chore: reverting mountains, also making the back one go up higher
ukaylee Sep 10, 2026
16a5a0f
chore: switched to sunset logo during intro animation
ukaylee Sep 10, 2026
b0c2c9f
chore(revisions): addressed stray code
ukaylee Sep 11, 2026
2feb851
chore(revisions): some constants
ukaylee Sep 11, 2026
98f1480
chore(revisions): replacing DispatchQueue with async + tasks
ukaylee Sep 11, 2026
79aaf0a
chore(revisions): refactor by making ViewModels for IntroAnimationVie…
ukaylee Sep 11, 2026
b2b2f8c
chore(revisions): converting variables into enum
ukaylee Sep 11, 2026
9cb223c
chore(revisions): fixing line length violations
ukaylee Sep 11, 2026
46577d4
chore(revisions): making many constants
ukaylee Sep 11, 2026
b7a7314
chore(revisions): moving constants to constants file
ukaylee Sep 11, 2026
9f35c05
chore(revisions): updating images to have 1x 2x 3x
ukaylee Sep 11, 2026
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
12 changes: 12 additions & 0 deletions Uplift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
2EE5F3E22B12EDB6008E0299 /* Apollo in Frameworks */ = {isa = PBXBuildFile; productRef = 2EE5F3E12B12EDB6008E0299 /* Apollo */; };
2EE5F3E42B12EDB6008E0299 /* ApolloAPI in Frameworks */ = {isa = PBXBuildFile; productRef = 2EE5F3E32B12EDB6008E0299 /* ApolloAPI */; };
2EF1A2582B129EEB007A299F /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EF1A2572B129EEB007A299F /* Network.swift */; };
52A30D3A3053B7E3002AE86C /* IntroAnimationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A30D393053B7DF002AE86C /* IntroAnimationViewModel.swift */; };
52A30D3C3053B9B8002AE86C /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A30D3B3053B9B4002AE86C /* SignInViewModel.swift */; };
63001AD62CC9ACFF0082AFFA /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63001AD52CC9ACFF0082AFFA /* LoginViewModel.swift */; };
63001AD82CC9AD970082AFFA /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = 63001AD72CC9AD970082AFFA /* GoogleSignIn */; };
63001ADA2CC9AD980082AFFA /* GoogleSignInSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 63001AD92CC9AD970082AFFA /* GoogleSignInSwift */; };
Expand Down Expand Up @@ -160,6 +162,7 @@
C07CFEB42F6B5478005830D3 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07CFEB32F6B546D005830D3 /* SettingsView.swift */; };
C0CB14922F709DA100E23E69 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0CB14912F709D9D00E23E69 /* AboutView.swift */; };
C0CB14942F70A2C800E23E69 /* Member.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0CB14932F70A2C100E23E69 /* Member.swift */; };
C0DED3032F70ACB600E43983 /* IntroAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0DED3022F70ACAD00E43983 /* IntroAnimationView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -262,6 +265,8 @@
2EE0C7CA2B12D6EE000D3BF6 /* Gym.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gym.graphql; sourceTree = "<group>"; };
2EE5F3C72B12E094008E0299 /* ApolloClientProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloClientProtocol.swift; sourceTree = "<group>"; };
2EF1A2572B129EEB007A299F /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
52A30D393053B7DF002AE86C /* IntroAnimationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroAnimationViewModel.swift; sourceTree = "<group>"; };
52A30D3B3053B9B4002AE86C /* SignInViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = "<group>"; };
63001AD52CC9ACFF0082AFFA /* LoginViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
6329A4452C964D0800D30A2F /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
6329A4472CA0F89D00D30A2F /* CreateProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateProfileView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -319,6 +324,7 @@
C07CFEB32F6B546D005830D3 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
C0CB14912F709D9D00E23E69 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
C0CB14932F70A2C100E23E69 /* Member.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Member.swift; sourceTree = "<group>"; };
C0DED3022F70ACAD00E43983 /* IntroAnimationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroAnimationView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -437,6 +443,7 @@
2E090ED02B1308C900BAE982 /* Views */ = {
isa = PBXGroup;
children = (
C0DED3022F70ACAD00E43983 /* IntroAnimationView.swift */,
294CC21C2D7E34D000EF6487 /* WeeklyWorkoutTrackerView.swift */,
293032562D7A8F64002E5484 /* WorkoutProgressArc.swift */,
89950D892B992E8400DFB007 /* ClassesView.swift */,
Expand All @@ -455,6 +462,8 @@
2E090ED12B1308D500BAE982 /* ViewModels */ = {
isa = PBXGroup;
children = (
52A30D3B3053B9B4002AE86C /* SignInViewModel.swift */,
52A30D393053B7DF002AE86C /* IntroAnimationViewModel.swift */,
293A20A12F467CED0012C74C /* SetGoalsViewModel.swift */,
135EEBA92EC7E5F70051AD5B /* WorkoutCheckInViewModel.swift */,
89C34AA02CA66E9000C579A5 /* CapacityRemindersViewModel.swift */,
Expand Down Expand Up @@ -957,6 +966,7 @@
893AD9172D595DC800C0817B /* MuscleGroupView.swift in Sources */,
89E4FAAA2CEFEC3C00A952B1 /* CapacitySemiCircleView.swift in Sources */,
89599A4E2BD4B39B00DA44DE /* FitnessClass.swift in Sources */,
52A30D3A3053B7E3002AE86C /* IntroAnimationViewModel.swift in Sources */,
2E15F5122B3A3D0000414BEC /* TriangleShape.swift in Sources */,
293A20A22F467CF00012C74C /* SetGoalsViewModel.swift in Sources */,
8940D4EE2CE3E60200F4A4A4 /* Workout.swift in Sources */,
Expand All @@ -967,6 +977,7 @@
296A2DAE2D7A805300EF042F /* ProfileViewModel.swift in Sources */,
2E15F50C2B3A0B2100414BEC /* CapacityCircleView.swift in Sources */,
2E090EC52B12EF2600BAE982 /* Publishers.swift in Sources */,
52A30D3C3053B9B8002AE86C /* SignInViewModel.swift in Sources */,
C07CFEB42F6B5478005830D3 /* SettingsView.swift in Sources */,
135EEBAA2EC7E60B0051AD5B /* WorkoutCheckInViewModel.swift in Sources */,
2E39D8222B3B631200AD238B /* DividerLine.swift in Sources */,
Expand All @@ -983,6 +994,7 @@
2E39D82A2B3B9F3D00AD238B /* FacilityExpandedView.swift in Sources */,
2EB161C92BBC9C3100493B71 /* StretchyModifier.swift in Sources */,
6329A44A2CA0FE8A00D30A2F /* CheckBoxView.swift in Sources */,
C0DED3032F70ACB600E43983 /* IntroAnimationView.swift in Sources */,
2E39D82C2B3BB35000AD238B /* FacilityExpandedViewModel.swift in Sources */,
8928C2932F71DCE900FA18BB /* GoalSettingWarningModal.swift in Sources */,
8992674A2CC03E8D00E5741E /* Dropdown.swift in Sources */,
Expand Down

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "appdev_logo_white.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1575.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1575 (1).png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "intro_background.png",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we not have 2x 3x files for this? you need the 2x 3x file so that the photo does not get blurry. also do we use png for our assets or svgs can you check the other files?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like pngs inside of Assets.xcassets

"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Animation.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Animation (1).png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is the same size as one above this looks sus 3x should have a file size bigger than the 2x

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here these are all the same size. in the figma there should be a way to export 2x, 3x of an asset

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions Uplift/Utils/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ struct Constants {
static let whistleSolid = Image("whistle_solid")
static let settings = Image("settings")
static let profileEmpty = Image("profile_empty")
static let introBackground = Image("intro_background")
static let mountainBack = Image("mountain_back")
static let mountainFront = Image("mountain_front")
static let appDevLogoWhite = Image("appdev_logo_white")
static let logoSunset = Image("logo_sunset")
}

/// Padding amounts used in Uplift.
Expand Down Expand Up @@ -235,4 +240,61 @@ struct Constants {
static let skippedLogin = "skippedLogin"
}

/// Constants used in IntroAnimation
enum IntroAnimation {
static let entranceDuration: Double = 1.0
static let entranceDelay: Double = 0.1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!


static let mountainFrontYOffset: CGFloat = 50

static let appDevLogoWidth: CGFloat = 164
static let appDevLogoHeight: CGFloat = 24
static let appDevLogoVerticalPositionMultiplier: CGFloat = 1.2

static let introDuration: Double = 1.5
static let transitionDuration: Double = 0.35
}

/// Constants used in SignIn
enum SignIn {
static let backgroundTrailingPadding: CGFloat = 51

static let backgroundFadeDuration: Double = 1
static let backgroundFadeDelay: Double = 1
static let contentFadeDuration: Double = 1
static let contentFadeDelay: Double = 2
static let initialFadeDuration: Double = 0.3

static let cardSpacing: CGFloat = 12
static let cardYOffset: CGFloat = 200
static let firstCardDelay: Double = 2.5
static let secondCardDelay: Double = 3
static let thirdCardDelay: Double = 3.5
static let cardsHorizontalPadding: CGFloat = 76

static let buttonHorizontalPadding: CGFloat = 46
static let buttonVerticalPadding: CGFloat = 12
static let buttonCornerRadius: CGFloat = 38

static let cardPadding: CGFloat = 12
static let cardCornerRadius: CGFloat = 8

static let headerTopPadding: CGFloat = 212
static let loginLabelTopPadding: CGFloat = 89
static let cardsTopPadding: CGFloat = 24

static let spacerMinLength: CGFloat = 16

static let transitionedLogoWidth: CGFloat = 130
static let transitionedLogoHeight: CGFloat = 115

static let enteredLogoWidth: CGFloat = 173.14737
static let enteredLogoHeight: CGFloat = 152.79259

static let transitionedLogoTopPadding: CGFloat = 10
static let transitionedLogoYOffset: CGFloat = 15
static let enteredLogoYOffset: CGFloat = 160
static let hiddenLogoYOffset: CGFloat = 900

}
}
6 changes: 2 additions & 4 deletions Uplift/Utils/Custom/CustomLoadingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,14 @@ struct CustomLoadingView: View {

private var spinningSpinner: some View {
Constants.Images.spokes
.resizable()
.aspectRatio(contentMode: .fit)
.resizable().scaledToFit()
.frame(width: 175, height: 175)
.rotationEffect(.degrees(rotation))
}

private var bobbingLogo: some View {
Constants.Images.logoTransparent
.resizable()
.aspectRatio(contentMode: .fit)
.resizable().scaledToFit()
.frame(width: 200, height: 176)
.shadow(color: .orange.opacity(0.5), radius: 20)
.offset(y: isAnimating ? -8 : 8)
Expand Down
58 changes: 58 additions & 0 deletions Uplift/ViewModels/IntroAnimationViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// IntroAnimationViewModel.swift
// Uplift
//
// Created by Kaylee Ulep on 9/11/26.
// Copyright © 2026 Cornell AppDev. All rights reserved.
//

import SwiftUI

final class IntroAnimationViewModel: ObservableObject {

// MARK: - Properties

@Published var hasEntered = false
@Published var isFadingOut = false

// MARK: - Helpers

func appDevLogoYOffset(for height: CGFloat) -> CGFloat {
hasEntered ? 0 : height
}

// MARK: - Animation

@MainActor
func startAnimation(
for height: CGFloat,
onTransition: (() -> Void)?,
onFinished: (() -> Void)?
) async {
guard height > 0 else { return }

hasEntered = true

try? await Task.sleep(
for: .seconds(Constants.IntroAnimation.introDuration)
)

guard !Task.isCancelled else { return }

withAnimation(
.smooth(duration: Constants.IntroAnimation.transitionDuration)
) {
isFadingOut = true
}

onTransition?()

try? await Task.sleep(
for: .seconds(Constants.IntroAnimation.transitionDuration)
)

guard !Task.isCancelled else { return }

onFinished?()
}
}
98 changes: 98 additions & 0 deletions Uplift/ViewModels/SignInViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// SignInViewModel.swift
// Uplift
//
// Created by Kaylee Ulep on 9/11/26.
// Copyright © 2026 Cornell AppDev. All rights reserved.
//

import SwiftUI

final class SignInAnimationViewModel: ObservableObject {

// MARK: - Phase

enum Phase {
case hidden
case entered
case transitioningToSignIn
case finished
}

@Published var phase: Phase

init(hasShownIntro: Bool) {
phase = hasShownIntro ? .finished : .hidden
}

// MARK: - Computed Properties

var showIntro: Bool {
phase != .finished
}

var introLogoEntered: Bool {
switch phase {
case .entered, .transitioningToSignIn, .finished:
return true
case .hidden:
return false
}
}

var isTransitioningToSignIn: Bool {
switch phase {
case .transitioningToSignIn, .finished:
return true
case .hidden, .entered:
return false
}
}

var mainLogoSize: CGSize {
isTransitioningToSignIn
? CGSize(width: Constants.SignIn.transitionedLogoWidth, height: Constants.SignIn.transitionedLogoHeight)
: CGSize(width: Constants.SignIn.enteredLogoWidth, height: Constants.SignIn.enteredLogoHeight)
}

var mainLogoTopPadding: CGFloat {
isTransitioningToSignIn ? Constants.SignIn.transitionedLogoTopPadding : 0
}

var mainLogoYOffset: CGFloat {
if isTransitioningToSignIn {
return Constants.SignIn.transitionedLogoYOffset
}

if introLogoEntered {
return Constants.SignIn.enteredLogoYOffset
}

return Constants.SignIn.hiddenLogoYOffset
}

// MARK: - Animation

@MainActor
func startIntroLogoAnimation() async {
guard phase == .hidden else { return }

await Task.yield()

phase = .entered
}

@MainActor
func transitionToSignIn() {
withAnimation(
.smooth(duration: Constants.IntroAnimation.transitionDuration)
) {
phase = .transitioningToSignIn
}
}

@MainActor
func finish() {
phase = .finished
}
}
3 changes: 1 addition & 2 deletions Uplift/Views/Classes/ClassDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ struct ClassDetailView: View {
.placeholder {
Constants.Colors.black
}
.resizable()
.aspectRatio(contentMode: .fill)
.resizable().scaledToFill()
.stretchy(geometry)
}
.frame(height: 360)
Expand Down
Loading