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 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
32 changes: 20 additions & 12 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 @@ -433,7 +439,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = YGAZHQXHH4;
DEVELOPMENT_TEAM = NWK2EYP5Q6;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
Expand All @@ -447,7 +453,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo;
PRODUCT_BUNDLE_IDENTIFIER = dev.andrewcowley.MakeItSo;
PRODUCT_NAME = MakeItSo;
SDKROOT = iphoneos;
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -463,7 +469,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = YGAZHQXHH4;
DEVELOPMENT_TEAM = NWK2EYP5Q6;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
Expand All @@ -477,7 +483,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo;
PRODUCT_BUNDLE_IDENTIFIER = dev.andrewcowley.MakeItSo;
PRODUCT_NAME = MakeItSo;
SDKROOT = iphoneos;
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -493,10 +499,11 @@
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;
DEVELOPMENT_TEAM = YGAZHQXHH4;
DEVELOPMENT_TEAM = NWK2EYP5Q6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -507,7 +514,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 12.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo;
PRODUCT_BUNDLE_IDENTIFIER = dev.andrewcowley.MakeItSo;
PRODUCT_NAME = MakeItSo;
SDKROOT = macosx;
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -521,10 +528,11 @@
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;
DEVELOPMENT_TEAM = YGAZHQXHH4;
DEVELOPMENT_TEAM = NWK2EYP5Q6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -535,7 +543,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 12.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = dev.peterfriese.MakeItSo;
PRODUCT_BUNDLE_IDENTIFIER = dev.andrewcowley.MakeItSo;
PRODUCT_NAME = MakeItSo;
SDKROOT = macosx;
SWIFT_EMIT_LOC_STRINGS = YES;
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 @@ -3,6 +3,7 @@
// MakeItSo
//
// Created by Peter Friese on 23.11.21.
// Contributing editor: Andrew Cowley on 8th Dec 2021
// Copyright © 2021 Google LLC. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -16,59 +17,8 @@
// 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
import Combine

extension Date {
func formattedRelativeToday() -> String {
if Calendar.autoupdatingCurrent.isDateInToday(self)
|| Calendar.autoupdatingCurrent.isDateInYesterday(self)
|| Calendar.autoupdatingCurrent.isDateInTomorrow(self) {

let formatStyle = Date.RelativeFormatStyle(
presentation: .named,
unitsStyle: .wide,
capitalizationContext: .beginningOfSentence)

return self.formatted(formatStyle)
}
else {
return self.formatted(date: .complete, time: .omitted)
}
}

func nearestHour() -> Date? {
var components = NSCalendar.current.dateComponents([.minute], from: self)
let minute = components.minute ?? 0
components.minute = minute >= 30 ? 60 - minute : -minute
return Calendar.current.date(byAdding: components, to: self)
}

func nextHour(basedOn date: Date? = nil) -> Date? {
let other = date ?? self

var timeComponents = Calendar.current.dateComponents([.hour, .minute], from: other)
let minute = timeComponents.minute ?? 0
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,
day: dateComponents.day,
hour: timeComponents.hour,
minute: timeComponents.minute)

return Calendar.current.date(from: newDateComponents)
}

func startOfDay() -> Date {
Calendar.current.startOfDay(for: self)
}
}

import SwiftUI //Needed for withOptionalAnimation

class ReminderDetailsViewModel: ObservableObject {
@Published var reminder: Reminder
Expand Down Expand Up @@ -129,12 +79,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 +99,89 @@ 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 single source of the truth for the
// view state of the pickers (instead of two separate booleans which could both
// mistakenly be set to true. Also allows each of the 6 transition animations to be controlled
// precisely in one place.
enum PickerState {
case none, date, time
}
@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)
}
}
}

// The following Date extension functions are only currently used in this view model
// so for now, keep them here. If used elsewhere at a later date, they should be moved
// to their own extension file.
extension Date {
func formattedRelativeToday() -> String {
if !Calendar.autoupdatingCurrent.isDateInToday(self),
!Calendar.autoupdatingCurrent.isDateInYesterday(self),
!Calendar.autoupdatingCurrent.isDateInTomorrow(self) {
return self.formatted(date: .complete, time: .omitted)
}
else
{
let formatStyle = Date.RelativeFormatStyle(
presentation: .named,
unitsStyle: .wide,
capitalizationContext: .beginningOfSentence)
return self.formatted(formatStyle)
}
}

func nextHour(basedOn date: Date? = nil) -> Date? {
var timeComponents = Calendar.current.dateComponents([.hour, .minute], from: date ?? self)
let minute = timeComponents.minute ?? 0
timeComponents.minute = 60 - minute
return Calendar.current.date(byAdding: timeComponents, to: self)
}

func startOfDay() -> Date {
Calendar.current.startOfDay(for: self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class RemindersListViewModel: ObservableObject {

return previousIndex
}
.delay(for: 0.01, scheduler: RunLoop.main) // <-- this helps reduce the visual jank
// .delay(for: 0.01, scheduler: RunLoop.main) // <-- this helps reduce the visual jank
.sink { index in
self.reminders.remove(at: index)
}
Expand Down
Loading