FSCalendar events in Swift 3 - swift3

How can events be added to an FSCalendar in swift 3?

Implement the appropriate methods in a class adopting FSCalendarDataSource.

var datesWithEvent = ["2015-10-03", "2015-10-06", "2015-10-12", "2015-10-25"]
var datesWithMultipleEvents = ["2015-10-08", "2015-10-16", "2015-10-20", "2015-10-28"]
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
if self.datesWithEvent.contains(dateString) {
return 1
}
if self.datesWithMultipleEvents.contains(dateString) {
return 3
}
return 0
}
Based On FsCalendar Documentation

Related

My Object that's Health Store are not refreshing data when it received a new data (in Health kit) in swift app

I want to develop view that's loading data from Health kit (mindfulness time) so I used Timer every 1 minute to get a new data from Health kit, created by Apple watch but onReceive(Timer) are not refreshing a new data (it pass previous data only)
if I Open another app and come back to this app then it's show me a new data
import SwiftUI
struct LoadingView: View {
var healthStore : HealthStore? = HealthStore()
#State private var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
#State var num : Int = 0
#Binding var showModal: Bool
var decription : String
// MARK: - BODY
var body: some View {
VStack (alignment: .center){
Spacer()
WatchView()
Spacer()
Text(decription)
.font(.callout)
.fontWeight(.semibold)
.padding(.horizontal,30)
Spacer()
}
.navigationBarBackButtonHidden(true)
.onReceive(timer) { _ in
if let healthStore = healthStore {
healthStore.requestAuthorization { success in
if success {
healthStore.getDailyMindfulnessTime { time in
print("\(time)")
}
} //: SUCCESS
}
}
}// ON RECEIVE
.onDisappear(perform: {
self.timer.upstream.connect().cancel()
})//ON DISAPPEAR
}
}
Health Store
import Foundation
import HealthKit
class HealthStore {
var healthStore : HKHealthStore?
var query : HKStatisticsCollectionQuery?
var querySampleQuery : HKSampleQuery?
init(){
// to check data is avaliable or not?
if HKHealthStore.isHealthDataAvailable(){
//Create instance of HKHealthStore
healthStore = HKHealthStore()
}
}
// Authorization
func requestAuthorization(compleion: #escaping(Bool)-> Void){
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
let mindfulSampleType = HKSampleType.categoryType(forIdentifier: .mindfulSession)!
guard let healthStore = self.healthStore else { return compleion(false)}
healthStore.requestAuthorization(toShare: [], read: [stepType,mindfulSampleType]) { (success, error) in
compleion(success)
}
}
//Calculate steps count
func calculateSteps(completion : #escaping(HKStatisticsCollection?)->Void){
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
let startDate = Calendar.current.date(byAdding: .day,value: -7, to: Date())
let anchorDate = Date.mondayAt12AM()
let daily = DateComponents(day:1)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date()
, options: .strictStartDate)
//cumulativeSum (Watch+Iphone)
query = HKStatisticsCollectionQuery(quantityType: stepType, quantitySamplePredicate: predicate, options: .cumulativeSum, anchorDate: anchorDate, intervalComponents: daily)
query!.initialResultsHandler = { query, statisticsCollection , error in
completion(statisticsCollection)
}
if let healthStore = self.healthStore, let query = self.query {
healthStore.execute(query)
}
}
// DailyMindfulnessTime
func getDailyMindfulnessTime(completion: #escaping (TimeInterval) -> Void) {
let sampleType = HKSampleType.categoryType(forIdentifier: .mindfulSession)!
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
let startDate = Calendar.current.startOfDay(for: Date())
let endDate = Calendar.current.date(byAdding: .day, value: 1, to: startDate)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
querySampleQuery = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [sortDescriptor]) { (_, results, error) in
if error != nil {
print(" HealthKit returned error while trying to query today's mindful sessions. The error was: \(String(describing: error?.localizedDescription))")
}
if let results = results {
var totalTime = TimeInterval()
for result in results {
totalTime += result.endDate.timeIntervalSince(result.startDate)
}
completion(totalTime)
} else {
completion(0)
}
}
if let healthStore = self.healthStore, let querySampleQuery = self.querySampleQuery {
healthStore.execute(querySampleQuery)
}
}
}
extension Date {
static func mondayAt12AM() -> Date{
return Calendar(identifier: .iso8601).date(from: Calendar(identifier: .iso8601).dateComponents([.yearForWeekOfYear,.weekOfYear],from: Date()))!
}
}
first of all you write in your question that you want to update every minute, but currently you update every second. TimeInterval is a typealias for Double and you pass it in your Timer as seconds. So in your case it should be:
#State private var timer = Timer.publish(every: 60, on: .main, in: .common).autoconnect()
Be aware this means onReceive is called after 60 seconds and not immediately.
And I tested your code and it worked fine for me. Unfortunately you didnt include your watch view so I dont know what you are doing in there.
I assumed num is the variable you wanted to update, so you need to call:
num += Int(time)
in your closure for getDailyMindfulnessTime.
If you want to display the time in your WatchView make sure to pass num as a Binding in there.

