DateTimePicker not displaying the right date - swift

I'm using a DateTimePicker that contains a Start Date and Time. Although the time updates properly, the date does not update based on the scrollview. Any idea what I can change to make it work?
Here's the code:
class DateTimePicker: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
// Reference from https://stackoverflow.com/questions/40878547/is-it-possible-to-have-uidatepicker-work-with-start-and-end-time
var didSelectDates: ((_ start: Date) -> Void)?
private lazy var pickerView: UIPickerView = {
let pickerView = UIPickerView()
pickerView.delegate = self
pickerView.dataSource = self
pickerView.backgroundColor = .white
return pickerView
}()
private var days = [Date]()
private var startTimes = [Date]()
// private var endTimes = [Date]()
let dayFormatter = DateFormatter()
let timeFormatter = DateFormatter()
var inputView: UIView {
return pickerView
}
func setup() {
dayFormatter.dateFormat = "EE d MMM"
timeFormatter.timeStyle = .short
days = setDays()
startTimes = setStartTimes()
// endTimes = setEndTimes()
}
// MARK: - UIPickerViewDelegate & DateSource
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
switch component {
case 0:
return days.count
case 1:
return startTimes.count
// case 2:
// return endTimes.count
default:
return 0
}
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var label: UILabel
if let view = view as? UILabel {
label = view
} else {
label = UILabel()
}
label.textColor = .black
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 15)
var text = ""
switch component {
case 0:
text = getDayString(from: days[row])
case 1:
text = getTimeString(from: startTimes[row])
// case 2:
// text = getTimeString(from: endTimes[row])
default:
break
}
label.text = text
return label
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let dayIndex = pickerView.selectedRow(inComponent: 0)
let startTimeIndex = pickerView.selectedRow(inComponent: 1)
// let endTimeIndex = pickerView.selectedRow(inComponent: 2)
guard days.indices.contains(dayIndex),
startTimes.indices.contains(startTimeIndex)
// endTimes.indices.contains(endTimeIndex)
else { return }
let startTime = startTimes[startTimeIndex]
// let endTime = endTimes[endTimeIndex]
didSelectDates?(startTime)
}
// MARK: - Private helpers
private func getDays(of date: Date) -> [Date] {
var dates = [Date]()
let calendar = Calendar.current
// first date
var currentDate = date
// adding 30 days to current date
let oneMonthFromNow = calendar.date(byAdding: .day, value: 30, to: currentDate)
// last date
let endDate = oneMonthFromNow
while currentDate <= endDate! {
dates.append(currentDate)
currentDate = calendar.date(byAdding: .day, value: 1, to: currentDate)!
}
return dates
}
private func getTimes(of date: Date) -> [Date] {
var times = [Date]()
var currentDate = date
currentDate = Calendar.current.date(bySetting: .hour, value: 7, of: currentDate)!
currentDate = Calendar.current.date(bySetting: .minute, value: 00, of: currentDate)!
let calendar = Calendar.current
let interval = 60
var nextDiff = interval - calendar.component(.minute, from: currentDate) % interval
var nextDate = calendar.date(byAdding: .minute, value: nextDiff, to: currentDate) ?? Date()
var hour = Calendar.current.component(.hour, from: nextDate)
while(hour < 23) {
times.append(nextDate)
nextDiff = interval - calendar.component(.minute, from: nextDate) % interval
nextDate = calendar.date(byAdding: .minute, value: nextDiff, to: nextDate) ?? Date()
hour = Calendar.current.component(.hour, from: nextDate)
}
return times
}
private func setDays() -> [Date] {
let today = Date()
return getDays(of: today)
}
private func setStartTimes() -> [Date] {
let today = Date()
return getTimes(of: today)
}
// private func setEndTimes() -> [Date] {
// let today = Date()
// return getTimes(of: today)
// }
private func getDayString(from: Date) -> String {
return dayFormatter.string(from: from)
}
private func getTimeString(from: Date) -> String {
return timeFormatter.string(from: from)
}
}
extension Date {
static func buildTimeRangeString(startDate: Date) -> String {
let dayFormatter = DateFormatter()
dayFormatter.dateFormat = "EEEE, MMM d"
let startTimeFormatter = DateFormatter()
startTimeFormatter.dateFormat = "h a"
// let endTimeFormatter = DateFormatter()
// endTimeFormatter.dateFormat = "h:mm a"
return String(format: "%#, %#",
dayFormatter.string(from: startDate),
startTimeFormatter.string(from: startDate))
// endTimeFormatter.string(from: endDate))
}
}
(Reference: https://www.youtube.com/watch?v=vZsJwsZ3iKQ)
In the main MessagesViewController, I have :
private lazy var dateTimePicker: DateTimePicker = {
let picker = DateTimePicker()
picker.setup()
picker.didSelectDates = {[weak self](startDate) in
let text = Date.buildTimeRangeString(startDate: startDate)
self?.actualDate = startDate
self?.label.text = text
dateText = text
}
return picker
}()

Related

Restricting hours and minutes in DatePicker- swift?

hi guys im trying to create a time picker which hours are only from (2pm - 9pm) and minutes are incremented by 30 this is the picture of timePicker that i want to create
here is my code
func creatTimePicker() {
timePicker.datePickerMode = .time
timePicker.minuteInterval = 30
let timeformatter = DateFormatter()
timeformatter.dateFormat = "HH:mm"
let min = timeformatter.date(from: "5:00")
let max = timeformatter.date(from: "9:00")
timePicker.minimumDate = min
timePicker.maximumDate = max
self.contentView.addSubview(timePicker)
}
the problem is hour starts 1-12 and minute starts 00-59 what is the problem? thank you
The problem is that you need to set the date picker date property to match the minimum date as well. You need also to set the date formatter default date to today and don't forget to set the locale to "en_US_POSIX" when parsing your date string time:
extension Formatter {
static let time: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = .init(identifier: "em_US_POSIX")
formatter.dateFormat = "HH:mm"
return formatter
}()
}
let timePicker = UIDatePicker()
func creatTimePicker() {
Formatter.time.defaultDate = Calendar.current.startOfDay(for: Date())
let minimumDate = Formatter.time.date(from: "14:00")!
let maximumDate = Formatter.time.date(from: "21:00")!
timePicker.date = minimumDate
timePicker.datePickerMode = .time
timePicker.minuteInterval = 30
timePicker.minimumDate = minimumDate
timePicker.maximumDate = maximumDate
self.contentView.addSubview(timePicker)
}
You can use Calendar to constraint the time range for UIDatePicker()
let picker = UIDatePicker()
picker.datePickerMode = .time
let minDate = Calendar.current.date(bySettingHour: 14, minute: 0, second: 0, of: Date()) // 2PM
let maxDate = Calendar.current.date(bySettingHour: 21, minute: 0, second: 0, of: Date()) // 9PM
picker.minimumDate = minDate
picker.maximumDate = maxDate
This won't let user select time outside the specified time range.
In case you want to show only these hours
You can use UIPickerView
Example:
let picker = UIPickerView()
picker.dataSource = self
picker.delegate = self
let hoursRange = Array(5...9)
// Data source
func numberOfComponents(in: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
print("Com :\(component)")
if component == 0 {
return hoursRange.count
}
return 1 // For the PM indicator
}
// Delegate
func pickerView(_ pickerView: UIPickerView,
titleForRow row: Int,
forComponent component: Int) -> String? {
switch component {
case 0:
return "\(hoursRange[row])"
case 1:
return "AM"
default:
return nil
}
}

