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

Update DayRangeSelectionDemoViewController.swift #326

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -1,115 +1,94 @@
// Created by Bryan Keller on 6/18/20.
// Copyright © 2020 Airbnb Inc. 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 HorizonCalendar
import UIKit
import HorizonCalendar

final class DayRangeSelectionDemoViewController: BaseDemoViewController {

// MARK: Internal

override func viewDidLoad() {
super.viewDidLoad()

title = "Day Range Selection"

calendarView.daySelectionHandler = { [weak self] day in
guard let self else { return }

DayRangeSelectionHelper.updateDayRange(
afterTapSelectionOf: day,
existingDayRange: &selectedDayRange)

calendarView.setContent(makeContent())
}

calendarView.multiDaySelectionDragHandler = { [weak self, calendar] day, state in
guard let self else { return }

DayRangeSelectionHelper.updateDayRange(
afterDragSelectionOf: day,
existingDayRange: &selectedDayRange,
initialDayRange: &selectedDayRangeAtStartOfDrag,
state: state,
calendar: calendar)

calendarView.setContent(makeContent())
}
}

override func makeContent() -> CalendarViewContent {
let startDate = calendar.date(from: DateComponents(year: 2020, month: 01, day: 01))!
let endDate = calendar.date(from: DateComponents(year: 2021, month: 12, day: 31))!

let dateRanges: Set<ClosedRange<Date>>
let selectedDayRange = selectedDayRange
if
let selectedDayRange,
let lowerBound = calendar.date(from: selectedDayRange.lowerBound.components),
let upperBound = calendar.date(from: selectedDayRange.upperBound.components)
{
dateRanges = [lowerBound...upperBound]
} else {
dateRanges = []
// Properties for storing multiple date ranges and their respective colors
private var dateRanges: [ClosedRange<Date>] = []
private var dateRangeColors: [ClosedRange<Date>: UIColor] = [:]
private var currentRangeStart: Date?

override func viewDidLoad() {
super.viewDidLoad()

title = "Day Range Selection"

calendarView.daySelectionHandler = { [weak self] day in
guard let self = self, let date = self.calendar.date(from: day.components) else { return }

if let start = self.currentRangeStart {
// Complete the current range and prompt for a color
let newRange = start...date
self.dateRanges.append(newRange)
self.currentRangeStart = nil // Reset the start date for a new range

self.promptForColorSelection(dateRange: newRange) { color in
self.dateRangeColors[newRange] = color
self.calendarView.setContent(self.makeContent())
}
} else {
// Start a new range
self.currentRangeStart = date
}
}
}

return CalendarViewContent(
calendar: calendar,
visibleDateRange: startDate...endDate,
monthsLayout: monthsLayout)

.interMonthSpacing(24)
.verticalDayMargin(8)
.horizontalDayMargin(8)

.dayItemProvider { [calendar, dayDateFormatter] day in
var invariantViewProperties = DayView.InvariantViewProperties.baseInteractive

let isSelectedStyle: Bool
if let selectedDayRange {
isSelectedStyle = day == selectedDayRange.lowerBound || day == selectedDayRange.upperBound
} else {
isSelectedStyle = false
private func promptForColorSelection(dateRange: ClosedRange<Date>, completion: @escaping (UIColor) -> Void) {
let alert = UIAlertController(title: "Select Color", message: "Choose a color for the selected date range", preferredStyle: .actionSheet)

let colors: [UIColor: String] = [.red: "Red", .green: "Green", .blue: "Blue", .orange: "Orange"]
for (color, name) in colors {
alert.addAction(UIAlertAction(title: name, style: .default, handler: { _ in
completion(color)
}))
}

alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}

if isSelectedStyle {
invariantViewProperties.backgroundShapeDrawingConfig.fillColor = .systemBackground
invariantViewProperties.backgroundShapeDrawingConfig.borderColor = UIColor(.accentColor)
override func makeContent() -> CalendarViewContent {
let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2020, month: 01, day: 01))!
let endDate = calendar.date(from: DateComponents(year: 2021, month: 12, day: 31))!

// Map your date ranges to ClosedRange<Date> using correct component extraction
let dateRanges = self.dateRanges.map { range -> ClosedRange<Date> in
let startComponents = calendar.dateComponents([.year, .month, .day], from: range.lowerBound)
let endComponents = calendar.dateComponents([.year, .month, .day], from: range.upperBound)
let start = calendar.date(from: startComponents)!
let end = calendar.date(from: endComponents)!
return start...end
}

let date = calendar.date(from: day.components)

return DayView.calendarItemModel(
invariantViewProperties: invariantViewProperties,
content: .init(
dayText: "\(day.day)",
accessibilityLabel: date.map { dayDateFormatter.string(from: $0) },
accessibilityHint: nil))
}

.dayRangeItemProvider(for: dateRanges) { dayRangeLayoutContext in
DayRangeIndicatorView.calendarItemModel(
invariantViewProperties: .init(),
content: .init(
framesOfDaysToHighlight: dayRangeLayoutContext.daysAndFrames.map { $0.frame }))
}
}

// MARK: Private

private var selectedDayRange: DayComponentsRange?
private var selectedDayRangeAtStartOfDrag: DayComponentsRange?
return CalendarViewContent(
calendar: calendar,
visibleDateRange: startDate...endDate,
monthsLayout: monthsLayout)
.interMonthSpacing(24)
.verticalDayMargin(8)
.horizontalDayMargin(8)
.dayItemProvider { [weak self, dateRangeColors] day in
guard let self = self else { return nil }
var invariantViewProperties = DayView.InvariantViewProperties.baseInteractive
let date = calendar.date(from: day.components)!

// Apply colors to date ranges
for (range, color) in dateRangeColors {
if range.contains(date) {
invariantViewProperties.backgroundShapeDrawingConfig.borderColor = color
invariantViewProperties.backgroundShapeDrawingConfig.fillColor = color.withAlphaComponent(0.15)
break
}
}

return DayView.calendarItemModel(
invariantViewProperties: invariantViewProperties,
content: .init(
dayText: "\(day.day)",
accessibilityLabel: self.dayDateFormatter.string(from: date),
accessibilityHint: nil))
}
}

}