diff --git a/CHANGELOG.md b/CHANGELOG.md
index 982d4db6..32daecc2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
# [1.4.1 - Unreleased]
- Adds clear method to `EventController`.
+- 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 4984a0ee..1db83c2c 100644
--- a/README.md
+++ b/README.md
@@ -352,9 +352,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..42abb682 100644
--- a/example/lib/pages/create_event_page.dart
+++ b/example/lib/pages/create_event_page.dart
@@ -12,44 +12,50 @@ class CreateEventPage extends StatelessWidget {
@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,
+ // TODO(Shubham): Remove temporary Directionality widget
+ return Directionality(
+ textDirection: TextDirection.rtl,
+ 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..506f7aa6 100644
--- a/example/lib/pages/day_view_page.dart
+++ b/example/lib/pages/day_view_page.dart
@@ -17,17 +17,20 @@ 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: TextDirection.rtl,
+ child: ResponsiveWidget(
+ webWidget: WebHomePage(
+ selectedView: CalendarView.day,
+ ),
+ mobileWidget: Scaffold(
+ floatingActionButton: FloatingActionButton(
+ child: Icon(Icons.add),
+ elevation: 8,
+ onPressed: () => context.pushRoute(CreateEventPage()),
+ ),
+ body: DayViewWidget(),
),
- body: DayViewWidget(),
),
);
}
diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart
index 85d8f05d..80a894a6 100644
--- a/example/lib/pages/home_page.dart
+++ b/example/lib/pages/home_page.dart
@@ -9,9 +9,13 @@ class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return ResponsiveWidget(
- mobileWidget: MobileHomePage(),
- webWidget: WebHomePage(),
+ // TODO(Shubham): Remove temporary wrapped widget
+ return Directionality(
+ textDirection: TextDirection.rtl,
+ child: ResponsiveWidget(
+ mobileWidget: MobileHomePage(),
+ webWidget: WebHomePage(),
+ ),
);
}
}
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..f45ac9b0 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';
@@ -43,7 +44,7 @@ class CalendarConfig extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
- "Active View:",
+ "${AppConstants.ltr}Active View:",
style: TextStyle(
fontSize: 20.0,
color: AppColors.black,
@@ -89,7 +90,7 @@ class CalendarConfig extends StatelessWidget {
height: 40,
),
Text(
- "Add Event: ",
+ "${AppConstants.ltr}Add Event: ",
style: TextStyle(
fontSize: 20.0,
color: AppColors.black,
diff --git a/example/lib/widgets/day_view_widget.dart b/example/lib/widgets/day_view_widget.dart
index a02c189f..ba52d41c 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,10 @@ class DayViewWidget extends StatelessWidget {
heightPerMinute: 3,
timeLineBuilder: _timeLineBuilder,
scrollPhysics: const BouncingScrollPhysics(),
- eventArranger: SideEventArranger(maxWidth: 30),
+ eventArranger: SideEventArranger(
+ maxWidth: 30,
+ directionality: Directionality.of(context),
+ ),
hourIndicatorSettings: HourIndicatorSettings(
color: Theme.of(context).dividerColor,
),
@@ -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/week_view_widget.dart b/example/lib/widgets/week_view_widget.dart
index 4222c531..a0faa123 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,27 @@ 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(
+ maxWidth: 30,
+ 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(
@@ -45,4 +59,19 @@ class WeekViewWidget extends StatelessWidget {
},
);
}
+
+ // TODO(Shubham): Include in readme to guide how to support RTL for string like below
+ 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..d16c9003 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';
@@ -63,7 +64,6 @@ class RoundedEventTile extends StatelessWidget {
borderRadius: borderRadius,
),
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (title.isNotEmpty)
@@ -97,6 +97,7 @@ class RoundedEventTile extends StatelessWidget {
Expanded(
child: Text(
"+${totalEvents - 1} more",
+ textAlign: TextAlign.center,
style: (descriptionStyle ??
TextStyle(
color: backgroundColor.accent.withAlpha(200),
@@ -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..68fc86ad 100644
--- a/lib/src/day_view/_internal_day_view_page.dart
+++ b/lib/src/day_view/_internal_day_view_page.dart
@@ -214,6 +214,15 @@ class _InternalDayViewPageState
@override
Widget build(BuildContext context) {
final fullDayEventList = widget.controller.getFullDayEvent(widget.date);
+ final hourLineOffset = (Directionality.of(context) == TextDirection.ltr
+ ? widget.timeLineWidth
+ : 0) +
+ widget.hourIndicatorSettings.offset;
+ final halfHourOffset = (Directionality.of(context) == TextDirection.ltr
+ ? widget.timeLineWidth
+ : 0) +
+ widget.halfHourIndicatorSettings.offset;
+
return Container(
height: widget.height,
width: widget.width,
@@ -269,6 +278,7 @@ class _InternalDayViewPageState
widget.halfHourIndicatorSettings.dashSpaceWidth,
startHour: widget.startHour,
endHour: widget.endHour,
+ textDirection: Directionality.of(context),
),
),
if (widget.showQuarterHours)
@@ -287,6 +297,8 @@ class _InternalDayViewPageState
widget.quarterHourIndicatorSettings.dashWidth,
dashSpaceWidth: widget
.quarterHourIndicatorSettings.dashSpaceWidth,
+ textDirection: Directionality.of(context),
+ timelineWidth: widget.timeLineWidth,
),
),
widget.dayDetectorBuilder(
@@ -296,8 +308,11 @@ class _InternalDayViewPageState
date: widget.date,
minuteSlotSize: widget.minuteSlotSize,
),
+ // TODO(Shubham): Update for directionality
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..c965b328 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,
@@ -311,6 +313,7 @@ class _InternalWeekViewPageState
vertical: 2,
horizontal: 1,
),
+ // TODO(Shubham): Add direction
child: Text(
widget.fullDayHeaderTitle,
textAlign:
@@ -353,23 +356,33 @@ 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,
+ // TODO(Shubham): Width of horizontal paint line
+ Positioned(
+ left: isLtr ? widget.timeLineWidth : 0,
+ // TODO(Shubham): Check padding of 6 from somewhere
+ 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 +418,13 @@ class _InternalWeekViewPageState
widget.quarterHourIndicatorSettings.dashWidth,
dashSpaceWidth: widget
.quarterHourIndicatorSettings.dashSpaceWidth,
+ textDirection: Directionality.of(context),
),
),
Align(
- alignment: Alignment.centerRight,
+ alignment: Directionality.of(context) == TextDirection.ltr
+ ? Alignment.centerRight
+ : Alignment.centerLeft,
child: SizedBox(
width: widget.weekTitleWidth * filteredDates.length,
height: widget.height,
@@ -486,7 +502,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..8c316a3e 100644
--- a/lib/src/week_view/week_view.dart
+++ b/lib/src/week_view/week_view.dart
@@ -492,6 +492,7 @@ class WeekViewState extends State> {
@override
Widget build(BuildContext context) {
+ // TODO(Shubham): Check directionality for quarter and half hours as well
return SafeAreaWrapper(
option: widget.safeAreaOption,
child: LayoutBuilder(builder: (context, constraint) {
@@ -886,6 +887,7 @@ class WeekViewState extends State> {
emulateVerticalOffsetBy: emulateVerticalOffsetBy,
startHour: startHour,
endHour: endHour,
+ textDirection: Directionality.of(context),
);
}