Can I use View Controller (CalendarKit) in SwiftUI application?

I want to use CalendarKit in my project github here
It's written using UIKit, but my project uses SwiftUI. Can I use CustomCalendarExampleController in SwiftUI? (maybe via UIViewControllerRepresentable or smth else?)
CustomCalendarExampleController -
class CustomCalendarExampleController: DayViewController, DatePickerControllerDelegate {
var data = [["Breakfast at Tiffany's",
"New York, 5th avenue"],
["Workout",
"Tufteparken"],
["Meeting with Alex",
"Home",
"Oslo, Tjuvholmen"],
["Beach Volleyball",
"Ipanema Beach",
"Rio De Janeiro"],
["WWDC",
"Moscone West Convention Center",
"747 Howard St"],
["Google I/O",
"Shoreline Amphitheatre",
"One Amphitheatre Parkway"],
["✈️️ to Svalbard ❄️️❄️️❄️️❤️️",
"Oslo Gardermoen"],
["💻📲 Developing CalendarKit",
"🌍 Worldwide"],
["Software Development Lecture",
"Mikpoli MB310",
"Craig Federighi"],
]
var generatedEvents = [EventDescriptor]()
var alreadyGeneratedSet = Set<Date>()
var colors = [UIColor.blue,
UIColor.yellow,
UIColor.green,
UIColor.red]
lazy var customCalendar: Calendar = {
let customNSCalendar = NSCalendar(identifier: NSCalendar.Identifier.gregorian)!
customNSCalendar.timeZone = TimeZone(abbreviation: "CEST")!
let calendar = customNSCalendar as Calendar
return calendar
}()
override func loadView() {
calendar = customCalendar
dayView = DayView(calendar: calendar)
view = dayView
}
override func viewDidLoad() {
super.viewDidLoad()
title = "CalendarKit Demo"
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Change Date",
style: .plain,
target: self,
action: #selector(presentDatePicker))
navigationController?.navigationBar.isTranslucent = false
dayView.autoScrollToFirstEvent = true
reloadData()
}
#objc func presentDatePicker() {
let picker = DatePickerController()
// let calendar = dayView.calendar
// picker.calendar = calendar
// picker.date = dayView.state!.selectedDate
picker.datePicker.timeZone = TimeZone(secondsFromGMT: 0)!
picker.delegate = self
let navC = UINavigationController(rootViewController: picker)
navigationController?.present(navC, animated: true, completion: nil)
}
func datePicker(controller: DatePickerController, didSelect date: Date?) {
if let date = date {
var utcCalendar = Calendar(identifier: .gregorian)
utcCalendar.timeZone = TimeZone(secondsFromGMT: 0)!
let offsetDate = dateOnly(date: date, calendar: dayView.calendar)
print(offsetDate)
dayView.state?.move(to: offsetDate)
}
controller.dismiss(animated: true, completion: nil)
}
func dateOnly(date: Date, calendar: Calendar) -> Date {
let yearComponent = calendar.component(.year, from: date)
let monthComponent = calendar.component(.month, from: date)
let dayComponent = calendar.component(.day, from: date)
let zone = calendar.timeZone
let newComponents = DateComponents(timeZone: zone,
year: yearComponent,
month: monthComponent,
day: dayComponent)
let returnValue = calendar.date(from: newComponents)
// let returnValue = calendar.date(bySettingHour: 0, minute: 0, second: 0, of: date)
return returnValue!
}
// MARK: EventDataSource
override func eventsForDate(_ date: Date) -> [EventDescriptor] {
if !alreadyGeneratedSet.contains(date) {
alreadyGeneratedSet.insert(date)
generatedEvents.append(contentsOf: generateEventsForDate(date))
}
return generatedEvents
}
private func generateEventsForDate(_ date: Date) -> [EventDescriptor] {
var workingDate = date.add(TimeChunk.dateComponents(hours: Int(arc4random_uniform(10) + 5)))
var events = [Event]()
for i in 0...4 {
let event = Event()
let duration = Int(arc4random_uniform(160) + 60)
let datePeriod = TimePeriod(beginning: workingDate,
chunk: TimeChunk.dateComponents(minutes: duration))
event.startDate = datePeriod.beginning!
event.endDate = datePeriod.end!
var info = data[Int(arc4random_uniform(UInt32(data.count)))]
let timezone = dayView.calendar.timeZone
print(timezone)
info.append(datePeriod.beginning!.format(with: "dd.MM.YYYY", timeZone: timezone))
info.append("\(datePeriod.beginning!.format(with: "HH:mm", timeZone: timezone)) - \(datePeriod.end!.format(with: "HH:mm", timeZone: timezone))")
event.text = info.reduce("", {$0 + $1 + "\n"})
event.color = colors[Int(arc4random_uniform(UInt32(colors.count)))]
event.isAllDay = Int(arc4random_uniform(2)) % 2 == 0
// Event styles are updated independently from CalendarStyle
// hence the need to specify exact colors in case of Dark style
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle == .dark {
event.textColor = textColorForEventInDarkTheme(baseColor: event.color)
event.backgroundColor = event.color.withAlphaComponent(0.6)
}
}
events.append(event)
let nextOffset = Int(arc4random_uniform(250) + 40)
workingDate = workingDate.add(TimeChunk.dateComponents(minutes: nextOffset))
event.userInfo = String(i)
}
print("Events for \(date)")
return events
}
private func textColorForEventInDarkTheme(baseColor: UIColor) -> UIColor {
var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
baseColor.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
return UIColor(hue: h, saturation: s * 0.3, brightness: b, alpha: a)
}
// MARK: DayViewDelegate
private var createdEvent: EventDescriptor?
override func dayViewDidSelectEventView(_ eventView: EventView) {
guard let descriptor = eventView.descriptor as? Event else {
return
}
print("Event has been selected: \(descriptor) \(String(describing: descriptor.userInfo))")
}
override func dayViewDidLongPressEventView(_ eventView: EventView) {
guard let descriptor = eventView.descriptor as? Event else {
return
}
endEventEditing()
print("Event has been longPressed: \(descriptor) \(String(describing: descriptor.userInfo))")
beginEditing(event: descriptor, animated: true)
print(Date())
}
override func dayView(dayView: DayView, didTapTimelineAt date: Date) {
endEventEditing()
print("Did Tap at date: \(date)")
}
override func dayViewDidBeginDragging(dayView: DayView) {
print("DayView did begin dragging")
}
override func dayView(dayView: DayView, willMoveTo date: Date) {
print("DayView = \(dayView) will move to: \(date)")
}
override func dayView(dayView: DayView, didMoveTo date: Date) {
print("DayView = \(dayView) did move to: \(date)")
}
override func dayView(dayView: DayView, didLongPressTimelineAt date: Date) {
print("Did long press timeline at date \(date)")
// Cancel editing current event and start creating a new one
endEventEditing()
let event = generateEventNearDate(date)
print("Creating a new event")
create(event: event, animated: true)
createdEvent = event
}
private func generateEventNearDate(_ date: Date) -> EventDescriptor {
let duration = Int(arc4random_uniform(160) + 60)
let startDate = date.subtract(TimeChunk.dateComponents(minutes: Int(CGFloat(duration) / 2)))
let event = Event()
let datePeriod = TimePeriod(beginning: startDate,
chunk: TimeChunk.dateComponents(minutes: duration))
event.startDate = datePeriod.beginning!
event.endDate = datePeriod.end!
var info = data[Int(arc4random_uniform(UInt32(data.count)))]
let timezone = dayView.calendar.timeZone
info.append(datePeriod.beginning!.format(with: "dd.MM.YYYY", timeZone: timezone))
info.append("\(datePeriod.beginning!.format(with: "HH:mm", timeZone: timezone)) - \(datePeriod.end!.format(with: "HH:mm", timeZone: timezone))")
event.text = info.reduce("", {$0 + $1 + "\n"})
event.color = colors[Int(arc4random_uniform(UInt32(colors.count)))]
event.editedEvent = event
// Event styles are updated independently from CalendarStyle
// hence the need to specify exact colors in case of Dark style
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle == .dark {
event.textColor = textColorForEventInDarkTheme(baseColor: event.color)
event.backgroundColor = event.color.withAlphaComponent(0.6)
}
}
return event
}
override func dayView(dayView: DayView, didUpdate event: EventDescriptor) {
print("did finish editing \(event)")
print("new startDate: \(event.startDate) new endDate: \(event.endDate)")
if let _ = event.editedEvent {
event.commitEditing()
}
if let createdEvent = createdEvent {
createdEvent.editedEvent = nil
generatedEvents.append(createdEvent)
self.createdEvent = nil
endEventEditing()
}
reloadData()
}
}
DayViewController -
#if os(iOS)
import UIKit
import DateToolsSwift
open class DayViewController: UIViewController, EventDataSource, DayViewDelegate {
public lazy var dayView: DayView = DayView()
public var dataSource: EventDataSource? {
get {
return dayView.dataSource
}
set(value) {
dayView.dataSource = value
}
}
public var delegate: DayViewDelegate? {
get {
return dayView.delegate
}
set(value) {
dayView.delegate = value
}
}
public var calendar = Calendar.autoupdatingCurrent {
didSet {
dayView.calendar = calendar
}
}
open override func loadView() {
view = dayView
}
override open func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = []
view.tintColor = SystemColors.systemRed
dataSource = self
delegate = self
dayView.reloadData()
let sizeClass = traitCollection.horizontalSizeClass
configureDayViewLayoutForHorizontalSizeClass(sizeClass)
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
dayView.scrollToFirstEventIfNeeded()
}
open override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
configureDayViewLayoutForHorizontalSizeClass(newCollection.horizontalSizeClass)
}
open func configureDayViewLayoutForHorizontalSizeClass(_ sizeClass: UIUserInterfaceSizeClass) {
dayView.transitionToHorizontalSizeClass(sizeClass)
}
// MARK: - CalendarKit API
open func move(to date: Date) {
dayView.move(to: date)
}
open func reloadData() {
dayView.reloadData()
}
open func updateStyle(_ newStyle: CalendarStyle) {
dayView.updateStyle(newStyle)
}
open func eventsForDate(_ date: Date) -> [EventDescriptor] {
return [Event]()
}
// MARK: - DayViewDelegate
open func dayViewDidSelectEventView(_ eventView: EventView) {
}
open func dayViewDidLongPressEventView(_ eventView: EventView) {
}
open func dayView(dayView: DayView, didTapTimelineAt date: Date) {
}
open func dayViewDidBeginDragging(dayView: DayView) {
}
open func dayView(dayView: DayView, willMoveTo date: Date) {
}
open func dayView(dayView: DayView, didMoveTo date: Date) {
}
open func dayView(dayView: DayView, didLongPressTimelineAt date: Date) {
}
open func dayView(dayView: DayView, didUpdate event: EventDescriptor) {
}
// MARK: - Editing
open func create(event: EventDescriptor, animated: Bool = false) {
dayView.create(event: event, animated: animated)
}
open func beginEditing(event: EventDescriptor, animated: Bool = false) {
dayView.beginEditing(event: event, animated: animated)
}
open func endEventEditing() {
dayView.endEventEditing()
}
}
#endif
There is nothing interesting in DatePickerControllerDelegate.
Thanks for the replies!
Lol I don't know why it didn't work before, but if you are looking for something like this
struct CustomController: UIViewControllerRepresentable {
func updateUIViewController(_ uiViewController: UIViewController, context: Context){
}
func makeUIViewController(context: Context) -> UIViewController {
let dayViewController = CustomCalendarExampleController()
return dayViewController
}
}