SwiftUI display yesterday's date

How do I list yesterday's date in SwiftUI? It probably is a simple answer but I'm just learning to code and for some reason I can't seem to find the solution anywhere. Is it because it is too easy?
struct DateShown: View {
let datechoice: Datechoice
var body: some View {
Text(currentDate(date: Date()))
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.blue)
}
func currentDate(date: Date!) -> String {
let formatter = DateFormatter()
formatter.locale = .current
formatter.dateFormat = "MMMM d, yyyy"
return date == nil ? "" : formatter.string(from: date)
}
}
I would rather use View extensions, though you also need Date formatting so I went the easier way and extended your solution. If the number at line "dayComponent.day" is positive, you go futher in time. I tested under:
swift 5
xcode 11.3.1
iOS 13.3.1 non beta
func yesterDay() -> String {
var dayComponent = DateComponents()
dayComponent.day = -1
let calendar = Calendar.current
let nextDay = calendar.date(byAdding: dayComponent, to: Date())!
let formatter = DateFormatter()
formatter.locale = .current
formatter.dateFormat = "MMMM d, yyyy"
return formatter.string(from: nextDay). //Output is "March 6, 2020
}
Usage is the same as yours:
Text(yesterDay())

How to change Event Dot Color in FSCalender

Here is my code. I am trying to change the dot color but I did not find any solution. Thanks
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
return 1;
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventColorFor date: Date) -> UIColor? {
return UIColor.red
}
Here is an example image of these event-dots:
This example is taken from here. Basically you just use the given method, check for event-type or something like that and return a color of your favour.
//Used by one of the example methods
var datesWithEvent = ["2015-10-03", "2015-10-06", "2015-10-12", "2015-10-25"]
var datesWithMultipleEvents = ["2015-10-08", "2015-10-16", "2015-10-20", "2015-10-28"]
//Used in one of the example methods
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
The complete example is to long for embedding, so i only took 2 example methods. I added the fields from the example, to have an "complete" example of how such a method could look like.
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventColorFor date: Date) -> UIColor? {
//Do some checks and return whatever color you want to.
return UIColor.purple
}
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventDefaultColorsFor date: Date) -> [UIColor]? {
let key = self.dateFormatter2.string(from: date)
if self.datesWithMultipleEvents.contains(key) {
return [UIColor.magenta, appearance.eventDefaultColor, UIColor.black]
}
return nil
}
For better understanding have a look at linked example class in Github. That example is pretty self explanatory.

How to change Month View to Week View vice versa for JTAppleCalendar

