JonasWanke/timetable

Modular architecture with support for different layouts

JonasWanke opened this issue Β· 31 comments

I plan to revise the layout and theming possibilities of this package, mainly with the following goals in mind:

  • flexibility: Make it possible to choose between different layouts:
    • agenda (linearly list all events by start time)
    • day list: similar to agenda in that days are in an infinite vertical list, but events are positioned like they are now, so you know their lengths/etc. at a glimpse (TODO: think of a better name)
    • day: a single day displayed like multi-date below but with a modified header layout to better fit a single day
    • multi-date: like the current one
    • month: see all days in a month and the first 3 (or so) events
    • resource timeline: With time only on the horizontal axis, this layout uses the vertical axis for separating events by resources they occupy (such as rooms). The horizontal time should be scalable, probably with different resolutions (i.e., showing individual hours when viewing a single day, but only individual days when viewing a month). Similar to https://fullcalendar.io ("Resource Timeline"-Demo)
  • themeability: All layouts should have lots of themeable properties for easy customization
  • modularity: Expose the building blocks that are currently used so you can easily build your own layout if themeability isn't enough
  • animations: All of the above should implicitly animate between any changes

My idea is to implement the layouts mentioned above as separate, stateful widgets so they can e.g. manage their scroll position on their own. They will have more parameters, e.g. a customizable date header widget builder in the multi-date widget. (Currently you can change the pattern, decoration and text style of the day-of-week/-month indicators individually, but not their padding or disable one of them.

The currently used subcomponents like WeekIndicator, MultiDateBackgroundPainter, etc. should get a stable API and be exported.

Implicit animations are inspired from material's ShapeBorder in that each layout can provide a lerpTo or lerpFrom for layouts it supports animating to/from.

Feel free to add a comment if you have ideas for different layouts, wishes for exposed properties/widgets, or feedback for anything else :)

Hello, i've testing your library to use on my app (salon booking app), the one of the missing features in many calendar libraries is the swimlane or resource time grid like in fullcalendar (https://fullcalendar.io/). Soon as possible i want study the code to help you on something.

Thanks for your feedback! That really looks like an interesting feature I'll keep my eye on. I've added the timeline layout to the issue description. Resources themselves could be natively supported by all layouts. Depending on the final modular architecture, this can probably be achieved in a backward-compatible way, so it'll probably be implemented afterward.

[ STACKING EVENTS ]
I see stacking events in covering-each-self style in Your README screenshots.
But after implementing Your package in my project I see, that events of same date and similar time doesn't stack, but show in row splitting day's width.
It's not good for me, since having more than 2 events like that make their content unreadable.

I see 2 options here:

  • add theme property to let user decide how to stack events (in way there are stacked now or like in screenshots)
  • add extra Timetable property called "stackedEventsBuilder" to provide extra widget, which show in place of classic BasicEventWidget when events stacks (default builder would be some placeholder with stacked events count, which expand or open dialog with stacked events)

@JulianKowalczuk If an event starts less than 15 min after another event, both events are shown next to each other. If the difference is 15 min or more, timetable overlaps the later event over the earlier event. If that behavior doesn't work in your app, please open an issue, preferably with a screenshot.

Regarding option 1: I've created #31 with a suggestion of two additional theme properties for better customization of the stacking/overlap behavior. Would that solve your problem? If not, please comment on that issue.

Regarding option 2: You can already achieve that behavior by collapsing overlapping events into a single, special event, and have your eventBuilder create a different looking widget for that. If you want timetable to support this feature natively I'll keep it in mind for the architectural refactor, but I don't think it's worth implementing it before that.

Ok, I found in "minStackOverlap" variable in date_events.dart and I guess that's the variable You mentioned.
I see some variables in this file are customizable in theme.
Can You extend theme by variable which may impact on minStackOverlap?
It would solve my issue and make this package more customizable :)

@JulianKowalczuk Please see #31, the property partDayEventMinimumDeltaForStacking it mentions corresponds to the old, hardcoded minStackOverlap.

How is this going? I'd love to support you to enable modular layouts. How ever this seems quite challenging without in depth knowledge of the library. Is there anyway to support this by tackling a part of the overall solution?

I'm sorry for the long delay. Exams at my university are now over for this semester and only a few days of seminars left, but I just started a new job. I really hope the coming weeks won't be so full and I (finally!) started working on this issue.

@raLaaaa I'll first have to write the underlying structure for the new design, but when the first layout is working, you could contribute other layouts or have a look at implicit animations between them (where I'm not sure how they'll be implemented).

Glad to hear things are going well!

Completly makes sense! Let me know if you see a possibility how I could support you.

any update on this? would love to have support for the timetable to show only a single day as opposed to a whole week.

Sorry for the delay and for not keeping this up-to-date. I've recently started this rewrite, and as part of that, also migrated to null-safety and dropped the time_machine and dartx dependencies (which wasn't migrated at the time). This rewrite isn't done yet, but I've already managed to overcome the major blockers (visible as layout overflows in the old app).

Nice to hear!

Will the rewrite be downwards compatible? Since you were talking about removing time_machine this sounds like some changes might be required if you want to upgrade to the newest version?

This will be a breaking change, but I hope it's worth it by offering much more control over the design and supporting more (or custom) layouts.

First of all: Thanks for letting all of us know about the upcoming change! :)

However, I have one question: Are we somehow able to track the progress of the rewrite? I am looking forward to the null-safe update and it would be very nice to see how things are going. Maybe the community might contribute at some point as well, so it might be a nice thing to see the source code in either in another branch in this repo or in a separate one :D

I've pushed the new changes to the issue/17-modular-architecture-with-support-for-different-layouts branch.