FSCalendar check today date

How can I check that I clicked on today date?
https://github.com/WenchaoIOS/FSCalendar
I got the below output:
todaydateString = 2020-05-18
dateString = 2020-05-17
which is not matching:
import UIKit
class LoadViewExampleViewController: UIViewController, FSCalendarDataSource, FSCalendarDelegate {
private weak var calendar: FSCalendar!
fileprivate lazy var dateFormatter1: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
let dateString = "2020-05-15"
let dateString1 = "2020-05-16"
let dateString2 = "2020-05-13"
var selectedDates = NSMutableArray()
override func loadView() {
selectedDates = [dateString, dateString1, dateString2]
let view = UIView(frame: UIScreen.main.bounds)
view.backgroundColor = UIColor.groupTableViewBackground
self.view = view
let height: CGFloat = UIDevice.current.model.hasPrefix("iPad") ? 400 : 300
let calendar = FSCalendar(frame: CGRect(x: 0, y: self.navigationController!.navigationBar.frame.maxY, width: self.view.bounds.width, height: height))
calendar.dataSource = self
calendar.delegate = self
calendar.backgroundColor = UIColor.clear
calendar.appearance.todayColor = UIColor.gray
// calendar.appearance.borderDefaultColor = UIColor.black
//calendar.appearance.borderRadius = 0
self.view.addSubview(calendar)
self.calendar = calendar
}
func calendar(_ calendar: FSCalendar, didDeselect date: Date, at monthPosition: FSCalendarMonthPosition) {
let todaydate = Date()
let dateString = self.dateFormatter1.string(from: date)
let todaydateString = self.dateFormatter1.string(from: todaydate)
print("todaydateString = \(todaydateString)")
print("dateString = \(dateString)")
if dateString == todaydateString
{
print("GOOD")
}
}
func calendar(_ calendar: FSCalendar, imageFor date: Date) -> UIImage? {
let dateString = self.dateFormatter1.string(from: date)
if self.selectedDates.contains(dateString) {
let image : UIImage = UIImage(named: "checkbox_Tick")!
return image
}
return UIImage()
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "FSCalendar"
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
if monthPosition == .previous || monthPosition == .next {
calendar.setCurrentPage(date, animated: true)
}
}
}

