UIDatePicker show only Sunday's date only? - swift

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)
}
}

Related

DateTimePicker not displaying the right date

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
}()

local notification with repeats

I am making a local notification that will run every year, the problem is that I need notifications that come based on the Hebrew calendar, that is, July 20, 2020 according to the Hebrew calendar 28 tamuz 5780 and if we add the year to 28 tamuz 5781 then according to the Gregorian calendar comes out on July 1, 2021, that is, according to the Gregorian calendar, the date changes, I also need to take into account the leap year, AnniversariesReminderService is responsible for the notification, thanks
July 20, 2020 is 28 tamuz 5780
but
28 tamuz 5781 is July 1, 2021
I need to automatically calculate this time difference so that every year I receive a notification according to the Jewish date
struct ReminderAnniversaries {
var id:Int!
var description:String!
var date:Date!
}
class AnniversariesReminderService {
fileprivate var formatter :DateFormatter {
let dateformatterDay = DateFormatter()
dateformatterDay.dateFormat = "yyyy.MM.dd HH:mm"
return dateformatterDay
}
func scheduleReminder(data: ReminderAnniversaries, complited: (() -> Void)? = nil) {
removeScheduledReminder(data: data)
let request = self.prepareNotificationRequest(data: data)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if error != nil {
print("ERROR SCHEDULE NOTIFICATION TYPE: \(String(describing: "\(data.id!)")), ERROR: \(String(describing:error?.localizedDescription))")
}
complited?()
})
}
fileprivate func prepareNotificationRequest(data: ReminderAnniversaries) -> UNNotificationRequest {
let content = UNMutableNotificationContent()
content.sound = .default
content.title = "AppDisplayName".localized()
content.body = data.description
let fireDate = data.date!
var dateInfo = DateComponents()
let triggerDaily = Calendar(identifier: .hebrew).dateComponents([.year, .month, .day, .hour, .second], from: fireDate)
dateInfo.year = fireDate.year
dateInfo.month = fireDate.month
dateInfo.day = fireDate.day
dateInfo.hour = fireDate.hour
dateInfo.minute = fireDate.minute + 1
dateInfo.second = fireDate.second
content.userInfo = ["id": data.id, "date" : fireDate,
"description": data.description]
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDaily, repeats: true)
let requestIdentifier = "\(data.id!)"
let request = UNNotificationRequest(identifier: requestIdentifier,
content: content, trigger: trigger)
print("NOTIFICATION SCHEDULED: (String(describing: requestIdentifier))")
print("NOTIFICATION TITLE: \(String(describing: content.body))")
print("NOTIFICATION TIME: \(String(describing: self.formatter.string(from: fireDate)))")
return request
}
func removeScheduledReminder(data: ReminderAnniversaries) {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["\(data.id!)"])
print("NOTIFICATION REMOVED: \(String(describing: "\(data.id!)"))")
}
func getScheduledReminderDate(data: ReminderAnniversaries) -> String? {
var scheduledDate: Date?
let semaphore = DispatchSemaphore(value: 0)
UNUserNotificationCenter.current().getPendingNotificationRequests { notifications in
notifications.forEach({ notification in
if let scheduledType = notification.content.userInfo["id"] as? Int, scheduledType == data.id {
scheduledDate = notification.content.userInfo["date"] as? Date ?? Date()
// continue;
semaphore.signal()
}
})
if scheduledDate == nil {
semaphore.signal()
}
}
semaphore.wait()
return scheduledDate != nil ? formatter.string(from: scheduledDate!) : nil
}
}
Setting of date
#objc func doneDatePicker(){
if isAlarmClock && stage != 1 {
datePicker.datePickerMode = .dateAndTime
pickerDone.setTitle("Done".localized(), for: .normal)
pickerCancel.setTitle("Back".localized(), for: .normal)
stage = 1
formatter.dateFormat = "dd-MMM-yyyy HH:mm"
} else if !isAlarmClock {
//1
formatter.dateFormat = "dd-MMM-yyyy"
formatter.calendar = Calendar(identifier: .gregorian)
let dateOfDied = formatter.string(from: datePicker.date)
selectedDate = datePicker.date
// result Jule 21 2020 г.
//2
formatter.calendar = Calendar(identifier: .hebrew) //convert to jewish date
formatter.dateFormat = "dd-MMM-yyyy"
jewishDatePicker.date = datePicker.date
jewishDatePicker.calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.hebrew)! as Calendar //convert to jewish calendar for adding year
//count of years between date of died and current date
let calendar = Calendar.current
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: selectedDate)
let date2 = calendar.startOfDay(for: Date())
let components = calendar.dateComponents([.year], from: date1, to: date2)
var dayComponent = DateComponents()
dayComponent.year = components.year! + 1
let new_date = jewishDatePicker.calendar.date(byAdding: dayComponent, to: jewishDatePicker.date) // adding year by jewish calendar
jewishSelectedDate = new_date!
let hebDate = formatter.string(from: jewishSelectedDate)
jewishDatePicker.locale = Locale(identifier: "he")
jewishDatePicker.setDate(new_date!, animated: false)
print(jewishDatePicker.date)
// result Jule 9 2021 г.
//3
formatter.calendar = Calendar(identifier: .gregorian) //convert to gregorian date
let gregDate = formatter.string(from: new_date!)
// result Jule 09 2021 г.
alarmClock.isEnabled = true
alarmClockBtn()
var txt = Localized("You choosed", arguments: "\(dateOfDied)")
txt = txt + " " + "Jewish anniversary falls on".localized() + " " + "\(gregDate) (\(hebDate))," + " " + "select the date and time to remind you".localized()
text.text = txt
} else {
reminderTime = datePicker.date
pickerView.isHidden = true
}
}
#objc func addNotificationBtn(){
if !(name.text?.isEmpty ?? false) && !(parentName.text?.isEmpty ?? false) &&
jewishSelectedDate != nil && reminderTime != nil {
errorNotifier.notify("Done".localized(), title: "Notification configured".localized(), showOK: true) { [weak self] in
let remind = ReminderService()
var txt = Localized("You have set an anniversary reminder", arguments: self!.name.text!)
txt = txt + " " + "Бен(Бат)".localized() + " " + self!.parentName.text!
let data = ReminderAnniversaries(id: 11, description: txt, date: self?.reminderTime)
remind.anniversaries.scheduleReminder(data: data) {
print("ready")
}
self?.dismiss(animated: true, completion: nil)
}
} else if (name.text?.isEmpty ?? false) && (parentName.text?.isEmpty ?? false) {
errorNotifier.notify("Check the fields".localized(), title: "Fields must not be empty".localized(), showOK: true)
} else if jewishSelectedDate == nil {
errorNotifier.notify("Please select date if died".localized(), title:"", showOK: true)
} else if reminderTime == nil {
errorNotifier.notify("Please select a time for the anniversary reminder, the time is automatically set the day before the death anniversary".localized(), title: "Please select a time reminder".localized(), showOK: true)
}
}

