As the title of the issue says the calendar:_:didSelectDate:date:cell:cellState: delegate method does not seem to be called on inDates and outDates.
Weirdly this happens only if I make the selection using selectDates programmatically(*). If the user "manually" selects the cells the delegate method gets called.
Is this intended behaviour? If so, is there any way to either:
Thanks in advance for the help (and the great library).
(*): using selectDates:triggerSelectionDelegate:keepSelectionIfMultiSelectionAllowed: does not improve the situation
What version of the calendar are you using?
What what is your calendar startDate and endDate ?
I've upgraded just before writing the issue report: 6.1.5.
Initially I experienced it on 6.1.2.
BTW: wow, your response times are incredible :-)
I also had a look at the selectDates implementation in UserInteractionFunctions.swift, but could not find anything there justifying the behaviour.
After looking at you code, I saw the solution.
The Library is correct. And the architecture is good, but you have one thing missing it seems.
Where is your dataSource?
I'll be online for the rest of the day here -> https://gitter.im/patchthecode/JTAppleCalendar
We never went through it. I guess you mean the configureCalendar: function of the JTAppleCalendarViewDataSource protocol, right?
Here it is:
func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy MM dd"
let startDate = formatter.date(from: "2000 01 01")! // You can use date generated from a formatter
let endDate = formatter.date(from:"2100 01 01")! // You can also use dates created from this function
let parameters = ConfigurationParameters(startDate: startDate,
endDate: endDate,
numberOfRows: 5, // Only 1, 2, 3, & 6 are allowed
calendar: Calendar.current,
generateInDates: .forAllMonths,
generateOutDates: .tillEndOfGrid,
firstDayOfWeek: .monday)
return parameters
}
With respect to the code we saw today I just changed generateOutDates: to .tillEndOfGrid (this was my original configuration, today I set it to .off while troubleshooting the problem before hearing you.
If you instead meant the "model data", I also thought that I can code around the problem by recalculating the cell state given the date. I am not sure it is the best possible solution though because:
Still it may be a viable solution and one that I will be willing to pursue if you confirm that you believe the current behaviour is the best possible for the library.
By the way, the more I think to the didSelect delegate method the more I think it is more sensible to always return the selected cell (instead of nil for inDates and outDates). In fact, a selected cell is visible on the screen and, for instance, the selection mark may want to go there (and doing it this way it would not require a different code path). Also, if needed it is always possible to check if the cell is in current month by inspecting the cellState struct, so the current behaviour is only a cellState.dateBelongsTo == .thisMonth away.
What's to loose?
But perhaps my opinion is skewed by my view of my particular case and it is indeed more sensible to return nil. I just can't see the advantages from my viewpoint.
Thanks again for all your help and efforts. I really appreciate it.
Hi, I've thought a lot about our discussion of last night and I think I have some points you may find interesting.
It actually occurred to me that I can pretty easily solve my problem (I did not tried it yet, but I am pretty confident that it can work): in the willDisplay delegate I can check if the cell is selected && if it is an inDate/outDate. If so, I will know that the didSelect method has not been called and safely call my update cell method.
This does not solve the other design problems in my app (I really think the DayInfoView should adopt the delegate/data source patterns), but it solves the current problem: my inability to handle correctly the case where inDate/outDate are programmatically selected.
I keep going back and forth about the idea that the didSelect method should behave differently. Now I'm thinking that indeed the behavior should be changed. I think a better behavior would be to acknowledge that in your case you have three cases:
My reasoning is as follows:
for what concerns the similarity with apple apis, I do not think it applies in this case. In fact, collection views do not have the concept of inDate cells (i.e., cells that are both offscreen and onscreen ). In their case they really do not have a cell to return and it is indeed the most obvious choice to return nil. And this is exactly the behavior the user is expecting.
Currently the behavior changes depending on how the selection happens; while the new behavior will be identical for both user selection and programmatic selection;
Current behavior can only be understood by knowing that there is this strange concept of offscreen/onscreen cells. I really think this is an implementation detail that should not be known by the user. He should know the difference between inmonth cells and inDate/outDates, but the knowledge of the difference should stop there;
API design should follow the principle of least surprise (which was the one driving motivation behind your example about apple APIs btw), and all the above make me think that the behavior of didSelect is indeed very much surprising
I understand that a change like this is problematic. The library seems to have a huge install base and the change in behavior may brake lots of applications. I still maintain that in the long term the new behavior will help everybody, but indeed it is a difficult transition to make. Probably the best way forward is to provide a new delegate method with the new behavior, explain in the documentation the problem with the old one, and make the old one deprecated so that it can be safely removed in, say, two years.
Yours is a terrific library and is very well designed. I do not need the above changes to make my app work, but I do really think that the library can be improved in this way. Given, the time and efforts you put in the library and in supporting me, I thought that taking a little time to share these thoughts with you was deserved and hopefully helpful.
Hey, I have figured out the solution and I have updated the code in a zip file for you to look at.
Let me know when your are online -> https://gitter.im/patchthecode/JTAppleCalendar
The problem was my original concern -> This library behaves exactly like a UITableView/UICollection view. Cells are reused. Therefore you cannot store information on a cell. You are to use your dataSource object to design the cell.
I have fixed the code you have given me and will send it to you once you are online.
Hi. I modified the code so to not using the cell state. This allows me to always handle the day info display in the didSelect method and everything works.
Thanks for your support. I'll try to get online this night to discuss your solution if you like it.
This issue is closed but it seems that it is not solved with version 6.1.6, is it?
I want to be able to detect if in- or outdates are selected so that I can automatically backward or forward the month to be shown (scroll to date).
@Montrazul Hey, we closed this because this was not a problem with the library.
The original poster wasnt aware that cells were being reused.
You said:
I want to be able to detect if in- or outdates are selected so that I can automatically backward or forward the month to be shown (scroll to date).
In order to detect when a date is selected, you can use the didSelectDate delegate.
func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleCell?, cellState: CellState) {
if cellState.dateBelongsTo == .followingMonthWithinBoundary {
// scroll forward
} else if cellState.dateBelongsTo == .previousMonthWithinBoundary {
// scroll backward
}
}
@boborbt your solution doesn't work for me, since when I tap an on an indate/outdate, the willDisplayCell event is not fired
@patchthecode I'm using the 6.1.6 version of your library. Could you help me to understand why when I select an indate/outdate cell, the behavior is different?
When I try to select multiple cells using,
calendarView.selectDates(from: self.startDate!, to: self.endDate!, triggerSelectionDelegate: false, keepSelectionIfMultiSelectionAllowed: true), the "willDisplayCell" is triggered, and everything works fine. But when I do the same with an indate/outdate, nothing happens. so I can't highlight the desired range of dates. I really need your help.
Thank you
@nabbestemmia if you tap on an indate/outdate with your finger in version 6.1.6, the didSelect delegate is correctly called.
If you select dates programatically, the didSelect delegate should also be called correctly.
If you are available, would you be able to join me here? -> https://gitter.im/patchthecode/JTAppleCalendar
I'll be more free there after my work ends. Send me a msg there.
@patchthecode
First of all, thank you for responding me.
The problem is not in the didSelect event, which works correctly as you stated; but this delegate method:
func calendar(_ calendar: JTAppleCalendarView, willDisplayCell cell: JTAppleDayCellView, date: Date, cellState: CellState):
when I call calendarview.selectDates([...]), and the from: parameter is a indate/outdate, the willDisplayCell delegate method is not fired for the cell corresponding to the firstDate.
My problem is that when I select a range of dates, I need to update the shape of the selection for each of them, including the first one
to make myself more clear:
http://imgur.com/a/hLKm9
in this situation I tapped on the 27, and a circle appeared; after that I tapped on the 7. After tapping on the 7 I had to update the 27 to change its shape, but I couldn't, because the willDisplayCell method didn't fire for that cell. This only happens for the ondates/outdates.
I played a bit with the debugger, and maybe there is something wrong in the indexPaths to be reoladed, in the UserInteractionFunctions.swift file, but I still didn't manage to find the exact point
I even tried to force the redraw of that specific cell but I didn't find a method to get a cell from a date, nor the relative indexPath. In short, I run out of ideas.
Sadly I won't be available on this weekend, but I'll join https://gitter.im/patchthecode/JTAppleCalendar and write there the next week.
Thank you for everything
@nabbestemmia ok i see the issue.
Hmm.. is there a change you can migrate to version 7.0?
I'm pretty sure this error is fixed there.
If you can, then i can help you migrate your project.
If you cant, then i'll have to go back and look at old code
whether you cant/can I guess i'll hear from you again next week. 馃槃
@patchthecode
I'll gladely update to version 7,0, and try to migrate my code, it shouldn't be a big deal.
I'll write you again in case of need!
For now, thank you so much for the support, have a good weekend!
@patchthecode For now I resolved by calling
calendarView.reloadDates([firstDate, lastDate]), wich forcefully triggers the redraw of the edge cells. But I'll try a migration to the new 7.0 version next week, when I'll have more time.
Thank you again!
alright. cool then.