Apple Mach-O Linker Error (static, not ld)

I have recently encountered the Apple Mach-O Linker Error. Most guides suggest to change bitcode in Build Settings to "No", however it only applies to the ld error, which is different from mine. I will provide a screenshot, please help to fix the bug.
The pod HandySwift is causing the bugs to appear.
Here is the Github code source for it. https://github.com/Flinesoft/HandySwift
It is from the CSV Importer pod on Cocoapods.
https://cocoapods.org/pods/CSVImporter
Click here to look at the overview of the HandySwift files
Click here for the screenshot of the error
Code referencing the error:
"static (extension in HandySwift):Swift.Double.seconds(Swift.Double) -> Swift.Double", referenced from:
//
// CalendarViewController.swift
// DBS
//
// Created by SDG on 18/10/2017.
// Copyright © 2017 DBSSDG. All rights reserved.
//
import UIKit
import JTAppleCalendar
import CSVImporter
import SystemConfiguration
enum EventTypes{
case SE,PH,SH
}
struct events{
var Title : String
var StartDate : Date
var EndDate : Date
var EventType : EventTypes
}
var PassingEvent = ("G7-G11 Mid-year Exam (4-19)", Date(), Date(), EventTypes.SE)
var TodayEvent = [events] ()
extension Array where Element:Equatable {
func removeDuplicates() -> [Element] {
var result = [Element]()
for value in self {
if result.contains(value) == false {
result.append(value)
}
}
return result
}
}
class CalendarViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIViewControllerPreviewingDelegate {
#IBOutlet weak var CalendarView: JTAppleCalendarView!
#IBOutlet weak var CalendarStackView: UIStackView!
#IBOutlet weak var EventsTableView: UITableView!
#IBOutlet weak var StackView: UIStackView!
#IBOutlet weak var year: UILabel!
#IBOutlet weak var month: UILabel!
#IBOutlet weak var todayButton: UIButton!
var didScroll = false
#IBAction func TodayButton(_ sender: Any) {
CalendarView.scrollToDate(Date())
CalendarView.deselectAllDates()
CalendarView.selectDates([Date()])
EventsTableView.reloadData()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(0.5), execute: {
self.CalendarView.selectDates([Date()])
self.EventsTableView.reloadData()
})
}
var index = 0
var CurrentDayEventsArray = [(Date, events)] ()
var CurrentDay = Date()
var DayEvents = [(Date, events)] ()
var SEBlue = UIColor(red: 97.0/255.0, green: 142.0/255.0, blue: 249.0/255.0, alpha: 1)
var SHOrange = UIColor(red: 1, green: 142.0/255.0, blue: 80.0/255.0, alpha: 1)
var currentmonth : String = ""
let formatter : DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = Calendar.current.timeZone
dateFormatter.locale = Calendar.current.locale
dateFormatter.dateFormat = "yyyy MM dd"
return dateFormatter
}()
#IBOutlet weak var DaysStack: UIStackView!
func WillAddCalendar(acrion: UIAlertAction){
let StringURL = "https://calendar.google.com/calendar/ical/g.dbs.edu.hk_tdmjqqq8vlv8keepi7a65f7j7s%40group.calendar.google.com/public/basic.ics"
let url = URL(string: StringURL)!
if isInternetAvailable(){
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}else{
let networkAlert = UIAlertController(title: "ERROR", message: "Please check your network availability.", preferredStyle: .alert)
networkAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(networkAlert, animated: true)
}
}
func ShareCalendar(action: UIAlertAction){
let StringURL = "https://calendar.google.com/calendar/ical/g.dbs.edu.hk_tdmjqqq8vlv8keepi7a65f7j7s%40group.calendar.google.com/public/basic.ics"
let url = URL(string: StringURL)!
let ActivityController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
present(ActivityController, animated: true, completion: nil)
}
func ActionSheetFunc(){
//Actions
let AddCalendarAction = UIAlertAction(title: "Add Calendar to Phone", style: .default, handler: WillAddCalendar)
let ShareAction = UIAlertAction(title: "Share Calendar", style: .default, handler: ShareCalendar)
let CancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
//Action Sheet
let ActionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
ActionSheet.addAction(AddCalendarAction)
ActionSheet.addAction(ShareAction)
ActionSheet.addAction(CancelAction)
present(ActionSheet, animated: true)
}
func AllEvents(){
performSegue(withIdentifier: "Calendar to All Events", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Calendar"
setUpCalendarView()
ParseCSV()
//UI Set up
year.frame = CGRect(x: 16, y: self.view.frame.height * 0.125, width: 100, height: 30)
todayButton.frame = CGRect(x: self.view.frame.width - todayButton.frame.size.width - 16, y: year.frame.origin.y, width: 0, height: 30)
todayButton.sizeToFit()
month.frame = CGRect(x: 16, y: year.frame.origin.y + year.frame.size.height, width: self.view.frame.width, height: 30)
CalendarView.frame.size.width = self.view.frame.width
CalendarView.frame.size.height = self.view.frame.height * 0.425
CalendarView.sizeToFit()
CalendarStackView.frame.origin.y = self.view.frame.height * 0.25
CalendarStackView.frame.origin.x = 0
CalendarStackView.frame.size.width = self.view.frame.width
CalendarStackView.frame.size.height = DaysStack.frame.height + CalendarView.frame.height
StackView.frame = CalendarStackView.frame
EventsTableView.frame.origin.y = CalendarStackView.frame.origin.y + CalendarStackView.frame.size.height
EventsTableView.frame.origin.x = 0
EventsTableView.frame.size.width = self.view.frame.width
EventsTableView.frame.size.height = self.view.frame.height - EventsTableView.frame.origin.y
EventsTableView.isScrollEnabled = true
self.registerForPreviewing(with: self, sourceView: EventsTableView)
//let EventsTableViewBottomConstraint = NSLayoutConstraint(item: EventsTableView, attribute: .bottomMargin, relatedBy: .equal, toItem: self.view, attribute: .bottomMargin, multiplier: 1, constant: 0)
//NSLayoutConstraint.activate([EventsTableViewBottomConstraint])
if #available(iOS 11.0, *) {
navigationItem.largeTitleDisplayMode = .never
}
EventsArray = [events]()
TodayEvent = [events]()
CurrentDayEventsArray = [(Date, events)]()
CalendarView.scrollToDate(Date())
TodayButton(self)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let AddCalendar = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(ActionSheetFunc))
let AllEvents = UIBarButtonItem(title: "All Events", style: .plain, target: self, action: #selector(self.AllEvents))
self.navigationItem.rightBarButtonItems = [AddCalendar, AllEvents]
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
CalendarView.selectDates([Date()])
}
func ParseCSV (){
let path = Bundle.main.path(forResource: "2017 - 2018 School Events New", ofType: "csv")!
let importer = CSVImporter<[String: String]>(path: path)
importer.startImportingRecords(structure: { (headerValues) -> Void in
}) { $0 }.onFinish { importedRecords in
for record in importedRecords {
self.formatter.dateFormat = "d/M/yyyy"
let EventStartDate = self.formatter.date(from: record["Start Date"]!)
let EventEndDate = self.formatter.date(from: record["End Date"]!)
let string = record["Title"]!
let input = string
var output = ""
var didColon = false
for i in input{
if didColon{
output += "\(i)"
}
if i == Character(":"){
didColon = true
}
}
output.removeFirst()
switch record["Type"]! {
case "PH" :
EventsArray += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .PH)]
if EventStartDate! <= Date() && EventEndDate! >= Date(){
TodayEvent += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .PH)]
}
case "SH" :
EventsArray += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SH)]
if EventStartDate! <= Date() && EventEndDate! >= Date(){
TodayEvent += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SH)]
}
case "SE" :
EventsArray += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SE)]
if EventStartDate! <= Date() && EventEndDate! >= Date(){
TodayEvent += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SE)]
}
default:
print("ERROR")
}
}
self.ParseAdoptionTimetable()
for i in TodayEvent{
self.CurrentDayEventsArray += [(Date(), i)]
}
self.EventsTableView.reloadData()
}
}
func ParseAdoptionTimetable(){
// if let url = URL(string: "http://www.dbs.edu.hk/index.php?section=calendar&listall=1") {
// do {
// let html = try String(contentsOf: url)
// for i in html.split(separator: ">") {
// if i.components(separatedBy: " adopts ").count == 2 {
// let String = (i.split(separator: "<")[0])
// print(String)
// //events(Title: i.split(separator: "<")[0], StartDate: <#T##Date#>, EndDate: <#T##Date#>, EventType: <#T##EventTypes#>)
// }
// }
// }catch{
// print("ERROR")
// }
// }
let Formatter = DateFormatter()
Formatter.dateFormat = "dd MM yyyy"
EventsArray += [events(Title: "30/4 Mon Adopts Tue Timetable", StartDate: Formatter.date(from: "30 04 2018")!, EndDate: Formatter.date(from: "30 04 2018")!, EventType: .SE), events(Title: "14/5 Mon Adopts Fri Timetable", StartDate: Formatter.date(from: "14 05 2018")!, EndDate: Formatter.date(from: "14 05 2018")!, EventType: .SE)]
EventsArray = EventsArray.sorted(by: { $0.StartDate <= $1.StartDate })
}
func setUpCalendarView(){
// Set up calendar spacing
CalendarView.minimumLineSpacing = 0
CalendarView.minimumInteritemSpacing = 0
// Set up labels
CalendarView.visibleDates{(visibleDates) in
let date = visibleDates.monthDates.first!.date
self.formatter.dateFormat = "yyyy"
self.year.text = self.formatter.string(from: date)
if self.year.text == self.formatter.string(from: Date()){
self.year.textColor = UIColor.red
} else {
self.year.textColor = UIColor.black
}
self.formatter.dateFormat = "MMMM"
self.month.text = self.formatter.string(from: date)
self.currentmonth = self.formatter.string(from: date)
if self.month.text == self.formatter.string(from: Date()){
self.month.textColor = UIColor.red
} else {
self.month.textColor = UIColor.black
}
}
}
func handleCellTextColor(view: JTAppleCell?, cellState: CellState) {
guard let validCell = view as? CustomCell else { return }
if cellState.isSelected {
validCell.selectedView.isHidden = false
} else {
validCell.selectedView.isHidden = true
}
}
func LoadEvents(view: JTAppleCell?, cellState: CellState) -> Any {
guard let validCell = view as? CustomCell else {return "Load Events Error"}
let CellDate = cellState.date
var CellDateEventsArray = [(Date, events)] ()
for event in EventsArray{
let EventStartDate = event.StartDate
let EventEndDate = event.EndDate
if CellDate >= EventStartDate && CellDate <= EventEndDate{
CellDateEventsArray += [(CellDate, event)]
}
}
CurrentDayEventsArray = CellDateEventsArray
if cellState.date == Date(){
self.EventsTableView.reloadData()
}
//CurrentDate = cellState.date
return CellDateEventsArray
}
func handleCellSelected(view: JTAppleCell?, cellState: CellState) {
guard let validCell = view as? CustomCell else { return }
var isPublicHoliday = false
for i in CurrentDayEventsArray{
if i.1.EventType == .PH{
isPublicHoliday = true
}
}
if cellState.isSelected {
validCell.datelabel.textColor = UIColor.white
}else{
if cellState.dateBelongsTo == .thisMonth{
//validCell.datelabel.textColor = UIColor.init(red: 253/255.0, green: 114/255.0, blue: 116.0/255.0, alpha: 1.0)
if cellState.day == .sunday || isPublicHoliday{
validCell.datelabel.textColor = UIColor.red
}else{
validCell.datelabel.textColor = UIColor.black
}
validCell.isUserInteractionEnabled = true
}else{
validCell.datelabel.textColor = UIColor.lightGray
//validCell.isUserInteractionEnabled = false
}
}
}
func setUpViewsForCalendar(from visibleDates: DateSegmentInfo){
let date = visibleDates.monthDates.first!.date
self.formatter.dateFormat = "yyyy"
self.year.text = self.formatter.string(from: date)
self.formatter.dateFormat = "MMMM"
self.month.text = self.formatter.string(from: date)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count = 0
for _ in CurrentDayEventsArray{
count += 1
}
if count == 0{
return 1
}
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
DayEvents = CurrentDayEventsArray
let cell = tableView.dequeueReusableCell(withIdentifier: "CalendarEventCell")! as UITableViewCell
cell.isUserInteractionEnabled = true
if CurrentDayEventsArray.isEmpty{
cell.textLabel?.text = "No events"
cell.textLabel?.textAlignment = .center
cell.detailTextLabel?.text = ""
cell.imageView?.image = nil
cell.isUserInteractionEnabled = false
cell.accessoryType = .none
return cell
}
//Manage Date
let StartDate = CurrentDayEventsArray[indexPath.row].1.StartDate
let EndDate = CurrentDayEventsArray[indexPath.row].1.EndDate
self.formatter.dateFormat = "d/M"
let StartDateString = formatter.string(from: StartDate)
let EndDateString = formatter.string(from: EndDate)
//Image
let EventType = CurrentDayEventsArray[indexPath.row].1.EventType
if let image = UIImage(named: "dot"){
let tintableImage = image.withRenderingMode(.alwaysTemplate)
cell.imageView?.image = tintableImage
}
switch EventType {
case .PH:
cell.imageView?.tintColor = UIColor.red
case .SH:
cell.imageView?.tintColor = SHOrange
case .SE:
cell.imageView?.tintColor = SEBlue
default:
cell.imageView?.tintColor = UIColor.red
}
//Title
cell.textLabel?.adjustsFontSizeToFitWidth = true
cell.textLabel?.text = String(describing: CurrentDayEventsArray[indexPath.row].1.Title)
//Subtitle
let Subtitle = "\(StartDateString) - \(EndDateString)"
if StartDate != EndDate{
cell.detailTextLabel?.text = Subtitle
}else{
cell.detailTextLabel?.text = StartDateString
}
//Arrow
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
//cell.selectionStyle = .gray
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
index = indexPath.row
PassingEvent = (DayEvents[index].1.Title, DayEvents[index].1.StartDate, DayEvents[index].1.EndDate, DayEvents[index].1.EventType)
performSegue(withIdentifier: "Detail Event", sender: self)
}
/*
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController = segue.destination as! DetailedEventViewController
DestViewController.PassingEvent = (CurrentDayEventsArray[index].1.Title, CurrentDayEventsArray[index].1.StartDate, CurrentDayEventsArray[index].1.EndDate, CurrentDayEventsArray[index].1.EventType)
}
*/
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = EventsTableView.indexPathForRow(at: location) else {
return nil
}
previewingContext.sourceRect = EventsTableView.cellForRow(at: indexPath)!.frame
let index = indexPath.row
PassingEvent = (DayEvents[index].1.Title, DayEvents[index].1.StartDate, DayEvents[index].1.EndDate, DayEvents[index].1.EventType)
let destViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Detail Event") as! DetailedEventViewController
return destViewController
return nil
}
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
navigationController?.pushViewController(viewControllerToCommit, animated: true)
}
func isInternetAvailable() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
}
extension CalendarViewController: JTAppleCalendarViewDelegate, JTAppleCalendarViewDataSource {
func calendar(_ calendar: JTAppleCalendarView, willDisplay cell: JTAppleCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) {
EventsTableView.reloadData()
}
func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
formatter.dateFormat = "yyy MM dd"
formatter.timeZone = Calendar.current.timeZone
formatter.locale = Calendar.current.locale
let startDate = formatter.date(from: "2017 09 01")
let endDate = formatter.date(from: "2019 08 31")
let generateInDates: InDateCellGeneration = .forAllMonths
let generateOutDates: OutDateCellGeneration = .tillEndOfGrid
let firstDayOfWeek: DaysOfWeek = .sunday
let parameters = ConfigurationParameters(startDate: startDate!, endDate: endDate!, numberOfRows: 4, calendar: Calendar.current, generateInDates: generateInDates, generateOutDates: generateOutDates, firstDayOfWeek: firstDayOfWeek, hasStrictBoundaries: true)
//let parameters = ConfigurationParameters(startDate: startDate!, endDate: endDate!)
return parameters
}
func calendar(_ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell {
let CalendarCell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
CalendarCell.datelabel.text = cellState.text
CalendarCell.selectedView.layer.cornerRadius = CalendarCell.selectedView.frame.width/2
CalendarCell.backgroundColor = UIColor.white
CalendarCell.EventCircle.layer.cornerRadius = CalendarCell.EventCircle.frame.width / 2
CalendarCell.EventCircle.isHidden = true
CalendarCell.SchoolHolidayBar.backgroundColor = self.SHOrange
CalendarCell.SchoolHolidayBar.isHidden = true
CalendarCell.isUserInteractionEnabled = false
if cellState.dateBelongsTo == .thisMonth{
CalendarCell.isSelected = false
}
LoadEvents(view: CalendarCell, cellState: cellState)
for i in CurrentDayEventsArray{
if i.1.EventType == .SH{
CalendarCell.SchoolHolidayBar.isHidden = true
CalendarCell.EventCircle.backgroundColor = SHOrange
CalendarCell.EventCircle.isHidden = false
break
}else if i.1.EventType == .PH{
CalendarCell.datelabel.textColor = UIColor.red
}else if i.1.EventType == .SE{
CalendarCell.EventCircle.backgroundColor = UIColor.lightGray
CalendarCell.EventCircle.isHidden = false
}else{
}
}
if cellState.date == Date(){
LoadEvents(view: CalendarCell, cellState: cellState)
EventsTableView.reloadData()
}
handleCellTextColor(view: CalendarCell, cellState: cellState)
handleCellSelected(view: CalendarCell, cellState: cellState)
return CalendarCell
}
func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleCell?, cellState: CellState) {
if didScroll{
calendar.deselect(dates: [CurrentDay])
didScroll = false
}
CurrentDay = date
//calendar.deselectAllDates()
//calendar.selectDates([date])
handleCellTextColor(view: cell, cellState: cellState)
handleCellSelected(view: cell, cellState: cellState)
LoadEvents(view: cell, cellState: cellState)
EventsTableView.reloadData()
}
func calendar(_ calendar: JTAppleCalendarView, didDeselectDate date: Date, cell: JTAppleCell?, cellState: CellState) {
handleCellTextColor(view: cell, cellState: cellState)
handleCellSelected(view: cell, cellState: cellState)
//calendar.deselect(dates: [date])
}
func calendar(_ calendar: JTAppleCalendarView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
let date = visibleDates.monthDates.first!.date
formatter.dateFormat = "yyyy"
year.text = self.formatter.string(from: date)
formatter.dateFormat = "MMMM"
month.text = self.formatter.string(from: date)
setUpCalendarView()
}
func calendarDidScroll(_ calendar: JTAppleCalendarView) {
didScroll = true
}
}
//}
In your TodayButton(_:) instead of:
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(0.5), execute: {
//...
})
do:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
//...
})
That .seconds(Int) takes an Int. So passing a Double in it by doing .seconds(0.5) makes it ambiguous as there is no .seconds(Double) in the DispatchTimeInterval enum.
To achieve this 0.5 second delay you can either do it in 2 ways:
+ 0.5
+ .milliseconds(500)