The components folder (under lib/src) contains many small, reusable components, already supporting #41, #58, and #61 and fixing #51 and #52. In the layouts folder, there's currently only the MultiDateTimetable that looks like the former Timetable widget, but should offer more customization options and can also be split into a MultiDateTimetableHeader and MultiDateTimetableContent.

The former TimetableController is now separated into a TimeController (for controlling the visible hours and current zoom) and a DateController (containing the date and VisibleDateRange (formerly VisibleRange)). I'm currently experimenting with the DateController, VisibleDateRange, and DateScrollPhysics used under the hood to address #25, (#37), #38, #56, and #60.

To provide events, you only have to supply a List<E> Function(Interval visibleRange) instead of an overly complicated EventProvider. For changing events, rebuild the widget and provide different events!

Hours theming / overlays are also in progress, addressing #26 and inspired by TatsuUkraine#3 (though adapted to work similar to how events are now supplied).

I'm currently planning to also address #46, #63, and #64, and look into #21 and #36.

Globalization is already working, hopefully simplifying #23.

As mentioned in a previous comment, this new version no longer depends on time_machine but rather uses the built-in DateTime and Duration from Dart. This also moves #13 out of scope for the rewrite, as AFAIK Dart doesn't support other calendars.

If you want to try out the new version, have a look at the included example app which is kept up-to-date, but keep in mind that the new API is not yet stable. Also, the documentation is currently out-of-date.

Please let me know if you have any feedback :)

Update: In addition to the previous post, I now have a working solution for the combination of DateController, VisibleDateRange, and DateScrollPhysics that supports #25, (#37), #38, #56, and #60. I'm currently adding a month-based navigation (like the one the Google Calendar app for Android shows when you tap the month in the app bar) to verify that it works with this solution.

Hours theming / overlays as requested in #26 is/are also working.

#46 is also done.

I don't yet have a good solution for #63, and would like to address/enable #64 (which is harder to achieve with the new architecture) and look into #21 and #36.

Also, styling properties still have to be exposed from most widgets in a unified way.

I'll try to get the API stable and release a new version very soon.

Also, styling properties still have to be exposed from most widgets in a unified way.

@JonasWanke you going to use inherited widget for this or like params in timetable widget?

@TatsuUkraine I've removed the InheritedWidget as I don't really see a benefit in using it for that purpose in this package. It's handy when you have multiple widgets relying on its data and sharing a widget tree, but you usually just have a single timetable.

The styling is, however, split into different classes for the individual components instead of having all properties in a single, huge class.

@JonasWanke I see. Was thinking that inherited widget could be quite useful in terms of global styling or scoped styling. So you could define default theme somewhere on MaterialApp level to keep it as close as possible to all your theme variables. And in the same time - give ability to override only needed stylings on usage level. Also might be much easier to use if you have some sort of user settings that can affect time table styling

I think it could be quite handy to have both (and props and inherited widget) like flutter team has for most of they're widgets that have styles

@TatsuUkraine Okay, that makes sense. One inherited widget for every component would probably be too much (there are currently 16 of them), but maybe one per layout or a single, global theme with properties applying to multiple layouts would be good πŸ‘

@JonasWanke agreed, flutter team has 1 main built-in inherited widget for all in most cases at least - Theme and a few small ones like ListTileTheme) and it seems they don't have any problems with such approach))

First of all, thank you for all effort you put into this library it is pretty awesome!

I have one question: will it be possible to build some sort of "recurrent event layout" with this refactoring? Like having the current week fixed (disable horizontal scroll) and list a particular event set. Pretty much like in this image:

I can try to make this possible (something similar has already been requested before in #36), and that might even work with pure styling and no extra widgets.

Since my last update above, #21 is working, and I've also added a separate widget for month-based navigation (like the one the Google Calendar app for Android shows when you tap the month in the app bar) that can work together with the main widget.

Remaining steps until the release are:

  • addressing #64
  • hopefully finding a solution for #63
  • implementing styling in a unified way (which might suffice for #36 and the above request)
  • cleanup
  • writing documentation

Time for another update: Theming/styling is implemented, and a recurring layout (as requested above and in #36) is now supported as well. I've also been able to address #64, though there are currently two small bugs that will be fixed when using a Flutter version with Default Scrollbars on Desktop. I also did a bit of cleanup and started writing documentation.

I'll probably postpone fixing #63 to after the release, so all that's left is some more cleanup and writing documentation!

@JonasWanke is your current branch with updated package more or less stable?

I'm asking, because if it's stable, and has just a few bugs (maybe you can share what are they) I can try to install new version in my project to start using it, and report about any problems that I find

More or less stable ;) I hope that the current architecture is final for the release, but during cleanup or creating the documentation, I might still find some places where I'll have to do minor breaking changes.

Bugs: When zooming in/out in a day, the scrollbar is only updated when that zooming also contains a change in the scroll offset. Also, two scrollbars are displayed when scrolling – on in the events area, and one on the left over the time indicators:

image

I've created a draft PR containing all changes: #69. Feel free to report any issues you find directly over there.

I also just pushed the current documentation updates. The README already has most parts done, though some are still marked as todo or outdated. (And links don't work yet because the online API docs are only generated when the package is published on pub.dev.) But be careful with documentation comments, as those may be outdated.

Initial documentation is now available and some remaining bugs were fixed. The new version is now published: v1.0.0-alpha.0.

This version should be mostly stable, but I'd prefer to wait for a bit before publishing this as a stable 1.0.0 in case maybe a rename or something similar will come up. But I don't expect any more major changes, so feel free to upgrade if you want :)

Hi Jonas,
Any news on swimlanes?
Best regards.

@renatoufsm No, unfortunately, and I don't think I'll have the time to add them anytime soon. I'm open to contributions, however :)