top view will shrink and fade into another view
This commit is contained in:
@@ -31,7 +31,6 @@ struct FeelsApp: App {
|
||||
}.onChange(of: scenePhase) { phase in
|
||||
if phase == .background {
|
||||
BGTask.scheduleBackgroundProcessing()
|
||||
print("background")
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import CoreData
|
||||
|
||||
struct AddMoodHeaderView: View {
|
||||
private let savedOnboardingData = UserDefaultsStore.getOnboarding()
|
||||
|
||||
|
||||
let addItemHeaderClosure: ((Mood, Date) -> Void)
|
||||
|
||||
var overrideDay: DayOptions?
|
||||
@@ -34,7 +34,7 @@ struct AddMoodHeaderView: View {
|
||||
}, label: {
|
||||
mood.icon
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50, alignment: .center)
|
||||
.frame(width: CGFloat(50), height: CGFloat(50), alignment: .center)
|
||||
.foregroundColor(mood.color)
|
||||
})
|
||||
|
||||
@@ -42,13 +42,12 @@ struct AddMoodHeaderView: View {
|
||||
}.frame(minWidth: 0, maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
}
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
.frame(minHeight: 85, maxHeight: 140)
|
||||
.frame(minHeight: 88, maxHeight: 150)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.padding()
|
||||
}
|
||||
|
||||
private func getTitle() -> String {
|
||||
|
||||
@@ -17,9 +17,14 @@ struct ContentView: View {
|
||||
@State private var showTodayInput = true
|
||||
@State private var selectedEntry: MoodEntry?
|
||||
@State private var showUpdateEntryAlert = false
|
||||
|
||||
@State private var headerHeight: CGFloat = 150
|
||||
|
||||
let minHeaderHeight = 88.0
|
||||
let maxHeaderHeight = 150.0
|
||||
@State private var headerOpacity: Double = 1.0
|
||||
|
||||
@ObservedObject var viewModel = ContentModeViewModel()
|
||||
|
||||
|
||||
init(){
|
||||
UITabBar.appearance().backgroundColor = UIColor.systemBackground
|
||||
}
|
||||
@@ -106,50 +111,86 @@ struct ContentView: View {
|
||||
return formatter.string(from: NSNumber(integerLiteral: day)) ?? ""
|
||||
}
|
||||
|
||||
func calcuateViewAlpha() {
|
||||
let perc = (((Double(headerHeight) - minHeaderHeight) * 100) / (maxHeaderHeight - minHeaderHeight)) / 100
|
||||
headerOpacity = perc
|
||||
}
|
||||
|
||||
func calculateHeight(minHeight: CGFloat, maxHeight: CGFloat, yOffset: CGFloat) {
|
||||
calcuateViewAlpha()
|
||||
|
||||
let newValue = maxHeight + yOffset
|
||||
// If scrolling up, yOffset will be a negative number
|
||||
if newValue < minHeight {
|
||||
// SCROLLING UP
|
||||
// Never go smaller than our minimum height
|
||||
headerHeight = minHeight
|
||||
return
|
||||
}
|
||||
|
||||
if newValue > maxHeight {
|
||||
// SCROLLING UP
|
||||
// Never go smaller than our minimum height
|
||||
headerHeight = maxHeight
|
||||
return
|
||||
}
|
||||
|
||||
// SCROLLING DOWN
|
||||
headerHeight = newValue
|
||||
}
|
||||
|
||||
private var listView: some View {
|
||||
VStack {
|
||||
List {
|
||||
// for reach year
|
||||
ForEach(viewModel.grouped.sorted(by: {
|
||||
$0.key > $1.key
|
||||
}), id: \.key) { year, months in
|
||||
|
||||
// for reach month
|
||||
ForEach(months.sorted(by: {
|
||||
ScrollView {
|
||||
ZStack {
|
||||
Color(.systemBackground).edgesIgnoringSafeArea(.bottom)
|
||||
.cornerRadius(10)
|
||||
|
||||
LazyVStack {
|
||||
// for reach year
|
||||
ForEach(viewModel.grouped.sorted(by: {
|
||||
$0.key > $1.key
|
||||
}), id: \.key) { month, entries in
|
||||
Section(header:
|
||||
HStack{
|
||||
Text(monthName(fromMonthInt: month))
|
||||
.font(.title2)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
Text(String(year))
|
||||
.font(.title2)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
}) {
|
||||
// for reach all entries
|
||||
ForEach(entries.sorted(by: {
|
||||
return $0.forDate! > $1.forDate!
|
||||
}), id: \.self) { entry in
|
||||
entryListView(entry: entry)
|
||||
.onTapGesture(perform: {
|
||||
selectedEntry = entry
|
||||
showUpdateEntryAlert = true
|
||||
})
|
||||
}.onDelete(perform: { offsets in
|
||||
withAnimation {
|
||||
viewModel.delete(offsets: offsets, inMonth: month, inYear: year)
|
||||
}
|
||||
})
|
||||
}), id: \.key) { year, months in
|
||||
|
||||
// for reach month
|
||||
ForEach(months.sorted(by: {
|
||||
$0.key > $1.key
|
||||
}), id: \.key) { month, entries in
|
||||
Section(header:
|
||||
HStack{
|
||||
Text(monthName(fromMonthInt: month))
|
||||
.font(.title2)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
Text(String(year))
|
||||
.font(.title2)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
}) {
|
||||
// for reach all entries
|
||||
ForEach(entries.sorted(by: {
|
||||
return $0.forDate! > $1.forDate!
|
||||
}), id: \.self) { entry in
|
||||
entryListView(entry: entry)
|
||||
.onTapGesture(perform: {
|
||||
selectedEntry = entry
|
||||
showUpdateEntryAlert = true
|
||||
})
|
||||
}.onDelete(perform: { offsets in
|
||||
withAnimation {
|
||||
viewModel.delete(offsets: offsets, inMonth: month, inYear: year)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GeometryReader { proxy in
|
||||
let offset = proxy.frame(in: .named("scroll")).minY
|
||||
Color.clear.preference(key: ViewOffsetKey.self, value: offset)
|
||||
}
|
||||
}
|
||||
.background(Color.clear.ignoresSafeArea())
|
||||
.onAppear {
|
||||
// Set the default to clear
|
||||
UITableView.appearance().backgroundColor = .clear
|
||||
}
|
||||
}
|
||||
.coordinateSpace(name: "scroll")
|
||||
.onPreferenceChange(ViewOffsetKey.self) { value in
|
||||
calculateHeight(minHeight: 88, maxHeight: 180, yOffset: value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,12 +232,13 @@ struct ContentView: View {
|
||||
viewModel.add(mood: mood, forDate: date)
|
||||
}
|
||||
})
|
||||
.frame(height: 180)
|
||||
.frame(height: headerHeight)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
} else {
|
||||
HeaderStatsView(fakeData: false, backDays: 30)
|
||||
.frame(height: 180)
|
||||
// should match backDays above
|
||||
.frame(height: headerHeight)
|
||||
|
||||
// should match backDays above
|
||||
Text(String(format: String(localized: "content_view_header_title"), 30))
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
@@ -233,26 +275,50 @@ struct ContentView: View {
|
||||
|
||||
private var mainView: some View {
|
||||
ZStack {
|
||||
|
||||
BGView().equatable()
|
||||
|
||||
VStack{
|
||||
settingsButtonView
|
||||
.padding(.top, 50)
|
||||
|
||||
if viewModel.hasNoData {
|
||||
Spacer()
|
||||
emptyView
|
||||
Spacer()
|
||||
} else {
|
||||
headerView
|
||||
listView
|
||||
ZStack {
|
||||
VStack {
|
||||
headerView
|
||||
Spacer()
|
||||
}
|
||||
.opacity(headerOpacity)
|
||||
|
||||
VStack {
|
||||
SmallRollUpHeaderView(fakeData: false, backDays: 30)
|
||||
.padding([.leading, .trailing])
|
||||
Spacer()
|
||||
}
|
||||
.opacity(1 - headerOpacity)
|
||||
|
||||
listView
|
||||
.padding([.leading, .trailing])
|
||||
.padding(.top, headerHeight+10)
|
||||
.padding(.bottom, 60)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ViewOffsetKey: PreferenceKey {
|
||||
typealias Value = CGFloat
|
||||
static var defaultValue = CGFloat.zero
|
||||
static func reduce(value: inout Value, nextValue: () -> Value) {
|
||||
value += nextValue()
|
||||
}
|
||||
}
|
||||
|
||||
private let itemFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .short
|
||||
|
||||
@@ -206,7 +206,6 @@ struct SettingsView: View {
|
||||
Toggle(String(localized: "settings_use_cloudkit_title"),
|
||||
isOn: $useCloudKit)
|
||||
.onChange(of: useCloudKit) { value in
|
||||
print(value)
|
||||
PersistenceController.shared.switchContainer()
|
||||
}
|
||||
.padding()
|
||||
|
||||
65
Shared/views/SmallHeaderView.swift
Normal file
65
Shared/views/SmallHeaderView.swift
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// SmallHeaderView.swift
|
||||
// Feels (iOS)
|
||||
//
|
||||
// Created by Trey Tartt on 1/28/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SmallRollUpHeaderView: View {
|
||||
var entries = [(Mood, Int)]()
|
||||
let backDays: Int
|
||||
|
||||
init(fakeData: Bool, backDays: Int) {
|
||||
self.backDays = backDays
|
||||
var moodEntries: [MoodEntry]?
|
||||
|
||||
if fakeData {
|
||||
moodEntries = PersistenceController.shared.randomEntries(count: 10)
|
||||
} else {
|
||||
var daysAgo = Calendar.current.date(byAdding: .day, value: -backDays, to: Date())!
|
||||
daysAgo = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: daysAgo)!
|
||||
|
||||
moodEntries = PersistenceController.shared.getData(startDate: daysAgo, endDate: Date(), includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
if let moodEntries = moodEntries {
|
||||
for (_, mood) in Mood.allValues.enumerated() {
|
||||
entries.append((mood, moodEntries.filter({
|
||||
Int($0.moodValue) == mood.rawValue
|
||||
}).count))
|
||||
}
|
||||
}
|
||||
|
||||
entries = entries.sorted(by: {
|
||||
$0.0.rawValue > $1.0.rawValue
|
||||
})
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
ForEach(entries, id: \.0) { (mood, value) in
|
||||
Text(String(value))
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(mood.color)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
|
||||
Text(String(format: String(localized: "content_view_header_title"), self.backDays))
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.padding(.top, 2)
|
||||
}
|
||||
.padding([.top])
|
||||
}
|
||||
}
|
||||
|
||||
struct SmallHeaderView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SmallRollUpHeaderView(fakeData: true, backDays: 30)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user