Some dates disappear and reappear on scroll in JTCalendar Swift

I am trying to setup a calendar in my app using JTCalendar library but unfortunately i have this issue when sometimes i scroll through the app, the month in view looses the dates as described in the attached picture. I have tried to find out any information or questions in regards to this kind of issue but all was in vain. Am a bit new on this library, could anyone help me to solve this. Thanks for your time.
override func viewDidLoad() {
super.viewDidLoad()
popWithSwipe()
PLmonthArr = ["Styczeń","Luty","Marzec","Kwiecień","Maj","Czerwiec","Lipiec","Sierpień","Wrzesień","Październik","Listopad","Grudzień"]
calendarManager.menuView = calendarMenuView
calendarManager.contentView = calendarContentView
calendarManager.settings.weekDayFormat = JTCalendarWeekDayFormat.single
calendarManager.delegate = self
calendarManager.setDate(Date())
}
//MARK: View Will Appear
override func viewWillAppear(_ animated: Bool) {
currentLang = UserDefaults.standard.object(forKey:"language")as?String ?? "pl-PL"
setTextOnLanguageChange(lang:UserDefaults.standard.object(forKey:"language")as?String ?? "pl-PL")
calendarManager.reload()
}
public func calendar(_ calendar: JTCalendarManager!, prepareMenuItemView menuItemView: UIView!, date: Date!)
{
if let headerLabel = menuItemView as? UILabel{
headerLabel.textAlignment = NSTextAlignment .center
headerLabel.font = UIFont(name: "Comfortaa-Light", size: 20)
headerLabel.backgroundColor = UIColor.clear
headerLabel.textColor = UIColor.gray
let formatter = DateFormatter()
formatter.dateFormat = "MMMM yyyy"
formatter.locale = Locale(identifier: "en_US_POSIX")
let monthYear = formatter.string(from:date)
print(monthYear)
let yearFormatter = DateFormatter()
yearFormatter.dateFormat = "yyyy"
let CurrentYear = yearFormatter.string(from:date)
print(currentLang)
if currentLang == "pl-PL"{
headerLabel.text = setmonthLang(monthYear: monthYear,CurrentYear:CurrentYear).uppercased()
}else //if currentLang == "en"
{
headerLabel.text = monthYear.uppercased()
}
}
}
func numberOfMondaysInMonth(month: Int, forYear year: Int) -> Int?
{
let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
calendar.firstWeekday = 2 // 2 == Monday
// First monday in month:
let comps = NSDateComponents()
comps.month = month
comps.year = year
comps.weekday = calendar.firstWeekday
comps.weekdayOrdinal = 1
guard let first = calendar.date(from: comps as DateComponents) else {
return nil
}
// Last monday in month:
comps.weekdayOrdinal = -1
guard let last = calendar.date(from: comps as DateComponents) else {
return nil
}
// Difference in weeks:
let weeks = calendar.components(.weekOfMonth, from: first, to: last, options: [])
return (weeks.weekOfMonth ?? 0) + 1
}
func setmonthLang(monthYear:String,CurrentYear:String)->String
{
if monthYear.contains("January")
{
return "\(PLmonthArr[0]), \(CurrentYear)"
}
else if monthYear.contains("February")
{
return "\(PLmonthArr[1]), \(CurrentYear)"
}
else if monthYear.contains("March"){
return "\(PLmonthArr[2]), \(CurrentYear)"
}
else if monthYear.contains("April"){
return "\(PLmonthArr[3]), \(CurrentYear)"
}
else if monthYear.contains("May"){
return "\(PLmonthArr[4]), \(CurrentYear)"
}
else if monthYear.contains("June"){
return "\(PLmonthArr[5]), \(CurrentYear)"
}
else if monthYear.contains("July"){
return "\(PLmonthArr[6]), \(CurrentYear)"
}
else if monthYear.contains("August"){
return "\(PLmonthArr[7]), \(CurrentYear)"
}
else if monthYear.contains("September"){
return "\(PLmonthArr[8]), \(CurrentYear)"
}
else if monthYear.contains("October"){
return "\(PLmonthArr[9]), \(CurrentYear)"
}
else if monthYear.contains("November"){
return "\(PLmonthArr[10]), \(CurrentYear)"
}
else{
return "\(PLmonthArr[11]), \(CurrentYear)"
}
}
public func calendar(_ calendar: JTCalendarManager!, prepareDayView dayView: (UIView & JTCalendarDay)!)
{
if dayView.isFromAnotherMonth(){
dayView.isHidden = true
}
let mydayview=dayView as! JTCalendarDayView
mydayview.textLabel.font = UIFont(name:"Montserrat-Regular", size:13)
mydayview.circleRatio = 2
mydayview.backgroundColor = UIColor.white
mydayview.circleView.layer.cornerRadius = 1
mydayview.textLabel.textColor = UIColor.gray
mydayview.isFromAnotherMonth = false
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateStr = dateFormatter.string(from: mydayview.date)
print(dateStr)
if(isAVailableOnSelectedDate(dateStr: dateStr)){
let now = Date()
dateFormatter.dateFormat = "yyyy-MM-dd"
print(dateFormatter.string(from: now))
if let currentDate = calendarManager.date() {
let currentDateString = String(describing: currentDate)
if dateFormatter.string(from: now) == currentDateString.prefix(10){
mydayview.circleView.isHidden = false
mydayview.circleView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
mydayview.textLabel.textColor = UIColor.black
}
else{
mydayview.circleView.isHidden = false
mydayview.textLabel.textColor = UIColor.black
mydayview.circleView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
}
}
}
else if calendarManager.dateHelper.date(calendarContentView.date, isTheSameMonthThan: mydayview.date)
{
mydayview.circleView.isHidden = true;
// mydayview.backgroundColor = UIColor.white
// mydayview.dotView.backgroundColor = UIColor.red
mydayview.textLabel.textColor = UIColor.gray
}
if calendarManager.dateHelper.date(Date(), isTheSameDayThan: mydayview.date){
mydayview.circleView.isHidden = false
mydayview.circleView.backgroundColor = UIColor.white
mydayview.layer.borderColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
mydayview.layer.borderWidth = 1
} else if mydayview.date > Date() || mydayview.date < Date(){
mydayview.layer.borderWidth = 0
}
}

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)

