From ff764ee0043c7827009d8e3459a70d55b32b1631 Mon Sep 17 00:00:00 2001 From: Shubham Jitiya Date: Thu, 9 Jan 2025 18:41:08 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20Fixes=20issue=20#412:=20=E2=9C=A8=20Add?= =?UTF-8?q?=20support=20for=20RTL=20directionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + README.md | 23 +- example/lib/constants.dart | 1 + example/lib/pages/create_event_page.dart | 80 ++++--- example/lib/pages/day_view_page.dart | 34 ++- example/lib/pages/event_details_page.dart | 195 +++++++++-------- .../lib/pages/mobile/mobile_home_page.dart | 94 ++++++-- example/lib/pages/month_view_page.dart | 30 ++- example/lib/pages/web/web_home_page.dart | 9 + example/lib/pages/week_view_page.dart | 34 ++- example/lib/widgets/add_event_form.dart | 28 +-- example/lib/widgets/calendar_configs.dart | 203 ++++++++++-------- example/lib/widgets/calendar_views.dart | 42 ++-- example/lib/widgets/day_view_widget.dart | 14 +- example/lib/widgets/month_view_widget.dart | 1 + example/lib/widgets/week_view_widget.dart | 32 ++- lib/src/components/_internal_components.dart | 9 +- lib/src/components/day_view_components.dart | 34 +-- lib/src/constants.dart | 1 + lib/src/day_view/_internal_day_view_page.dart | 7 +- lib/src/day_view/day_view.dart | 6 +- .../event_arrangers/side_event_arranger.dart | 10 +- lib/src/painters.dart | 139 ++++++++++-- .../week_view/_internal_week_view_page.dart | 50 +++-- lib/src/week_view/week_view.dart | 1 + 25 files changed, 711 insertions(+), 367 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2a15c10..b268f4bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Adds clear method to `EventController`. - Adds `onEventTapDetails`, `onEventDoubleTapDetails` & `onEventLongTapDetails` gesture recognizers to get tap details. [#390](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/390) +- Adds support of directionality. [#412](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/412) # [1.4.0 - 7 Jan 2025](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.4.0) diff --git a/README.md b/README.md index d1a0c0ad..e798c69a 100644 --- a/README.md +++ b/README.md @@ -357,9 +357,30 @@ WeekView( ], ); ``` - Above code will create `WeekView` with only five days, from monday to friday. +### Support for RTL +Wrap your widget with `Directionality` widget and use `textDirection` to give RTL or LTR direction. + +```dart +Directionality( + textDirection: TextDirection.rtl, + child: ResponsiveWidget( + webWidget: WebHomePage( + selectedView: CalendarView.week, + ), + mobileWidget: Scaffold( + floatingActionButton: FloatingActionButton( + child: Icon(Icons.add), + elevation: 8, + onPressed: () => context.pushRoute(CreateEventPage()), + ), + body: WeekViewWidget(), + ), + ), +); +``` + ## Main Contributors diff --git a/example/lib/constants.dart b/example/lib/constants.dart index 21da78d8..adc9aa4b 100644 --- a/example/lib/constants.dart +++ b/example/lib/constants.dart @@ -6,6 +6,7 @@ class AppConstants { AppConstants._(); static final List weekTitles = ['M', 'T', 'W', 'T', 'F', 'S', 'S']; + static final ltr = '\u202A'; // Use this to force text direction to LTR static OutlineInputBorder inputBorder = OutlineInputBorder( borderRadius: BorderRadius.circular(7), diff --git a/example/lib/pages/create_event_page.dart b/example/lib/pages/create_event_page.dart index 3b8e2499..f3422107 100644 --- a/example/lib/pages/create_event_page.dart +++ b/example/lib/pages/create_event_page.dart @@ -6,50 +6,60 @@ import '../extension.dart'; import '../widgets/add_event_form.dart'; class CreateEventPage extends StatelessWidget { - const CreateEventPage({super.key, this.event}); + const CreateEventPage({ + super.key, + this.event, + this.directionality = TextDirection.ltr, + }); final CalendarEventData? event; + final TextDirection directionality; @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - elevation: 0, - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - centerTitle: false, - leading: IconButton( - onPressed: context.pop, - icon: Icon( - Icons.arrow_back, - color: AppColors.black, + return Directionality( + textDirection: directionality, + child: Scaffold( + appBar: AppBar( + elevation: 0, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + centerTitle: false, + leading: IconButton( + onPressed: context.pop, + icon: Icon( + Icons.arrow_back, + color: AppColors.black, + ), ), - ), - title: Text( - event == null ? "Create New Event" : "Update Event", - style: TextStyle( - color: AppColors.black, - fontSize: 20.0, - fontWeight: FontWeight.bold, + title: Text( + event == null ? "Create New Event" : "Update Event", + style: TextStyle( + color: AppColors.black, + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), ), ), - ), - body: SingleChildScrollView( - physics: ClampingScrollPhysics(), - child: Padding( - padding: EdgeInsets.all(20.0), - child: AddOrEditEventForm( - onEventAdd: (newEvent) { - if (this.event != null) { - CalendarControllerProvider.of(context) - .controller - .update(this.event!, newEvent); - } else { - CalendarControllerProvider.of(context).controller.add(newEvent); - } + body: SingleChildScrollView( + physics: ClampingScrollPhysics(), + child: Padding( + padding: EdgeInsets.all(20.0), + child: AddOrEditEventForm( + onEventAdd: (newEvent) { + if (this.event != null) { + CalendarControllerProvider.of(context) + .controller + .update(this.event!, newEvent); + } else { + CalendarControllerProvider.of(context) + .controller + .add(newEvent); + } - context.pop(true); - }, - event: event, + context.pop(true); + }, + event: event, + ), ), ), ), diff --git a/example/lib/pages/day_view_page.dart b/example/lib/pages/day_view_page.dart index 1a80aba2..e4c660dd 100644 --- a/example/lib/pages/day_view_page.dart +++ b/example/lib/pages/day_view_page.dart @@ -8,7 +8,12 @@ import 'create_event_page.dart'; import 'web/web_home_page.dart'; class DayViewPageDemo extends StatefulWidget { - const DayViewPageDemo({super.key}); + const DayViewPageDemo({ + super.key, + this.directionality = TextDirection.ltr, + }); + + final TextDirection directionality; @override _DayViewPageDemoState createState() => _DayViewPageDemoState(); @@ -17,17 +22,24 @@ class DayViewPageDemo extends StatefulWidget { class _DayViewPageDemoState extends State { @override Widget build(BuildContext context) { - return ResponsiveWidget( - webWidget: WebHomePage( - selectedView: CalendarView.day, - ), - mobileWidget: Scaffold( - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - elevation: 8, - onPressed: () => context.pushRoute(CreateEventPage()), + return Directionality( + textDirection: widget.directionality, + child: ResponsiveWidget( + webWidget: WebHomePage( + selectedView: CalendarView.day, + ), + mobileWidget: Scaffold( + floatingActionButton: FloatingActionButton( + child: Icon(Icons.add), + elevation: 8, + onPressed: () => context.pushRoute( + CreateEventPage( + directionality: widget.directionality, + ), + ), + ), + body: DayViewWidget(), ), - body: DayViewWidget(), ), ); } diff --git a/example/lib/pages/event_details_page.dart b/example/lib/pages/event_details_page.dart index a9f38220..3907e8cb 100644 --- a/example/lib/pages/event_details_page.dart +++ b/example/lib/pages/event_details_page.dart @@ -8,124 +8,129 @@ import 'create_event_page.dart'; class DetailsPage extends StatelessWidget { final CalendarEventData event; final DateTime date; + final TextDirection directionality; const DetailsPage({ required this.event, required this.date, + this.directionality = TextDirection.ltr, super.key, }); @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: event.color, - elevation: 0, - centerTitle: false, - title: Text( - event.title, - style: TextStyle( - color: event.color.accentColor, - fontSize: 20.0, - fontWeight: FontWeight.bold, + return Directionality( + textDirection: directionality, + child: Scaffold( + appBar: AppBar( + backgroundColor: event.color, + elevation: 0, + centerTitle: false, + title: Text( + event.title, + style: TextStyle( + color: event.color.accentColor, + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), ), - ), - leading: IconButton( - onPressed: context.pop, - icon: Icon( - Icons.arrow_back, - color: event.color.accentColor, + leading: IconButton( + onPressed: context.pop, + icon: Icon( + Icons.arrow_back, + color: event.color.accentColor, + ), ), ), - ), - body: ListView( - padding: const EdgeInsets.all(20.0), - children: [ - Text( - "Date: ${event.date.dateToStringWithFormat(format: "dd/MM/yyyy")}", - ), - SizedBox( - height: 15.0, - ), - if (event.startTime != null && event.endTime != null) ...[ + body: ListView( + padding: const EdgeInsets.all(20.0), + children: [ + Text( + "Date: ${event.date.dateToStringWithFormat(format: "dd/MM/yyyy")}", + ), + SizedBox( + height: 15.0, + ), + if (event.startTime != null && event.endTime != null) ...[ + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("From"), + Text( + event.startTime + ?.getTimeInFormat(TimeStampFormat.parse_12) ?? + "", + ), + ], + ), + ), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("To"), + Text( + event.endTime + ?.getTimeInFormat(TimeStampFormat.parse_12) ?? + "", + ), + ], + ), + ), + ], + ), + SizedBox( + height: 30.0, + ), + ], + if (event.description?.isNotEmpty ?? false) ...[ + Divider(), + Text("Description"), + SizedBox( + height: 10.0, + ), + Text(event.description!) + ], + const SizedBox(height: 50), Row( children: [ Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("From"), - Text( - event.startTime - ?.getTimeInFormat(TimeStampFormat.parse_12) ?? - "", - ), - ], + child: ElevatedButton( + onPressed: () async { + await _handleDeleteEvent(context); + Navigator.of(context).pop(); + }, + child: Text('Delete Event'), ), ), + SizedBox(width: 30), Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("To"), - Text( - event.endTime - ?.getTimeInFormat(TimeStampFormat.parse_12) ?? - "", - ), - ], + child: ElevatedButton( + onPressed: () async { + final result = await Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => CreateEventPage( + event: event, + ), + ), + ); + + if (result != null) { + Navigator.of(context).pop(); + } + }, + child: Text('Edit Event'), ), ), ], ), - SizedBox( - height: 30.0, - ), ], - if (event.description?.isNotEmpty ?? false) ...[ - Divider(), - Text("Description"), - SizedBox( - height: 10.0, - ), - Text(event.description!) - ], - const SizedBox(height: 50), - Row( - children: [ - Expanded( - child: ElevatedButton( - onPressed: () async { - await _handleDeleteEvent(context); - Navigator.of(context).pop(); - }, - child: Text('Delete Event'), - ), - ), - SizedBox(width: 30), - Expanded( - child: ElevatedButton( - onPressed: () async { - final result = await Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => CreateEventPage( - event: event, - ), - ), - ); - - if (result != null) { - Navigator.of(context).pop(); - } - }, - child: Text('Edit Event'), - ), - ), - ], - ), - ], + ), ), ); } diff --git a/example/lib/pages/mobile/mobile_home_page.dart b/example/lib/pages/mobile/mobile_home_page.dart index 640dde95..d39a1869 100644 --- a/example/lib/pages/mobile/mobile_home_page.dart +++ b/example/lib/pages/mobile/mobile_home_page.dart @@ -5,7 +5,17 @@ import '../day_view_page.dart'; import '../month_view_page.dart'; import '../week_view_page.dart'; -class MobileHomePage extends StatelessWidget { +class MobileHomePage extends StatefulWidget { + @override + State createState() => _MobileHomePageState(); +} + +class _MobileHomePageState extends State { + bool isRtl = false; + + TextDirection get directionality => + isRtl ? TextDirection.rtl : TextDirection.ltr; + @override Widget build(BuildContext context) { return Scaffold( @@ -13,30 +23,68 @@ class MobileHomePage extends StatelessWidget { title: Text("Flutter Calendar Page"), centerTitle: true, ), - body: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ElevatedButton( - onPressed: () => context.pushRoute(MonthViewPageDemo()), - child: Text("Month View"), - ), - SizedBox( - height: 20, - ), - ElevatedButton( - onPressed: () => context.pushRoute(DayViewPageDemo()), - child: Text("Day View"), - ), - SizedBox( - height: 20, + body: Stack( + children: [ + Padding( + padding: EdgeInsets.only(right: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'Enable RTL ', + style: TextStyle( + fontSize: 18, + ), + ), + Switch( + value: isRtl, + onChanged: (value) { + setState( + () => isRtl = value, + ); + }, + ), + ], ), - ElevatedButton( - onPressed: () => context.pushRoute(WeekViewDemo()), - child: Text("Week View"), + ), + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () => context.pushRoute( + MonthViewPageDemo( + directionality: directionality, + ), + ), + child: Text("Month View"), + ), + SizedBox( + height: 20, + ), + ElevatedButton( + onPressed: () => context.pushRoute( + DayViewPageDemo( + directionality: directionality, + ), + ), + child: Text("Day View"), + ), + SizedBox( + height: 20, + ), + ElevatedButton( + onPressed: () => context.pushRoute( + WeekViewDemo( + directionality: directionality, + ), + ), + child: Text("Week View"), + ), + ], ), - ], - ), + ), + ], ), ); } diff --git a/example/lib/pages/month_view_page.dart b/example/lib/pages/month_view_page.dart index 9bd798c2..dfe190ca 100644 --- a/example/lib/pages/month_view_page.dart +++ b/example/lib/pages/month_view_page.dart @@ -10,8 +10,11 @@ import 'web/web_home_page.dart'; class MonthViewPageDemo extends StatefulWidget { const MonthViewPageDemo({ super.key, + this.directionality = TextDirection.ltr, }); + final TextDirection directionality; + @override _MonthViewPageDemoState createState() => _MonthViewPageDemoState(); } @@ -19,17 +22,24 @@ class MonthViewPageDemo extends StatefulWidget { class _MonthViewPageDemoState extends State { @override Widget build(BuildContext context) { - return ResponsiveWidget( - webWidget: WebHomePage( - selectedView: CalendarView.month, - ), - mobileWidget: Scaffold( - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - elevation: 8, - onPressed: () => context.pushRoute(CreateEventPage()), + return Directionality( + textDirection: widget.directionality, + child: ResponsiveWidget( + webWidget: WebHomePage( + selectedView: CalendarView.month, + ), + mobileWidget: Scaffold( + floatingActionButton: FloatingActionButton( + child: Icon(Icons.add), + elevation: 8, + onPressed: () => context.pushRoute( + CreateEventPage( + directionality: widget.directionality, + ), + ), + ), + body: MonthViewWidget(), ), - body: MonthViewWidget(), ), ); } diff --git a/example/lib/pages/web/web_home_page.dart b/example/lib/pages/web/web_home_page.dart index 3fe2b836..3368540f 100644 --- a/example/lib/pages/web/web_home_page.dart +++ b/example/lib/pages/web/web_home_page.dart @@ -17,6 +17,7 @@ class WebHomePage extends StatefulWidget { class _WebHomePageState extends State { late var _selectedView = widget.selectedView; + var _directionality = TextDirection.ltr; void _setView(CalendarView view) { if (view != _selectedView && mounted) { @@ -26,6 +27,12 @@ class _WebHomePageState extends State { } } + void _setDirectionality(TextDirection directionality) { + if (mounted) { + setState(() => _directionality = directionality); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -35,6 +42,7 @@ class _WebHomePageState extends State { child: CalendarConfig( onViewChange: _setView, currentView: _selectedView, + onDirectionalityChange: _setDirectionality, ), ), Expanded( @@ -46,6 +54,7 @@ class _WebHomePageState extends State { child: CalendarViews( key: ValueKey(MediaQuery.of(context).size.width), view: _selectedView, + directionality: _directionality, ), ), ), diff --git a/example/lib/pages/week_view_page.dart b/example/lib/pages/week_view_page.dart index 3a183f5e..e20d5f50 100644 --- a/example/lib/pages/week_view_page.dart +++ b/example/lib/pages/week_view_page.dart @@ -8,7 +8,12 @@ import 'create_event_page.dart'; import 'web/web_home_page.dart'; class WeekViewDemo extends StatefulWidget { - const WeekViewDemo({super.key}); + const WeekViewDemo({ + super.key, + this.directionality = TextDirection.ltr, + }); + + final TextDirection directionality; @override _WeekViewDemoState createState() => _WeekViewDemoState(); @@ -17,17 +22,24 @@ class WeekViewDemo extends StatefulWidget { class _WeekViewDemoState extends State { @override Widget build(BuildContext context) { - return ResponsiveWidget( - webWidget: WebHomePage( - selectedView: CalendarView.week, - ), - mobileWidget: Scaffold( - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - elevation: 8, - onPressed: () => context.pushRoute(CreateEventPage()), + return Directionality( + textDirection: widget.directionality, + child: ResponsiveWidget( + webWidget: WebHomePage( + selectedView: CalendarView.week, + ), + mobileWidget: Scaffold( + floatingActionButton: FloatingActionButton( + child: Icon(Icons.add), + elevation: 8, + onPressed: () => context.pushRoute( + CreateEventPage( + directionality: widget.directionality, + ), + ), + ), + body: WeekViewWidget(), ), - body: WeekViewWidget(), ), ); } diff --git a/example/lib/widgets/add_event_form.dart b/example/lib/widgets/add_event_form.dart index dbdf31c9..e7888d77 100644 --- a/example/lib/widgets/add_event_form.dart +++ b/example/lib/widgets/add_event_form.dart @@ -67,6 +67,7 @@ class _AddOrEditEventFormState extends State { key: _form, child: Column( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ TextFormField( controller: _titleController, @@ -255,15 +256,12 @@ class _AddOrEditEventFormState extends State { hintText: "Event Description", ), ), - Align( - alignment: Alignment.centerLeft, - child: Text( - 'Repeat', - style: TextStyle( - color: AppColors.black, - fontWeight: FontWeight.w500, - fontSize: 17, - ), + Text( + 'Repeat', + style: TextStyle( + color: AppColors.black, + fontWeight: FontWeight.w500, + fontSize: 17, ), ), Row( @@ -392,7 +390,7 @@ class _AddOrEditEventFormState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Reoccurrence ends on: ', + '${AppConstants.ltr}Reoccurrence ends on: ', style: TextStyle( color: AppColors.black, fontWeight: FontWeight.w500, @@ -519,7 +517,7 @@ class _AddOrEditEventFormState extends State { Row( children: [ Text( - "Event Color: ", + "${AppConstants.ltr}Event Color: ", style: TextStyle( color: AppColors.black, fontSize: 17, @@ -537,9 +535,11 @@ class _AddOrEditEventFormState extends State { SizedBox( height: 15, ), - CustomButton( - onTap: _createEvent, - title: widget.event == null ? "Add Event" : "Update Event", + Center( + child: CustomButton( + onTap: _createEvent, + title: widget.event == null ? "Add Event" : "Update Event", + ), ), ], ), diff --git a/example/lib/widgets/calendar_configs.dart b/example/lib/widgets/calendar_configs.dart index 9f976f88..490a728e 100644 --- a/example/lib/widgets/calendar_configs.dart +++ b/example/lib/widgets/calendar_configs.dart @@ -1,4 +1,5 @@ import 'package:calendar_view/calendar_view.dart'; +import 'package:example/constants.dart'; import 'package:flutter/material.dart'; import '../app_colors.dart'; @@ -6,110 +7,144 @@ import '../enumerations.dart'; import '../extension.dart'; import 'add_event_form.dart'; -class CalendarConfig extends StatelessWidget { +class CalendarConfig extends StatefulWidget { final void Function(CalendarView view) onViewChange; + final void Function(TextDirection directionality) onDirectionalityChange; final CalendarView currentView; const CalendarConfig({ super.key, required this.onViewChange, + required this.onDirectionalityChange, this.currentView = CalendarView.month, }); + @override + State createState() => _CalendarConfigState(); +} + +class _CalendarConfigState extends State { + bool isRtl = false; + + TextDirection get directionality => + isRtl ? TextDirection.rtl : TextDirection.ltr; + @override Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(left: 20, top: 20), - child: Text( - "Flutter Calendar Page", - style: TextStyle( - color: AppColors.black, - fontSize: 30, + return Directionality( + textDirection: directionality, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(left: 20, top: 20), + child: Text( + "Flutter Calendar Page", + style: TextStyle( + color: AppColors.black, + fontSize: 30, + ), ), ), - ), - Divider( - color: AppColors.lightNavyBlue, - ), - Expanded( - child: SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 20), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Active View:", - style: TextStyle( - fontSize: 20.0, - color: AppColors.black, + Divider( + color: AppColors.lightNavyBlue, + ), + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 20), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + 'Enable RTL ', + style: TextStyle( + fontSize: 20.0, + color: AppColors.black, + ), + ), + Switch( + value: isRtl, + onChanged: (value) { + setState(() => isRtl = value); + widget.onDirectionalityChange(directionality); + }, + ), + ], ), - ), - Wrap( - children: List.generate( - CalendarView.values.length, - (index) { - final view = CalendarView.values[index]; - return GestureDetector( - onTap: () => onViewChange(view), - child: Container( - padding: EdgeInsets.symmetric( - vertical: 10, - horizontal: 40, - ), - margin: EdgeInsets.only( - right: 20, - top: 20, - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(7), - color: view == currentView - ? AppColors.navyBlue - : AppColors.bluishGrey, - ), - child: Text( - view.name.capitalized, - style: TextStyle( - color: view == currentView - ? AppColors.white - : AppColors.black, - fontSize: 17, + SizedBox(height: 10), + Text( + "${AppConstants.ltr}Active View:", + style: TextStyle( + fontSize: 20.0, + color: AppColors.black, + ), + ), + Wrap( + children: List.generate( + CalendarView.values.length, + (index) { + final view = CalendarView.values[index]; + return GestureDetector( + onTap: () => widget.onViewChange(view), + child: Container( + padding: EdgeInsets.symmetric( + vertical: 10, + horizontal: 40, + ), + margin: EdgeInsets.only( + right: 20, + top: 20, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7), + color: view == widget.currentView + ? AppColors.navyBlue + : AppColors.bluishGrey, + ), + child: Text( + view.name.capitalized, + style: TextStyle( + color: view == widget.currentView + ? AppColors.white + : AppColors.black, + fontSize: 17, + ), ), ), - ), - ); - }, + ); + }, + ), + ), + SizedBox( + height: 40, + ), + Text( + "${AppConstants.ltr}Add Event: ", + style: TextStyle( + fontSize: 20.0, + color: AppColors.black, + ), ), - ), - SizedBox( - height: 40, - ), - Text( - "Add Event: ", - style: TextStyle( - fontSize: 20.0, - color: AppColors.black, + SizedBox( + height: 20, + ), + AddOrEditEventForm( + onEventAdd: (event) { + CalendarControllerProvider.of(context) + .controller + .add(event); + }, ), - ), - SizedBox( - height: 20, - ), - AddOrEditEventForm( - onEventAdd: (event) { - CalendarControllerProvider.of(context) - .controller - .add(event); - }, - ), - ], + ], + ), ), ), - ), - ], + ], + ), ); } } diff --git a/example/lib/widgets/calendar_views.dart b/example/lib/widgets/calendar_views.dart index 28509775..b0b79e44 100644 --- a/example/lib/widgets/calendar_views.dart +++ b/example/lib/widgets/calendar_views.dart @@ -11,31 +11,39 @@ import 'week_view_widget.dart'; class CalendarViews extends StatelessWidget { final CalendarView view; - const CalendarViews({super.key, this.view = CalendarView.month}); + const CalendarViews({ + super.key, + this.view = CalendarView.month, + this.directionality = TextDirection.ltr, + }); final _breakPoint = 490.0; + final TextDirection directionality; @override Widget build(BuildContext context) { final availableWidth = MediaQuery.of(context).size.width; final width = min(_breakPoint, availableWidth); - return Container( - height: double.infinity, - width: double.infinity, - color: AppColors.grey, - child: Center( - child: view == CalendarView.month - ? MonthViewWidget( - width: width, - ) - : view == CalendarView.day - ? DayViewWidget( - width: width, - ) - : WeekViewWidget( - width: width, - ), + return Directionality( + textDirection: directionality, + child: Container( + height: double.infinity, + width: double.infinity, + color: AppColors.grey, + child: Center( + child: view == CalendarView.month + ? MonthViewWidget( + width: width, + ) + : view == CalendarView.day + ? DayViewWidget( + width: width, + ) + : WeekViewWidget( + width: width, + ), + ), ), ); } diff --git a/example/lib/widgets/day_view_widget.dart b/example/lib/widgets/day_view_widget.dart index a02c189f..aedc84cd 100644 --- a/example/lib/widgets/day_view_widget.dart +++ b/example/lib/widgets/day_view_widget.dart @@ -1,4 +1,5 @@ import 'package:calendar_view/calendar_view.dart'; +import 'package:example/constants.dart'; import 'package:flutter/material.dart'; import '../pages/event_details_page.dart'; @@ -23,7 +24,9 @@ class DayViewWidget extends StatelessWidget { heightPerMinute: 3, timeLineBuilder: _timeLineBuilder, scrollPhysics: const BouncingScrollPhysics(), - eventArranger: SideEventArranger(maxWidth: 30), + eventArranger: SideEventArranger( + directionality: Directionality.of(context), + ), hourIndicatorSettings: HourIndicatorSettings( color: Theme.of(context).dividerColor, ), @@ -39,6 +42,7 @@ class DayViewWidget extends StatelessWidget { builder: (_) => DetailsPage( event: events.first, date: date, + directionality: Directionality.of(context), ), ), ); @@ -71,9 +75,10 @@ class DayViewWidget extends StatelessWidget { Positioned.fill( top: -8, right: 8, + left: 8, child: Text( "${date.hour}:${date.minute}", - textAlign: TextAlign.right, + textAlign: TextAlign.center, style: TextStyle( color: Colors.black.withAlpha(50), fontStyle: FontStyle.italic, @@ -92,9 +97,10 @@ class DayViewWidget extends StatelessWidget { Positioned.fill( top: -8, right: 8, + left: 8, child: Text( - "$hour ${date.hour ~/ 12 == 0 ? "am" : "pm"}", - textAlign: TextAlign.right, + "${AppConstants.ltr} $hour ${date.hour ~/ 12 == 0 ? "am" : "pm"}", + textAlign: TextAlign.center, ), ), ], diff --git a/example/lib/widgets/month_view_widget.dart b/example/lib/widgets/month_view_widget.dart index d9102d0c..8cfe103d 100644 --- a/example/lib/widgets/month_view_widget.dart +++ b/example/lib/widgets/month_view_widget.dart @@ -27,6 +27,7 @@ class MonthViewWidget extends StatelessWidget { builder: (_) => DetailsPage( event: event, date: date, + directionality: Directionality.of(context), ), ), ); diff --git a/example/lib/widgets/week_view_widget.dart b/example/lib/widgets/week_view_widget.dart index 4222c531..7885880e 100644 --- a/example/lib/widgets/week_view_widget.dart +++ b/example/lib/widgets/week_view_widget.dart @@ -1,4 +1,5 @@ import 'package:calendar_view/calendar_view.dart'; +import 'package:example/constants.dart'; import 'package:flutter/material.dart'; import '../pages/event_details_page.dart'; @@ -14,14 +15,26 @@ class WeekViewWidget extends StatelessWidget { return WeekView( key: state, width: width, + headerStringBuilder: (DateTime date, {DateTime? secondaryDate}) => + _weekStringBuilder( + date, + secondaryDate: secondaryDate, + textDirection: Directionality.of(context), + ), showWeekends: true, showLiveTimeLineInAllDays: true, - eventArranger: SideEventArranger(maxWidth: 30), - timeLineWidth: 65, + eventArranger: SideEventArranger( + directionality: Directionality.of(context), + ), + timeLineWidth: 68, scrollPhysics: const BouncingScrollPhysics(), liveTimeIndicatorSettings: LiveTimeIndicatorSettings( color: Colors.redAccent, + timeBackgroundViewWidth: 68, + offset: 0, showTime: true, + showBullet: true, + showTimeBackgroundView: true, ), onTimestampTap: (date) { SnackBar snackBar = SnackBar( @@ -35,6 +48,7 @@ class WeekViewWidget extends StatelessWidget { builder: (_) => DetailsPage( event: events.first, date: date, + directionality: Directionality.of(context), ), ), ); @@ -45,4 +59,18 @@ class WeekViewWidget extends StatelessWidget { }, ); } + + String _weekStringBuilder(DateTime date, + {DateTime? secondaryDate, TextDirection? textDirection}) { + final dateString = "${date.day} / ${date.month} / ${date.year}"; + final secondaryDateString = secondaryDate != null + ? "${secondaryDate.day} / ${secondaryDate.month} / ${secondaryDate.year}" + : ""; + + if (textDirection == TextDirection.rtl) { + return "${AppConstants.ltr}${secondaryDateString} to ${dateString}"; + } else { + return "${AppConstants.ltr}${dateString} to ${secondaryDateString}"; + } + } } diff --git a/lib/src/components/_internal_components.dart b/lib/src/components/_internal_components.dart index a13bd432..e8c8009f 100644 --- a/lib/src/components/_internal_components.dart +++ b/lib/src/components/_internal_components.dart @@ -98,6 +98,12 @@ class _LiveTimeIndicatorState extends State { /// to set dy offset of live time indicator final startMinutes = widget.startHour * 60; + /// To support LTR & RTL we need to manage X position of point-1 to draw line + /// according to position of timeline add and subtract its width + final offsetX = Directionality.of(context) == TextDirection.ltr + ? widget.liveTimeIndicatorSettings.offset + widget.timeLineWidth + : widget.liveTimeIndicatorSettings.offset - widget.timeLineWidth; + /// Check if live time is not between startHour and endHour if it is then /// don't show live time indicator /// @@ -111,9 +117,10 @@ class _LiveTimeIndicatorState extends State { size: Size(widget.width, widget.liveTimeIndicatorSettings.height), painter: CurrentTimeLinePainter( color: widget.liveTimeIndicatorSettings.color, + textDirection: Directionality.of(context), height: widget.liveTimeIndicatorSettings.height, offset: Offset( - widget.timeLineWidth + widget.liveTimeIndicatorSettings.offset, + offsetX, (_currentTime.getTotalMinutes - startMinutes) * widget.heightPerMinute, ), diff --git a/lib/src/components/day_view_components.dart b/lib/src/components/day_view_components.dart index b8e28e9e..24f4c9bc 100644 --- a/lib/src/components/day_view_components.dart +++ b/lib/src/components/day_view_components.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import '../calendar_event_data.dart'; +import '../constants.dart'; import '../extensions.dart'; import '../typedefs.dart'; @@ -134,17 +135,19 @@ class DefaultTimeLineMark extends StatelessWidget { final timeString = (timeStringBuilder != null) ? timeStringBuilder!(date) : date.minute != 0 - ? "$hour:${date.minute}" - : "$hour ${date.hour ~/ 12 == 0 ? "am" : "pm"}"; + ? "${Constants.ltr}$hour:${date.minute}" + : "${Constants.ltr}$hour ${date.hour ~/ 12 == 0 ? "am" : "pm"}"; return Transform.translate( offset: Offset(0, -7.5), child: Padding( - padding: const EdgeInsets.only(right: 7.0), + padding: const EdgeInsets.only(right: 7.0, left: 7.0), child: Text( timeString, - textAlign: TextAlign.right, + textAlign: Directionality.of(context) == TextDirection.ltr + ? TextAlign.right + : TextAlign.left, style: markingStyle ?? - TextStyle( + const TextStyle( fontSize: 15.0, ), ), @@ -212,14 +215,19 @@ class FullDayEventView extends StatelessWidget { margin: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(1.0), height: 24, - child: Text( - events[index].title, - style: titleStyle ?? - TextStyle( - fontSize: 16, - color: events[index].color.accent, - ), - maxLines: 1, + child: Align( + alignment: Directionality.of(context) == TextDirection.ltr + ? Alignment.centerLeft + : Alignment.centerRight, + child: Text( + events[index].title, + style: titleStyle ?? + TextStyle( + fontSize: 16, + color: events[index].color.accent, + ), + maxLines: 1, + ), ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), diff --git a/lib/src/constants.dart b/lib/src/constants.dart index 158379c8..f0204e6d 100644 --- a/lib/src/constants.dart +++ b/lib/src/constants.dart @@ -10,6 +10,7 @@ class Constants { static final Random _random = Random(); static final int _maxColor = 256; + static final ltr = '\u202A'; // Use this to force text direction LTR static const int hoursADay = 24; static const int minutesADay = 1440; diff --git a/lib/src/day_view/_internal_day_view_page.dart b/lib/src/day_view/_internal_day_view_page.dart index 28424c74..c5a8b8d9 100644 --- a/lib/src/day_view/_internal_day_view_page.dart +++ b/lib/src/day_view/_internal_day_view_page.dart @@ -269,6 +269,7 @@ class _InternalDayViewPageState widget.halfHourIndicatorSettings.dashSpaceWidth, startHour: widget.startHour, endHour: widget.endHour, + textDirection: Directionality.of(context), ), ), if (widget.showQuarterHours) @@ -287,6 +288,8 @@ class _InternalDayViewPageState widget.quarterHourIndicatorSettings.dashWidth, dashSpaceWidth: widget .quarterHourIndicatorSettings.dashSpaceWidth, + textDirection: Directionality.of(context), + timelineWidth: widget.timeLineWidth, ), ), widget.dayDetectorBuilder( @@ -297,7 +300,9 @@ class _InternalDayViewPageState minuteSlotSize: widget.minuteSlotSize, ), Align( - alignment: Alignment.centerRight, + alignment: Directionality.of(context) == TextDirection.ltr + ? Alignment.centerRight + : Alignment.centerLeft, child: EventGenerator( height: widget.height, date: widget.date, diff --git a/lib/src/day_view/day_view.dart b/lib/src/day_view/day_view.dart index c290fd19..82d019c6 100644 --- a/lib/src/day_view/day_view.dart +++ b/lib/src/day_view/day_view.dart @@ -566,6 +566,7 @@ class DayViewState extends State> { _halfHourIndicatorSettings = widget.halfHourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, + lineStyle: LineStyle.dashed, color: Constants.defaultBorderColor, offset: 5, ); @@ -731,10 +732,13 @@ class DayViewState extends State> { int startHour, int endHour, ) { + final directionality = Directionality.of(context); return HourLinePainter( lineColor: lineColor, lineHeight: lineHeight, - offset: offset, + timelineWidth: widget.timeLineWidth, + textDirection: directionality, + offset: directionality == TextDirection.ltr ? offset : 0, minuteHeight: minuteHeight, verticalLineOffset: verticalLineOffset, showVerticalLine: showVerticalLine, diff --git a/lib/src/event_arrangers/side_event_arranger.dart b/lib/src/event_arrangers/side_event_arranger.dart index 5c0283c9..473bc943 100644 --- a/lib/src/event_arrangers/side_event_arranger.dart +++ b/lib/src/event_arrangers/side_event_arranger.dart @@ -10,6 +10,7 @@ class SideEventArranger extends EventArranger { const SideEventArranger({ this.maxWidth, this.includeEdges = false, + this.directionality = TextDirection.ltr, }); /// Decides whether events that are overlapping on edge @@ -26,6 +27,9 @@ class SideEventArranger extends EventArranger { /// If max width is not specified, slots will expand to fill the cell. final double? maxWidth; + /// Defines the directionality LRT/RTL + final TextDirection directionality; + /// {@macro event_arranger_arrange_method_doc} /// /// Make sure that all the events that are passed in [events], must be in @@ -130,9 +134,11 @@ class SideEventArranger extends EventArranger { final top = (startTime.getTotalMinutes - (startHour * 60)) * heightPerMinute; + final isLtr = directionality == TextDirection.ltr; + return OrganizedCalendarEventData( - left: offset, - right: totalWidth - (offset + slotWidth), + left: isLtr ? offset : totalWidth - (offset + slotWidth), + right: isLtr ? totalWidth - (offset + slotWidth) : offset, top: top, bottom: bottom, startDuration: startTime, diff --git a/lib/src/painters.dart b/lib/src/painters.dart index 4498bfb3..1911d89b 100644 --- a/lib/src/painters.dart +++ b/lib/src/painters.dart @@ -47,6 +47,12 @@ class HourLinePainter extends CustomPainter { /// This field will be used to set end hour for day and week view final int endHour; + /// Defines the width of timeline + final double? timelineWidth; + + /// Defines directionality + final TextDirection textDirection; + /// Paints 24 hour lines. HourLinePainter({ required this.lineColor, @@ -56,45 +62,68 @@ class HourLinePainter extends CustomPainter { required this.showVerticalLine, required this.startHour, required this.emulateVerticalOffsetBy, + this.timelineWidth, this.endHour = Constants.hoursADay, this.verticalLineOffset = 10, this.lineStyle = LineStyle.solid, this.dashWidth = 4, this.dashSpaceWidth = 4, + this.textDirection = TextDirection.ltr, }); + bool get isLtr => textDirection == TextDirection.ltr; + @override void paint(Canvas canvas, Size size) { final dx = offset + emulateVerticalOffsetBy; final paint = Paint() ..color = lineColor ..strokeWidth = lineHeight; + // X point of Point P2 + final endXPoint = size.width - (isLtr ? 0 : timelineWidth ?? 0); for (var i = startHour + 1; i < endHour; i++) { final dy = (i - startHour) * minuteHeight * 60; if (lineStyle == LineStyle.dashed) { var startX = dx; - while (startX < size.width) { + final width = isLtr ? size.width : size.width - (timelineWidth ?? 0); + + while (startX < width) { canvas.drawLine( - Offset(startX, dy), Offset(startX + dashWidth, dy), paint); + Offset(startX, dy), + Offset(startX + dashWidth, dy), + paint, + ); startX += dashWidth + dashSpaceWidth; } } else { - canvas.drawLine(Offset(dx, dy), Offset(size.width, dy), paint); + final startX = isLtr ? dx : dx - (timelineWidth ?? 0); + canvas.drawLine(Offset(startX, dy), Offset(endXPoint, dy), paint); } } if (showVerticalLine) { + final ltrOffset = offset + verticalLineOffset; + final rtlOffset = size.width - verticalLineOffset - (timelineWidth ?? 0); + if (lineStyle == LineStyle.dashed) { + final xPoint = isLtr ? ltrOffset : rtlOffset; var startY = 0.0; + while (startY < size.height) { - canvas.drawLine(Offset(offset + verticalLineOffset, startY), - Offset(offset + verticalLineOffset, startY + dashWidth), paint); + canvas.drawLine( + Offset(xPoint, startY), + Offset(xPoint, startY + dashWidth), + paint, + ); startY += dashWidth + dashSpaceWidth; } } else { - canvas.drawLine(Offset(offset + verticalLineOffset, 0), - Offset(offset + verticalLineOffset, size.height), paint); + canvas.drawLine( + Offset(isLtr ? ltrOffset : rtlOffset, 0), + Offset(isLtr ? ltrOffset : rtlOffset, size.height), + paint, + ); } } } @@ -138,6 +167,9 @@ class HalfHourLinePainter extends CustomPainter { /// This field will be used to set end hour for day and week view final int endHour; + /// Defines directionality + final TextDirection textDirection; + /// Paint half hour lines HalfHourLinePainter({ required this.lineColor, @@ -149,8 +181,11 @@ class HalfHourLinePainter extends CustomPainter { this.dashWidth = 4, this.dashSpaceWidth = 4, this.endHour = Constants.hoursADay, + this.textDirection = TextDirection.ltr, }); + bool get isLtr => textDirection == TextDirection.ltr; + @override void paint(Canvas canvas, Size size) { final paint = Paint() @@ -159,15 +194,21 @@ class HalfHourLinePainter extends CustomPainter { for (var i = startHour; i < endHour; i++) { final dy = (i - startHour) * minuteHeight * 60 + (minuteHeight * 30); + final width = isLtr ? size.width : size.width - offset; if (lineStyle == LineStyle.dashed) { - var startX = offset; - while (startX < size.width) { + var startX = isLtr ? offset : 0.0; + while (startX < width) { canvas.drawLine( - Offset(startX, dy), Offset(startX + dashWidth, dy), paint); + Offset(startX, dy), + Offset(startX + dashWidth, dy), + paint, + ); startX += dashWidth + dashSpaceWidth; } } else { - canvas.drawLine(Offset(offset, dy), Offset(size.width, dy), paint); + final startX = isLtr ? offset : 0.0; + final endX = isLtr ? width : size.width - offset; + canvas.drawLine(Offset(startX, dy), Offset(endX, dy), paint); } } } @@ -205,6 +246,12 @@ class QuarterHourLinePainter extends CustomPainter { /// Line dash space width when using the [LineStyle.dashed] style final double dashSpaceWidth; + /// Defines the width of timeline + final double? timelineWidth; + + /// Defines directionality + final TextDirection textDirection; + /// Paint quarter hour lines QuarterHourLinePainter({ required this.lineColor, @@ -212,10 +259,14 @@ class QuarterHourLinePainter extends CustomPainter { required this.offset, required this.minuteHeight, required this.lineStyle, + this.timelineWidth, this.dashWidth = 4, this.dashSpaceWidth = 4, + this.textDirection = TextDirection.ltr, }); + bool get isLtr => textDirection == TextDirection.ltr; + @override void paint(Canvas canvas, Size size) { final paint = Paint() @@ -225,21 +276,39 @@ class QuarterHourLinePainter extends CustomPainter { for (var i = 0; i < Constants.hoursADay; i++) { final dy1 = i * minuteHeight * 60 + (minuteHeight * 15); final dy2 = i * minuteHeight * 60 + (minuteHeight * 45); + final endX = isLtr ? size.width : size.width - offset; if (lineStyle == LineStyle.dashed) { var startX = offset; - while (startX < size.width) { + + while (startX < endX) { canvas.drawLine( - Offset(startX, dy1), Offset(startX + dashWidth, dy1), paint); + Offset(startX, dy1), + Offset(startX + dashWidth, dy1), + paint, + ); startX += dashWidth + dashSpaceWidth; canvas.drawLine( - Offset(startX, dy2), Offset(startX + dashWidth, dy2), paint); + Offset(startX, dy2), + Offset(startX + dashWidth, dy2), + paint, + ); startX += dashWidth + dashSpaceWidth; } } else { - canvas.drawLine(Offset(offset, dy1), Offset(size.width, dy1), paint); - canvas.drawLine(Offset(offset, dy2), Offset(size.width, dy2), paint); + final startXPoint = isLtr ? offset : 0.0; + canvas + ..drawLine( + Offset(startXPoint, dy1), + Offset(endX, dy1), + paint, + ) + ..drawLine( + Offset(startXPoint, dy2), + Offset(endX, dy2), + paint, + ); } } } @@ -283,6 +352,11 @@ class CurrentTimeLinePainter extends CustomPainter { /// Width of time backgroud view. final double timeBackgroundViewWidth; + /// Defines directionality + final TextDirection textDirection; + + bool get isLtr => textDirection == TextDirection.ltr; + /// Paints a single horizontal line at [offset]. CurrentTimeLinePainter({ required this.showBullet, @@ -294,33 +368,46 @@ class CurrentTimeLinePainter extends CustomPainter { required this.showTime, required this.showTimeBackgroundView, required this.timeBackgroundViewWidth, + this.textDirection = TextDirection.ltr, }); @override void paint(Canvas canvas, Size size) { + final startXPoint = isLtr + ? offset.dx - (showBullet ? 0 : 8) + : offset.dx - (showBullet ? 8 : 0); + final endXPoint = size.width - (isLtr ? 0 : timeBackgroundViewWidth); canvas.drawLine( - Offset(offset.dx - (showBullet ? 0 : 8), offset.dy), - Offset(size.width, offset.dy), + Offset(startXPoint, offset.dy), + Offset(endXPoint, offset.dy), Paint() ..color = color ..strokeWidth = height, ); if (showBullet) { + final xPoint = isLtr ? offset.dx : offset.dx + size.width; canvas.drawCircle( - Offset(offset.dx, offset.dy), bulletRadius, Paint()..color = color); + Offset(xPoint, offset.dy), + bulletRadius, + Paint()..color = color, + ); } if (showTimeBackgroundView) { + final dx = isLtr + ? offset.dx - timeBackgroundViewWidth - 4 + : offset.dx + size.width; + canvas.drawRRect( RRect.fromRectAndRadius( Rect.fromLTWH( - max(3, offset.dx - 68), + max(3, dx), offset.dy - 11, timeBackgroundViewWidth, 24, ), - Radius.circular(12), + const Radius.circular(12), ), Paint() ..color = color @@ -335,13 +422,19 @@ class CurrentTimeLinePainter extends CustomPainter { text: TextSpan( text: timeString, style: TextStyle( - fontSize: 12.0, + fontSize: 12, color: showTimeBackgroundView ? Colors.white : color, ), ), ) ..layout() - ..paint(canvas, Offset(offset.dx - 62, offset.dy - 6)); + ..paint( + canvas, + Offset( + isLtr ? 8 : offset.dx + size.width + 6, + offset.dy - 6, + ), + ); } } diff --git a/lib/src/week_view/_internal_week_view_page.dart b/lib/src/week_view/_internal_week_view_page.dart index 85d36b54..7a02aefe 100644 --- a/lib/src/week_view/_internal_week_view_page.dart +++ b/lib/src/week_view/_internal_week_view_page.dart @@ -251,6 +251,8 @@ class _InternalWeekViewPageState @override Widget build(BuildContext context) { final filteredDates = _filteredDate(); + final isLtr = Directionality.of(context) == TextDirection.ltr; + return Container( height: widget.height + widget.weekTitleHeight, width: widget.width, @@ -353,23 +355,31 @@ class _InternalWeekViewPageState width: widget.width, child: Stack( children: [ - CustomPaint( - size: Size(widget.width, widget.height), - painter: HourLinePainter( - lineColor: widget.hourIndicatorSettings.color, - lineHeight: widget.hourIndicatorSettings.height, - offset: widget.timeLineWidth + - widget.hourIndicatorSettings.offset, - minuteHeight: widget.heightPerMinute, - verticalLineOffset: widget.verticalLineOffset, - showVerticalLine: widget.showVerticalLine, - lineStyle: widget.hourIndicatorSettings.lineStyle, - dashWidth: widget.hourIndicatorSettings.dashWidth, - dashSpaceWidth: - widget.hourIndicatorSettings.dashSpaceWidth, - emulateVerticalOffsetBy: widget.emulateVerticalOffsetBy, - startHour: widget.startHour, - endHour: widget.endHour, + Positioned( + left: isLtr ? widget.timeLineWidth : 0, + right: isLtr ? 0 : widget.timeLineWidth + 6, + child: CustomPaint( + size: Size( + widget.width, + widget.height, + ), + painter: HourLinePainter( + lineColor: widget.hourIndicatorSettings.color, + lineHeight: widget.hourIndicatorSettings.height, + offset: + isLtr ? widget.hourIndicatorSettings.offset : 0, + minuteHeight: widget.heightPerMinute, + verticalLineOffset: widget.verticalLineOffset, + showVerticalLine: widget.showVerticalLine, + lineStyle: widget.hourIndicatorSettings.lineStyle, + dashWidth: widget.hourIndicatorSettings.dashWidth, + dashSpaceWidth: + widget.hourIndicatorSettings.dashSpaceWidth, + emulateVerticalOffsetBy: + widget.emulateVerticalOffsetBy, + startHour: widget.startHour, + endHour: widget.endHour, + ), ), ), if (widget.showHalfHours) @@ -405,10 +415,12 @@ class _InternalWeekViewPageState widget.quarterHourIndicatorSettings.dashWidth, dashSpaceWidth: widget .quarterHourIndicatorSettings.dashSpaceWidth, + textDirection: Directionality.of(context), ), ), Align( - alignment: Alignment.centerRight, + alignment: + isLtr ? Alignment.centerRight : Alignment.centerLeft, child: SizedBox( width: widget.weekTitleWidth * filteredDates.length, height: widget.height, @@ -486,7 +498,7 @@ class _InternalWeekViewPageState LiveTimeIndicator( liveTimeIndicatorSettings: widget.liveTimeIndicatorSettings, - width: widget.width, + width: widget.width - 8, height: widget.height, heightPerMinute: widget.heightPerMinute, timeLineWidth: widget.timeLineWidth, diff --git a/lib/src/week_view/week_view.dart b/lib/src/week_view/week_view.dart index b91efa13..7b3d202e 100644 --- a/lib/src/week_view/week_view.dart +++ b/lib/src/week_view/week_view.dart @@ -886,6 +886,7 @@ class WeekViewState extends State> { emulateVerticalOffsetBy: emulateVerticalOffsetBy, startHour: startHour, endHour: endHour, + textDirection: Directionality.of(context), ); }