Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:

ios:
name: iOS (xcodebuild)
runs-on: macos-latest
runs-on: macos-15

steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
Expand Down
24 changes: 9 additions & 15 deletions Apps/iOS/BetterFitApp/BetterFitApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -351,21 +351,15 @@ struct BetterFitApp: App {
.padding(.vertical, 12)
.frame(maxWidth: .infinity)
.background {
if #available(iOS 26.0, *) {
shape
.fill(color.opacity(0.2))
.glassEffect(.regular.interactive(), in: shape)
} else {
shape
.fill(color.opacity(0.2))
.overlay { shape.stroke(color.opacity(0.3), lineWidth: 1) }
.shadow(
color: Color.black.opacity(0.22),
radius: 14,
x: 0,
y: 6
)
}
shape
.fill(color.opacity(0.2))
.overlay { shape.stroke(color.opacity(0.3), lineWidth: 1) }
.shadow(
color: Color.black.opacity(0.22),
radius: 14,
x: 0,
y: 6
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,7 @@ struct ActiveWorkoutView: View {

private var emptyWorkoutView: some View {
VStack(spacing: 24) {
Image(systemName: "dumbbell.fill")
.font(.system(size: 48))
.foregroundStyle(theme.accent.opacity(0.5))
FitnessIcon(systemImage: "dumbbell.fill", size: 48, color: theme.accent.opacity(0.5))

VStack(spacing: 8) {
Text("No exercises yet")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ struct ExerciseDetailView: View {
private var heroSection: some View {
Section {
VStack(spacing: 16) {
Image(systemName: "figure.strengthtraining.traditional")
.font(.system(size: 56))
.foregroundStyle(theme.accent)
FitnessIcon(systemImage: "figure.strengthtraining.traditional", size: 56, color: theme.accent)
.frame(maxWidth: .infinity)
.padding(.vertical, 8)

Expand Down
6 changes: 2 additions & 4 deletions Apps/iOS/BetterFitApp/Features/Auth/SignInView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,8 @@ struct SignInView: View {

// MARK: - Logo & Title

VStack(spacing: 16) {
Image(systemName: "figure.strengthtraining.traditional")
.font(.system(size: 80, weight: .bold))
.foregroundStyle(theme.accent)
VStack(spacing: 16) {
FitnessIcon(systemImage: "figure.strengthtraining.traditional", size: 80, color: theme.accent)

Text("BetterFit")
.bfHeading(theme: theme, size: 44, relativeTo: .largeTitle)
Expand Down
37 changes: 8 additions & 29 deletions Apps/iOS/BetterFitApp/Features/Demo/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,14 @@ struct ContentView: View {
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
if #available(iOS 26.0, *) {
GlassEffectContainer(spacing: 16) {
HStack(spacing: 10) {
BFChromeIconButton(
systemImage: "magnifyingglass",
accessibilityLabel: "Search",
theme: theme
) {
showingSearch = true
}
HStack(spacing: 10) {
BFChromeIconButton(
systemImage: "magnifyingglass",
accessibilityLabel: "Search",
theme: theme
) {
showingSearch = true
}

BFChromeIconButton(
systemImage: "paintpalette",
Expand All @@ -83,25 +81,6 @@ struct ContentView: View {
showingThemePicker = true
}
}
}
} else {
HStack(spacing: 10) {
BFChromeIconButton(
systemImage: "magnifyingglass",
accessibilityLabel: "Search",
theme: theme
) {
showingSearch = true
}

BFChromeIconButton(
systemImage: "paintpalette",
accessibilityLabel: "Change theme",
theme: theme
) {
showingThemePicker = true
}
}
}
}
}
Expand Down
40 changes: 37 additions & 3 deletions Apps/iOS/BetterFitApp/Features/Profile/ProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@ import Auth
import BetterFit
import SwiftUI

// MARK: - Animated Counter

struct AnimatedCounter: View {
let value: Double
let unit: String
let duration: Double
let formatter: (Double) -> String

@State private var displayedValue: Double = 0

init(value: Double, unit: String = "", duration: Double = 1.0, formatter: ((Double) -> String)? = nil) {
self.value = value
self.unit = unit
self.duration = duration
self.formatter = formatter ?? { "\(Int($0))\(unit.isEmpty ? "" : " \(unit)")"
}
}

var body: some View {
Text(formatter(displayedValue))
.monospacedDigit()
.onAppear {
withAnimation(.easeOut(duration: duration)) {
displayedValue = value
}
}
}
}

// MARK: - Personal Record

struct PersonalRecord: Identifiable {
Expand Down Expand Up @@ -859,9 +888,14 @@ struct ProfileView: View {
.foregroundStyle(.green)
}

Text(formatGoalValue(goal.current, unit: goal.unit))
.font(.caption.weight(.semibold))
.foregroundStyle(isCompleted ? .green : .primary)
AnimatedCounter(
value: goal.current,
unit: goal.unit,
duration: 0.8,
formatter: { formatGoalValue($0, unit: goal.unit) }
)
.font(.caption.weight(.semibold))
.foregroundStyle(isCompleted ? .green : .primary)

Text("/ \(formatGoalValue(goal.target, unit: goal.unit))")
.font(.caption)
Expand Down
47 changes: 37 additions & 10 deletions Apps/iOS/BetterFitApp/Features/RootTab/RootTabView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,23 +143,50 @@ struct RootTabView: View {
.frame(height: 54)
.frame(maxWidth: .infinity)
.background {
if #available(iOS 26.0, *) {
shape
.fill(Color.yellow)
.glassEffect(.regular.interactive(), in: shape)
} else {
shape
.fill(Color.yellow)
.overlay { shape.stroke(Color.yellow.opacity(0.3), lineWidth: 1) }
.shadow(color: Color.black.opacity(0.22), radius: 14, x: 0, y: 6)
}
StartWorkoutGlow(shape)
}
}
.buttonStyle(.plain)
.accessibilityLabel("Start Workout")
}
}

/// "The Finals" style shine/glow animation for the start workout button
private struct StartWorkoutGlow: View {
let shape: AnyShape

init<S: Shape>(_ s: S) {
self.shape = AnyShape(s)
}

@State private var animationProgress: CGFloat = 0

var body: some View {
ZStack {
shape.fill(Color.yellow)

shape
.trim(from: 0, to: animationProgress)
.stroke(
LinearGradient(
colors: [.white.opacity(0.9), .white.opacity(0), .white.opacity(0.7)],
startPoint: .leading,
endPoint: .trailing
),
lineWidth: 3
)
.blur(radius: 1)
.animation(
Animation.easeInOut(duration: 1.8).repeatForever(autoreverses: false),
value: animationProgress
)
}
.onAppear {
animationProgress = 1
}
}
}

@ViewBuilder
private func activeWorkoutControls(shape: RoundedRectangle) -> some View {
HStack(spacing: 12) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ extension WorkoutHomeView {
Circle()
.fill(theme.accent.opacity(0.22))
.frame(width: 48, height: 48)
Image(systemName: "figure.run.circle.fill")
.font(.system(size: 22, weight: .semibold))
.foregroundStyle(theme.accent)
FitnessIcon(systemImage: "figure.run.circle.fill", size: 22, color: theme.accent)
}

VStack(alignment: .leading, spacing: 4) {
Expand All @@ -77,9 +75,7 @@ extension WorkoutHomeView {
Circle()
.fill(theme.accent.opacity(0.22))
.frame(width: 36, height: 36)
Image(systemName: "figure.run.circle.fill")
.font(.system(size: 16, weight: .semibold))
.foregroundStyle(theme.accent)
FitnessIcon(systemImage: "figure.run.circle.fill", size: 16, color: theme.accent)
}

VStack(alignment: .leading, spacing: 2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,7 @@ struct WorkoutHomeView: View {

@ViewBuilder
private var toolbarContent: some View {
if #available(iOS 26.0, *) {
GlassEffectContainer(spacing: 16) {
toolbarButtons
}
} else {
toolbarButtons
}
toolbarButtons
}

@ViewBuilder
Expand Down
Loading
Loading