SwiftCharts how to hide the midValue on yLabel

The charting library "SwiftCharts" can show the "Default" maxValue , midValue and the minValue, but how to hide the midValue "98 " ? please help me, thanks!
I used the demo project on the SwiftCharts:
Code
func initializeChart(cell: MarketPriceCell, index: Int) {
// Initialize data series and labels
var serieData: [Double] = []
var labels: [Double] = []
var labelsAsString: Array<String> = []
let beginInd = 0
let oneFour = stockValuesAll.count / 4
let twoFour = (stockValuesAll.count * 2) / 4
let thrFour = (stockValuesAll.count * 3) / 4
labels = [Double(beginInd), (Double(oneFour)), (Double(twoFour)),(Double(thrFour))]
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd"
let ddate1 = dateFormatter.string(from: stockValuesAll[beginInd]["date"] as! Date)
let ddate2 = dateFormatter.string(from: stockValuesAll[oneFour]["date"] as! Date)
let ddate3 = dateFormatter.string(from: stockValuesAll[twoFour]["date"] as! Date)
let ddate4 = dateFormatter.string(from: stockValuesAll[thrFour]["date"] as! Date)
labelsAsString = [ddate1,ddate2,ddate3,ddate4]
/// Date formatter to retrieve the month names
for (_, value) in stockValuesAll.enumerated() {
serieData.append(value["close"] as! Double)
}
let series = ChartSeries(serieData)
series.area = true
// Configure chart layout
cell.stkChart.lineWidth = 0.5
cell.stkChart.labelFont = UIFont.systemFont(ofSize: 12)
cell.stkChart.xLabels = labels
cell.stkChart.xLabelsFormatter = { (labelIndex: Int, labelValue: Double) -> String in
return labelsAsString[labelIndex]
}
cell.stkChart.xLabelsTextAlignment = .left
cell.stkChart.minY = serieData.min()! - 5
cell.stkChart.add(series)
Json File:
{
"quotes":
[
{ "date": "2017-07-01", "close": 93.52 },
{ "date": "2017-07-02", "close": 93.48 },
{ "date": "2017-07-03", "close": 94.03 },
{ "date": "2017-07-07", "close": 95.97 }...
The labels for the y-axis are set in the following function:
fileprivate func drawLabelsAndGridOnYAxis() {
let context = UIGraphicsGetCurrentContext()!
context.setStrokeColor(gridColor.cgColor)
context.setLineWidth(0.5)
var labels: [Double]
if yLabels == nil {
labels = [(min.y + max.y) / 2, max.y]
if yLabelsOnRightSide || min.y != 0 {
labels.insert(min.y, at: 0)
}
} else {
labels = yLabels!
}
so you would have to set your own array of yLabels (which contain only min and max) and assign them to your chart.
Another option would be to change the above code and remove the item for the midvalue:
if yLabels == nil {
labels = [max.y]