Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve animation issues with Date picker #75

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
16 changes: 12 additions & 4 deletions code/frontend/MakeItSo/MakeItSo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
49281E992760EBCB0046A465 /* ReminderDateTimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49281E982760EBCB0046A465 /* ReminderDateTimeView.swift */; };
49281E9A2760EBCB0046A465 /* ReminderDateTimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49281E982760EBCB0046A465 /* ReminderDateTimeView.swift */; };
Copy link
Owner

Choose a reason for hiding this comment

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

Duplicate entries, might be a result of manually merging this file.

Copy link
Author

Choose a reason for hiding this comment

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

agreed.

Copy link
Author

Choose a reason for hiding this comment

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

On closer inspection, the two lines are not duplicates: line 10 starts: 49281E99 vs line 11 starting: 49281E9A
The last character is different. Just to be sure, I ran 'uniq -d project.pbxproj' from the command line, and there was no output - indicating no duplicates.

Choose a reason for hiding this comment

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

agreed

881EF5BD272DC399004761E5 /* View+Focus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881EF5BC272DC399004761E5 /* View+Focus.swift */; };
887B6FAD273ED4180028263D /* EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887B6FA9273ED4180028263D /* EmptyStateView.swift */; };
887B6FAE273ED4180028263D /* EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887B6FA9273ED4180028263D /* EmptyStateView.swift */; };
Expand All @@ -33,19 +35,20 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
49281E982760EBCB0046A465 /* ReminderDateTimeView.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = ReminderDateTimeView.swift; sourceTree = "<group>"; tabWidth = 2; };
881EF5BC272DC399004761E5 /* View+Focus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Focus.swift"; sourceTree = "<group>"; };
887B6FA9273ED4180028263D /* EmptyStateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyStateView.swift; sourceTree = "<group>"; };
88A1B7422756541400DB0494 /* ReminderListRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderListRowViewModel.swift; sourceTree = "<group>"; };
88C30CD5274D1B4500E6694D /* ReminderDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderDetailsViewModel.swift; sourceTree = "<group>"; };
88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderDetailsView.swift; sourceTree = "<group>"; };
88C30CD5274D1B4500E6694D /* ReminderDetailsViewModel.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = ReminderDetailsViewModel.swift; sourceTree = "<group>"; tabWidth = 2; };
88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = ReminderDetailsView.swift; sourceTree = "<group>"; tabWidth = 2; };
88FA998C274D63A400670474 /* View+ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ConfirmationDialog.swift"; sourceTree = "<group>"; };
88FA99912750090200670474 /* View+InteractiveDismissDisable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+InteractiveDismissDisable.swift"; sourceTree = "<group>"; };
88FEECCA27275ABC00ED368C /* MakeItSoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeItSoApp.swift; sourceTree = "<group>"; };
88FEECCC27275ABD00ED368C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
88FEECD127275ABD00ED368C /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; };
88FEECD727275ABD00ED368C /* MakeItSo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MakeItSo.app; sourceTree = BUILT_PRODUCTS_DIR; };
88FEECD927275ABD00ED368C /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = "<group>"; };
88FEECEF2727FEFF00ED368C /* Reminder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reminder.swift; sourceTree = "<group>"; };
88FEECEF2727FEFF00ED368C /* Reminder.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = Reminder.swift; sourceTree = "<group>"; tabWidth = 2; };
88FEECF22728044100ED368C /* RemindersListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersListView.swift; sourceTree = "<group>"; };
88FEECF62728072D00ED368C /* RemindersListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersListViewModel.swift; sourceTree = "<group>"; };
88FEECF927280F3D00ED368C /* ReminderListRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderListRowView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -165,6 +168,7 @@
88FEECF22728044100ED368C /* RemindersListView.swift */,
88FEECF927280F3D00ED368C /* ReminderListRowView.swift */,
88E7B7BD274CF30A00AF477D /* ReminderDetailsView.swift */,
49281E982760EBCB0046A465 /* ReminderDateTimeView.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -226,7 +230,7 @@
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1310;
LastUpgradeCheck = 1310;
LastUpgradeCheck = 1320;
TargetAttributes = {
88FEECD027275ABD00ED368C = {
CreatedOnToolsVersion = 13.1;
Expand Down Expand Up @@ -291,6 +295,7 @@
88C30CD6274D1B4500E6694D /* ReminderDetailsViewModel.swift in Sources */,
88FEECDA27275ABD00ED368C /* MakeItSoApp.swift in Sources */,
881EF5BD272DC399004761E5 /* View+Focus.swift in Sources */,
49281E992760EBCB0046A465 /* ReminderDateTimeView.swift in Sources */,
88FEECF32728044100ED368C /* RemindersListView.swift in Sources */,
88FEECF72728072D00ED368C /* RemindersListViewModel.swift in Sources */,
);
Expand All @@ -305,6 +310,7 @@
88FEECFB27280F3D00ED368C /* ReminderListRowView.swift in Sources */,
88FEECDB27275ABD00ED368C /* MakeItSoApp.swift in Sources */,
88FEECF42728044100ED368C /* RemindersListView.swift in Sources */,
49281E9A2760EBCB0046A465 /* ReminderDateTimeView.swift in Sources */,
88FEECF82728072D00ED368C /* RemindersListViewModel.swift in Sources */,
88A1B7442756541400DB0494 /* ReminderListRowViewModel.swift in Sources */,
887B6FAE273ED4180028263D /* EmptyStateView.swift in Sources */,
Expand Down Expand Up @@ -493,6 +499,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
Expand Down Expand Up @@ -521,6 +528,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Foundation

