add apple tv app

This commit is contained in:
Trey t
2024-06-18 12:03:56 -05:00
parent addeca4ead
commit 7d2b6b3e6e
134 changed files with 869 additions and 37 deletions

View File

@@ -0,0 +1,161 @@
//
// AllWorkoutsListView.swift
// Werkout_ios
//
// Created by Trey Tartt on 7/7/23.
//
import SwiftUI
struct AllWorkoutsListView: View {
enum SortType: String, CaseIterable {
case name = "Name"
case date = "Date"
}
@State var searchString: String = ""
@Binding var uniqueWorkoutUsers: [RegisteredUser]?
@State private var filteredRegisterdUser: RegisteredUser?
let workouts: [Workout]
let selectedWorkout: ((Workout) -> Void)
@State var filteredWorkouts = [Workout]()
var refresh: (() -> Void)
@State var currentSort: SortType?
var body: some View {
VStack {
if let filteredRegisterdUser = filteredRegisterdUser {
Text((filteredRegisterdUser.firstName ?? "NA") + "'s Workouts")
}
ScrollView {
LazyVStack(spacing: 20) {
ForEach(filteredWorkouts, id:\.id) { workout in
WorkoutOverviewView(workout: workout)
.padding([.leading, .trailing])
.contentShape(Rectangle())
.onTapGesture {
selectedWorkout(workout)
}
}
}
}
.refreshable {
refresh()
}
HStack {
TextField("Filter" ,text: $searchString)
.padding()
.textFieldStyle(OvalTextFieldStyle())
if let uniqueWorkoutUsers = uniqueWorkoutUsers {
Menu(content: {
ForEach(uniqueWorkoutUsers, id: \.self) { index in
Button(action: {
filteredRegisterdUser = index
filteredWorkouts = filterWorkouts()
}, label: {
Text((index.firstName ?? "") + " -" + (index.lastName ?? ""))
})
}
Button(action: {
filteredRegisterdUser = nil
filteredWorkouts = filterWorkouts()
}, label: {
Text("All")
})
}, label: {
Image(systemName: filteredRegisterdUser == nil ? "person.2" : "person.2.fill")
.padding(.trailing)
})
}
Menu(content: {
ForEach(SortType.allCases, id: \.self) { index in
Button(action: {
sortWorkouts(sortType: index)
}, label: {
Text(index.rawValue)
})
}
}, label: {
Image(systemName: "list.number")
.padding(.trailing)
})
}
}
.onChange(of: searchString) { newValue in
filteredWorkouts = filterWorkouts()
}
.onAppear{
filteredWorkouts = filterWorkouts()
}
}
func sortWorkouts(sortType: SortType) {
if currentSort == sortType {
filteredWorkouts = filteredWorkouts.reversed()
return
}
switch sortType {
case .name:
filteredWorkouts = filteredWorkouts.sorted(by: {
$0.name < $1.name
})
case .date:
filteredWorkouts = filteredWorkouts.sorted(by: {
$0.createdAt ?? Date() < $1.createdAt ?? Date()
})
}
currentSort = sortType
}
func filterWorkouts() -> [Workout] {
var matchingWorkouts = [Workout]()
if (!searchString.isEmpty && searchString.count > 0) {
matchingWorkouts = workouts.filter({
if $0.name.lowercased().contains(searchString.lowercased()) {
return true
}
if let equipment = $0.equipment?.joined(separator: "").lowercased(),
equipment.contains(searchString.lowercased()) {
return true
}
if let muscles = $0.muscles?.joined(separator: "").lowercased(),
muscles.contains(searchString.lowercased()) {
return true
}
return false
})
}
if matchingWorkouts.isEmpty {
matchingWorkouts.append(contentsOf: workouts)
}
if let filteredRegisterdUser = filteredRegisterdUser {
matchingWorkouts = matchingWorkouts.filter({
$0.registeredUser == filteredRegisterdUser
})
}
return matchingWorkouts
}
}
struct AllWorkoutsListView_Previews: PreviewProvider {
static var previews: some View {
AllWorkoutsListView(uniqueWorkoutUsers: .constant([]),
workouts: PreviewData.allWorkouts(),
selectedWorkout: { workout in },
refresh: { })
}
}

View File

