Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
opps. here is code
import CoreLocation
struct Home: View {
// MARK: - Incoming Parameters
var topEdge: CGFloat
var size: CGSize
// MARK: - Environment & State
@EnvironmentObject var weatherViewModel: WeatherViewModel
@StateObject private var trainingViewModel = TrainingViewModel()
@State private var offset: CGFloat = 0
@State private var isFavoriteToggled: Bool = false
@State private var scrollToTop: UUID = UUID()
@State private var lastStationID: String? = nil
// Adjustable bottom padding for the main content
@State private var bottomPadding: CGFloat = 30
// MARK: - Body
var body: some View {
let displayedStation = weatherViewModel.currentStation
// Calculate offsets used in WeatherHeaderView and TempView
let baseOffset = -offset
let positiveOffset = offset > 0 ? (offset / size.width) * 100 : 0
let titleOffset = getTitleOffset() // Subtle upward shift based on scroll
let finalOffset = baseOffset + positiveOffset + titleOffset
ZStack {
// MARK: - Gradient Background
LinearGradient(
gradient: Gradient(colors: [
Color(red: 0.0, green: 0.1, blue: 0.1), // Dark blue/gray
Color(red: 0.1, green: 0.1, blue: 0.2), // Medium blue
Color(red: 0.1, green: 0.2, blue: 0.5) // Light blue
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
.ignoresSafeArea(.container, edges: .top)
.blur(radius: min(10, offset / 15))
.overlay(
Color.black.opacity(0.15) // Slight darkening overlay
.ignoresSafeArea()
)
// MARK: - Main Scroll
ScrollViewReader { proxy in
ScrollView(.vertical, showsIndicators: false) {
VStack {
// Dummy view to scroll to top
Color.clear
.frame(height: 0)
.id(scrollToTop)
// MARK: - Weather Header
WeatherHeaderView(displayedStation: displayedStation)
.offset(y: finalOffset)
// MARK: - Temperature View
TempView(
displayedStation: displayedStation,
isFavoriteToggled: $isFavoriteToggled
) {
toggleFavorite(for: displayedStation)
}
.offset(y: finalOffset)
.opacity(getTempViewOpacity())
// MARK: - Wind Details
if let stationID = displayedStation?.stationID {
WindDetailsView(stationID: stationID)
.padding(.top, 10)
.environmentObject(weatherViewModel)
// MARK: - Weather Data
WeatherDataView(
stationID: stationID,
stations: weatherViewModel.weatherData,
trainingViewModel: trainingViewModel
)
.environmentObject(weatherViewModel) // Provide the environment object
.id(stationID) // Force a refresh if the station ID changes
.onChange(of: weatherViewModel.currentStation?.stationID) { oldID, newID in
guard let newID = newID else { return }
guard newID != lastStationID else { return }
lastStationID = newID
withAnimation {
proxy.scrollTo(scrollToTop, anchor: .top)
}
}
.padding(.bottom, bottomPadding)
.environmentObject(weatherViewModel)
} else {
// Loading indicator if no station is displayed
ProgressView("Loading station data...")
.foregroundColor(.white)
.padding()
.background(Color.black.opacity(0.3))
.cornerRadius(10)
}
}
.padding(.top, 25)
.padding(.top, topEdge)
.padding(.horizontal)
.safeAreaInset(edge: .bottom) {
Color.clear.frame(height: 10)
}
.offsetChangeHome { rect in
offset = rect.minY
}
}
// Also update this one to the TWO-parameter closure
.onChange(of: weatherViewModel.currentStation?.stationID) { oldID, newID in
guard let newID = newID else { return }
guard newID != lastStationID else { return }
lastStationID = newID
withAnimation {
proxy.scrollTo(scrollToTop, anchor: .top)
}
}
}
}
// MARK: - Favorite Limit Alert
.alert(isPresented: $weatherViewModel.showFavoriteLimitAlert) {
Alert(
title: Text("Favorite Limit Reached"),
message: Text("You can only have up to 5 favorite stations."),
dismissButton: .default(Text("OK"))
)
}
}
}
// MARK: - Private Methods
extension Home {
private func toggleFavorite(for station: RawsWeatherStation?) {
guard let station = station else { return }
weatherViewModel.toggleFavoriteStatus(for: station)
}
private func getTitleOffset() -> CGFloat {
let progress = max(0, min(1, -offset / 120))
return -progress * 34
}
private func getTempViewOpacity() -> CGFloat {
let fadeOutStart: CGFloat = 0
let fadeOutEnd: CGFloat = 100
let progress = (offset - fadeOutEnd) / (fadeOutStart - fadeOutEnd)
return max(2 - progress, 0)
}
}```
Topic:
UI Frameworks
SubTopic:
SwiftUI