Hi newBiew in JTAppleCalendar.
I follow this link for JTAppleCalendar.
https://www.youtube.com/watch?v=CQNotydm58s&index=6&list=PLpqJf39XekqyUG7dxcqGO0JNprryysv9Q
I have this Problem:
How to I show calendar when user click a button to change monthView to WeekView or from week View to month View
How to I change the calendar size programmatically for CalendarView and mainStack as they have constrains?
I believe I need to handle configureCalendar as below but how to change programmatically month view to week view vice versa.
I have a stack (Call it mainStack) which used to contain CalendarView
Layout for the Calendar view :
#IBOutlet weak var CalendarView : JTAppleCalendarView!<br/>
#IBOutlet weak var mainStack: UIStackView!<br/>
extension MyCalendar: JTAppleCalendarViewDataSource, JTAppleCalendarViewDelegate {
func configureCalendar( _ calendar:JTAppleCalendarView) -> ConfigurationParameters {
formatter.dateFormat = "yyyy MM dd"
formatter.timeZone = Calendar.current.timeZone
formatter.locale = Calendar.current.locale
let startDate = formatter.date(from: "2017 01 01")!
let endDate = formatter.date(from: "2027 12 31")!
//-- how to set these "
1) Full calendar view
let parameters = ConfigurationParameters(startDate : startDate, endDate: endDate)
return parameters
2) for week view
let parameters = ConfigurationParameters(startDate : startDate, endDate: endDate, numberOfRows:1)
return parameters
}
func calendar( _ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell{
let cell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.dateLabel.text = cellState.text
configureCell(cell:cell, cellState: cellState)
return cell
}
//------------ selected item
func calendar( _ calendar: JTAppleCalendarView, didSelectDate date: Date, cell:JTAppleCell?, cellState:CellState){
configureCell(cell: cell, cellState: cellState)
}
func calendar( _ calendar: JTAppleCalendarView, didDeselectDate date: Date, cell:JTAppleCell?, cellState:CellState){
configureCell(cell: cell, cellState: cellState)
}
func calendar(_ calendar: JTAppleCalendarView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
setupCalendarView(dateSegment: visibleDates)
}
}
Please help.
Thanks
So the plan is:
You have a variable for the number of rows.
In a monthView mode, it has 6 rows.
In a weekView mode, it has 1 row.
So when you want to change the mode you change numberOfRows and reload calendarView and scroll to the current date.
Also when you have weekView, you should use a little bit different ConfigurationParameters.
That's how I do this:
#IBAction func monthWeekModeChanged(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
numberOfRows = 6
} else {
numberOfRows = 1
}
calendarView.reloadData()
calendarView.scrollToDate(Date(), animateScroll: false)
}
var numberOfRows = 6
extension CalendarViewController: JTAppleCalendarViewDataSource {
func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
let startDate = viewModel.formatter.date(from: "01-Jan-2019")
let endDate = viewModel.formatter.date(from: "31-Dec-2020")
if numberOfRows == 6 {
return ConfigurationParameters(startDate: startDate!, endDate: endDate!, numberOfRows: numberOfRows, firstDayOfWeek: .monday)
} else {
return ConfigurationParameters(startDate: startDate!,
endDate: endDate!,
numberOfRows: 1,
generateInDates: .forFirstMonthOnly,
generateOutDates: .off, firstDayOfWeek: .monday,
hasStrictBoundaries: false)
}
}
}
The tutorial here states just how to do this.
I cannot paste the whole thing here since the instructions are long.
Also, at the bottom of the page is the complete code in a zip file that you can play around with.

Swift 3: Internal Extension to Set Time

I had this internal Date extension that appears to no longer work in Swift 3:
internal extension DateComponents {
func to12pm() {
self.hour = 12
self.minute = 0
self.second = 0
}
}
The error message is:
Cannot assign to property: 'self' is immutable
How do I achieve this in Swift 3?
Additional Info (if needed): It was called by this Date extension:
func endOfWeek(_ weekday: Int) -> Date? {
guard
let cal = Calendar.current,
var comp: DateComponents = (cal as Calendar).components([.weekOfYear], from: self)
else {
return nil
}
comp.weekOfYear = 1
comp.day -= 1
comp.to12pm()
return (cal as NSCalendar).date(byAdding: comp, to: self.startOfWeek(weekday)!, options: [])!
}
Which now looks like this in Swift 3:
func endOfWeek(_ weekday: Int) -> Date? {
let cal = Calendar.current
var comp = cal.dateComponents([.weekOfYear], from: self)
comp.weekOfYear = 1
comp.day? -= 1
//This does not have the "comp.to12pm()" that the Swift 2 version did
return cal.date(byAdding: comp, to: self.startOfWeek(weekday)!)!
}
DateComponents is now a struct thats why it is throwing that error:
Cannot assign to property: 'self' is immutable
You need to create a new var from self, change it and return it as follow:
extension DateComponents {
var to12pm: DateComponents {
var components = self
components.hour = 12
components.minute = 0
components.second = 0
components.nanosecond = 0
return components
}
}