@@ -0,0 +1,204 @@
//
// AllWorkoutsView.swift
// Werkout_ios
//
// Created by Trey Tartt on 6/15/23.
//
import Foundation
import SwiftUI
import HealthKit
enum MainViewTypes: Int, CaseIterable {
case AllWorkout = 0
case MyWorkouts
var title: String {
switch self {
case .AllWorkout:
return "All Workouts"
case .MyWorkouts:
return "Planned Workouts"
}
}
}
struct AllWorkoutsView: View {
@State var isUpdating = false
@State var workouts: [Workout]?
@State var uniqueWorkoutUsers: [RegisteredUser]?
let healthStore = HKHealthStore()
var bridgeModule = BridgeModule.shared
@State public var needsUpdating: Bool = true
@ObservedObject var dataStore = DataStore.shared
@State private var showWorkoutDetail = false
@State private var selectedWorkout: Workout? {
didSet {
bridgeModule.currentExerciseInfo.workout = selectedWorkout
}
}
@State private var selectedPlannedWorkout: Workout? {
didSet {
bridgeModule.currentExerciseInfo.workout = selectedPlannedWorkout
}
}
@State private var showLoginView = false
@State private var selectedSegment: MainViewTypes = .AllWorkout
@State var selectedDate: Date = Date()
let pub = NotificationCenter.default.publisher(for: NSNotification.Name("CreatedNewWorkout"))
var body: some View {
ZStack {
if let workouts = workouts {
VStack {
AllWorkoutPickerView(mainViews: MainViewTypes.allCases,
selectedSegment: $selectedSegment,
showCurrentWorkout: {
selectedWorkout = bridgeModule.currentExerciseInfo.workout
})
switch selectedSegment {
case .AllWorkout:
if isUpdating {
ProgressView()
.progressViewStyle(.circular)
}
AllWorkoutsListView(uniqueWorkoutUsers: $uniqueWorkoutUsers,
workouts: workouts,
selectedWorkout: { workout in
selectedWorkout = workout
}, refresh: {
self.needsUpdating = true
maybeUpdateShit()
})
Divider()
case .MyWorkouts:
plannedWorkout(workouts: UserStore.shared.plannedWorkouts)
}
}
} else {
ProgressView("Updating")
}
}.onAppear{
// UserStore.shared.logout()
authorizeHealthKit()
maybeUpdateShit()
}
.sheet(item: $selectedWorkout) { item in
var isPreview = item.id == bridgeModule.currentExerciseInfo.workout?.id
let viewModel = WorkoutDetailViewModel(workout: item, isPreview: isPreview)
WorkoutDetailView(viewModel: viewModel)
}
.sheet(item: $selectedPlannedWorkout) { item in
let viewModel = WorkoutDetailViewModel(workout: item, isPreview: true)
WorkoutDetailView(viewModel: viewModel)
}
.sheet(isPresented: $showLoginView) {
LoginView(completion: {
self.needsUpdating = true
maybeUpdateShit()
})
.interactiveDismissDisabled()
}
.onReceive(pub) { (output) in
self.needsUpdating = true
maybeUpdateShit()
}
}
func plannedWorkout(workouts: [PlannedWorkout]) -> some View {
List {
ForEach(workouts, id:\.workout.name) { plannedWorkout in
HStack {
VStack(alignment: .leading) {
Text(plannedWorkout.onDate.plannedDate?.weekDay ?? "-")
.font(.title)
Text(plannedWorkout.onDate.plannedDate?.monthString ?? "-")
.font(.title)
Text(plannedWorkout.onDate.plannedDate?.dateString ?? "-")
.font(.title)
}
Divider()
VStack {
Text(plannedWorkout.workout.name)
.font(.title)
.frame(maxWidth: .infinity, alignment: .leading)
Text(plannedWorkout.workout.description ?? "")
.font(.body)
.frame(maxWidth: .infinity, alignment: .leading)
Text(plannedWorkout.onDate)
.font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading)
}
.contentShape(Rectangle())
.onTapGesture {
selectedPlannedWorkout = plannedWorkout.workout
}
}
}
}
}
func maybeUpdateShit() {
if UserStore.shared.token != nil{
if UserStore.shared.plannedWorkouts.isEmpty {
UserStore.shared.fetchPlannedWorkouts()
}
if needsUpdating {
self.isUpdating = true
dataStore.fetchAllData(completion: {
DispatchQueue.main.async {
guard let allWorkouts = dataStore.allWorkouts else {
return
}
self.workouts = allWorkouts.sorted(by: {
$0.createdAt ?? Date() < $1.createdAt ?? Date()
})
self.isUpdating = false
self.uniqueWorkoutUsers = dataStore.workoutsUniqueUsers
}
self.isUpdating = false
})
}
} else {
showLoginView = true
}
}
func authorizeHealthKit() {
let healthKitTypes: Set = [
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .oxygenSaturation)!,
HKQuantityType.workoutType()
]
healthStore.requestAuthorization(toShare: healthKitTypes, read: healthKitTypes) { (succ, error) in
if !succ {
fatalError("Error requesting authorization from health store: \(String(describing: error)))")
}
}
}
}
struct AllWorkoutsView_Previews: PreviewProvider {
static var previews: some View {
AllWorkoutsView(workouts: PreviewData.allWorkouts())
}
}