enum Priority: String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
// limitations under the License.

import Foundation
import Combine
import SwiftUI

extension Date {
func formattedRelativeToday() -> String {
Expand Down Expand Up @@ -53,7 +53,7 @@ extension Date {
timeComponents.minute = minute >= 0 ? 60 : 0

let dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: self)

let newDateComponents = DateComponents(calendar: Calendar.current,
year: dateComponents.year,
month: dateComponents.month,
Expand All @@ -69,6 +69,11 @@ extension Date {
}
}

// We should never display the date picker and the time picker together
// so define an enum to control view state of the pickers
enum PickerState {
case none, date, time
}

class ReminderDetailsViewModel: ObservableObject {
@Published var reminder: Reminder
Expand Down Expand Up @@ -129,12 +134,13 @@ class ReminderDetailsViewModel: ObservableObject {
set {
if newValue == true {
reminder.dueDate = Date()
isShowingDatePicker = true
setPickerState(.date)
}
else {
hasDueTime = false
else
{
reminder.dueDate = nil
isShowingDatePicker = false
reminder.hasDueTime = false
setPickerState(.none)
}
}
}
Expand All @@ -148,27 +154,51 @@ class ReminderDetailsViewModel: ObservableObject {
guard let nearestHour = dueDate.nextHour(basedOn: Date()) else { return }
dueDate = nearestHour
reminder.hasDueTime = true
isShowingTimePicker = true
setPickerState(.time)
}
else {
else
{
dueDate = dueDate.startOfDay()
reminder.hasDueTime = false
isShowingTimePicker = false
setPickerState(.none)
}
}
}

@Published var isShowingDatePicker: Bool = false
@Published var isShowingTimePicker: Bool = false
// We should never display the date picker and the time picker together
// so define an enum to control view state of the pickers
@Published var pickerState: PickerState = .none

func toggleTimePicker() {
isShowingTimePicker.toggle()
isShowingDatePicker = false
func setPickerState(_ newValue: PickerState) {
// Dont animate if transitioning from state where date picker is shown
if pickerState == .date {
pickerState = newValue
}
else
{
// Animate transition if Accessibility setting allows.
withOptionalAnimation {
pickerState = newValue
}
}
}

func toggleDatePicker() {
isShowingDatePicker.toggle()
isShowingTimePicker = false
// Toggle the display when a date value is pressed
func datePressed() {
pickerState = pickerState == .date ? .none : .date
}
// Toggle the display when a time value is pressed
func timePressed() {
pickerState = pickerState == .time ? .none : .time
}

func withOptionalAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
if UIAccessibility.isReduceMotionEnabled {
return try body()
}
else
{
return try withAnimation(animation, body)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// ReminderDateTimeView.swift
disc0infern0 marked this conversation as resolved.
Show resolved Hide resolved
// MakeItSo
//
// Created by Andrew Cowley on 08/12/2021.
// Copyright © 2021 Google LLC. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import SwiftUI

// Make the date time toggle section in the ReminderDetailsView
struct ReminderDateTimeView: View {
@EnvironmentObject var viewModel: ReminderDetailsViewModel

var body: some View {
Toggle(isOn: $viewModel.hasDueDate) {
dateToggleLabel
}
.animation(.none, value: viewModel.pickerState )

if viewModel.pickerState == .date {
DatePicker("Date", selection: $viewModel.dueDate, displayedComponents: .date)
.datePickerStyle(.graphical)
}

Toggle(isOn: $viewModel.hasDueTime) {
timeToggleLabel
}
if viewModel.pickerState == .time {
DatePicker("Time", selection: $viewModel.dueDate, displayedComponents: .hourAndMinute)
.datePickerStyle(.wheel)
}
}

// Toggle label subviews for body
var dateToggleLabel: some View {
disc0infern0 marked this conversation as resolved.
Show resolved Hide resolved
HStack {
Image(systemName: "calendar")
.frame(width: 26, height: 26)
.background(.red)
.foregroundColor(.white)
.cornerRadius(4)
VStack(alignment: .leading) {
Text("Date")
if let dueDate = viewModel.dueDate {
Button( action: viewModel.datePressed) {
Text(dueDate.formattedRelativeToday())
.font(.caption2)
.foregroundColor(Color.accentColor) // Accent Color, which currently defaults to blue
}
}
}
}
}
var timeToggleLabel: some View {
HStack {
Image(systemName: "clock")
.frame(width: 26, height: 26) //, alignment: .center)
.background(.blue)
.foregroundColor(.white)
.cornerRadius(4)
VStack(alignment: .leading) {
Text("Time")
if viewModel.hasDueTime {
Button(action: viewModel.timePressed) {
Text(viewModel.dueDate, style: .time)
.font(.caption2)
.foregroundColor(Color.accentColor) // Accent Color, which will default to blue
}
}
}
}
}
}

struct DateTimeSection_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
Form {
Section {
Text("Header")
}
Section {
ReminderDateTimeView()
.environmentObject(ReminderDetailsViewModel(reminder: Reminder.samples[0]))
}
Section {
Text("Footer")
}
}
}
}
}
Loading