UIDatePicker show only Sunday's date only?

How we can set UIDatePicker values to show only Sunday's date in swift iOS ?
finally, I myself found solution. In didSelectRow Method check if the selected day is sunday??? if yes then ok but if not then reload component to select date of nearest sunday.
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
pickerView.reloadComponent(1)
}
let titleLabel = pickerView.viewForRow(row, forComponent: component) as? UILabel
titleLabel?.font = UIFont(name: BCGConstants.Fonts.Name.ProximaNovaBold, size: 27)!
var dayValue = pickerView.selectedRowInComponent(1) + 1
let monthValue = pickerView.selectedRowInComponent(0) + 1
var yearValue = 0
let unitFlags: NSCalendarUnit = [.Day, .Month, .Year, .Weekday]
let currentDateComponents = NSCalendar.currentCalendar().components(unitFlags, fromDate: NSDate())
if monthValue > currentDateComponents.month || (dayValue >= currentDateComponents.day && monthValue == currentDateComponents.month ) {
yearValue = currentDateComponents.year
} else {
yearValue = currentDateComponents.year + 1
}
debugPrint("\(self.isGivenDaySunday(dayValue, selectedMonth: monthValue, selectedYear: yearValue)) day = \(dayValue) month = \(monthValue) )")
let sundayCheck = self.isGivenDaySunday(pickerView.selectedRowInComponent(1) + 1, selectedMonth: pickerView.selectedRowInComponent(0) + 1, selectedYear: yearValue)
if sundayCheck.isSunday {
self.startDateTextField.text = sundayCheck.sundayDate?.fullStyleDateString
self.newBootcamp?.startDate = sundayCheck.sundayDate!
} else {
// titleLabel?.font = UIFont(name: BCGConstants.Fonts.Name.ProximaNovaBold, size: 27)!
// titleLabel?.textColor = UIColor.lightGrayColor()
if dayValue > 15 {
dayValue = pickerView.selectedRowInComponent(1) - (7 - sundayCheck.nextSundayAsWeekDay)
pickerView.selectRow(dayValue, inComponent: 1, animated: true)
} else {
dayValue = pickerView.selectedRowInComponent(1) + sundayCheck.nextSundayAsWeekDay
pickerView.selectRow(dayValue, inComponent: 1, animated: true)
}
var confirmSunday = self.isGivenDaySunday(dayValue + 1, selectedMonth: monthValue, selectedYear: yearValue)
// Added by mohsin : Reason bug : selecting previous day
if confirmSunday.sundayDate?.isLessThanDate(NSDate()) == true {
confirmSunday = self.isGivenDaySunday(dayValue, selectedMonth: monthValue, selectedYear: yearValue + 1)
//TODO: Need to be verify again : If not working fine then you must try to change next commented statement and uncomment it
// dayValue = pickerView.selectedRowInComponent(1) + sundayCheck.nextSundayAsWeekDay
pickerView.selectRow(dayValue - 1, inComponent: 1, animated: true)
}
self.startDateTextField.text = confirmSunday.sundayDate?.fullStyleDateString
self.newBootcamp?.startDate = confirmSunday.sundayDate!
debugPrint(confirmSunday.sundayDate?.fullStyleDateString)
}
}
Method which checks sunday is following one
func isGivenDaySunday(selectedDay: Int, selectedMonth: Int, selectedYear: Int) -> (isSunday: Bool, nextSundayAsWeekDay: Int, sundayDate: NSDate?) {
let unitFlags: NSCalendarUnit = [.Day, .Month, .Year, .Weekday]
let selectedDateComponents = NSDateComponents()
selectedDateComponents.month = selectedMonth
selectedDateComponents.day = selectedDay
selectedDateComponents.year = selectedYear
let selectedDate = NSCalendar(identifier: NSCalendarIdentifierGregorian)?.dateFromComponents(selectedDateComponents)
let newSelectedDateComponent = NSCalendar.currentCalendar().components(unitFlags, fromDate: selectedDate!)
if newSelectedDateComponent.weekday == 1 { // 1 means SUNDAY as per Gregorian
return (true, 0, selectedDate)
} else {
return (false, 8 - newSelectedDateComponent.weekday, nil)
}
}