Skip to content

Commit

Permalink
feat: Fixes issue #412: ✨ Add support for RTL directionality
Browse files Browse the repository at this point in the history
  • Loading branch information
shubham-jitiya-simform committed Jan 16, 2025
1 parent 469cc29 commit 8e5990b
Show file tree
Hide file tree
Showing 18 changed files with 284 additions and 75 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# [1.4.1 - Unreleased]

- Adds clear method to `EventController`.
- Adds support of RTL in mobile view. [#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)

Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,28 @@ WeekView(
);
```

### 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(),
),
),
);
```

Above code will create `WeekView` with only five days, from monday to friday.

## Main Contributors
Expand Down
1 change: 1 addition & 0 deletions example/lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class AppConstants {
AppConstants._();

static final List<String> weekTitles = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
static final ltr = '\u202A'; // Use this to keep text direction LTR

static OutlineInputBorder inputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(7),
Expand Down
23 changes: 13 additions & 10 deletions example/lib/pages/day_view_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ class DayViewPageDemo extends StatefulWidget {
class _DayViewPageDemoState extends State<DayViewPageDemo> {
@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(),
),
);
}
Expand Down
9 changes: 6 additions & 3 deletions example/lib/pages/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ class HomePage extends StatelessWidget {

@override
Widget build(BuildContext context) {
return ResponsiveWidget(
mobileWidget: MobileHomePage(),
webWidget: WebHomePage(),
return Directionality(
textDirection: TextDirection.rtl,
child: ResponsiveWidget(
mobileWidget: MobileHomePage(),
webWidget: WebHomePage(),
),
);
}
}
4 changes: 2 additions & 2 deletions example/lib/widgets/add_event_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ class _AddOrEditEventFormState extends State<AddOrEditEventForm> {
),
),
Align(
alignment: Alignment.centerLeft,
alignment: Alignment.centerRight,
child: Text(
'Repeat',
style: TextStyle(
Expand Down Expand Up @@ -519,7 +519,7 @@ class _AddOrEditEventFormState extends State<AddOrEditEventForm> {
Row(
children: [
Text(
"Event Color: ",
"${AppConstants.ltr}Event Color: ",
style: TextStyle(
color: AppColors.black,
fontSize: 17,
Expand Down
5 changes: 3 additions & 2 deletions example/lib/widgets/calendar_configs.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 10 additions & 4 deletions example/lib/widgets/day_view_widget.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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,
),
Expand Down Expand Up @@ -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,
Expand All @@ -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,
),
),
],
Expand Down
32 changes: 31 additions & 1 deletion example/lib/widgets/week_view_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,24 @@ 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),
eventArranger: SideEventArranger(
maxWidth: 30,
directionality: Directionality.of(context),
),
timeLineWidth: 65,
scrollPhysics: const BouncingScrollPhysics(),
liveTimeIndicatorSettings: LiveTimeIndicatorSettings(
color: Colors.redAccent,
showTime: true,
showTimeBackgroundView: true,
),
onTimestampTap: (date) {
SnackBar snackBar = SnackBar(
Expand All @@ -45,4 +55,24 @@ 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}"
: "";
// Unicode character for Left-to-Right Embedding
// (to enforce LTR in the string)
const ltr = '\u202A';
// Unicode character for Pop Directional Formatting
// (to close the directional formatting)
const pop = '\u202C';
if (textDirection == TextDirection.rtl) {
return "$ltr${secondaryDateString} to ${dateString}$pop";
} else {
return "$ltr${dateString} to ${secondaryDateString}$pop";
}
}
}
5 changes: 4 additions & 1 deletion lib/src/components/_internal_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,11 @@ class _LiveTimeIndicatorState extends State<LiveTimeIndicator> {
size: Size(widget.width, widget.liveTimeIndicatorSettings.height),
painter: CurrentTimeLinePainter(
color: widget.liveTimeIndicatorSettings.color,
textDirection: Directionality.of(context),
height: widget.liveTimeIndicatorSettings.height,
width: widget.width - widget.timeLineWidth - 12,
offset: Offset(
widget.timeLineWidth + widget.liveTimeIndicatorSettings.offset,
widget.liveTimeIndicatorSettings.offset,
(_currentTime.getTotalMinutes - startMinutes) *
widget.heightPerMinute,
),
Expand Down Expand Up @@ -230,6 +232,7 @@ class _TimeLineState extends State<TimeLine> {
),
child: Stack(
children: [
// TODO(Shubham): Update padding for RTL
for (int i = widget.startHour + 1; i < widget.endHour; i++)
_timelinePositioned(
topPosition: widget.hourHeight * (i - widget.startHour) -
Expand Down
36 changes: 24 additions & 12 deletions lib/src/components/day_view_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:flutter/material.dart';

import '../calendar_event_data.dart';
import '../constants.dart';
import '../extensions.dart';
import '../typedefs.dart';

Expand Down Expand Up @@ -120,12 +121,15 @@ class DefaultTimeLineMark extends StatelessWidget {
/// Text style for time string.
final TextStyle? markingStyle;

final TextDirection? textDirection;

/// Time marker for timeline used in week and day view.
const DefaultTimeLineMark({
Key? key,
required this.date,
this.markingStyle,
this.timeStringBuilder,
this.textDirection,
}) : super(key: key);

@override
Expand All @@ -134,15 +138,18 @@ 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,
// textDirection: Directionality.of(context),
textAlign: Directionality.of(context) == TextDirection.ltr
? TextAlign.right
: TextAlign.left,
style: markingStyle ??
TextStyle(
fontSize: 15.0,
Expand Down Expand Up @@ -212,14 +219,19 @@ class FullDayEventView<T> 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),
Expand Down
1 change: 1 addition & 0 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 15 additions & 1 deletion lib/src/day_view/_internal_day_view_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ class _InternalDayViewPageState<T extends Object?>
@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,
Expand Down Expand Up @@ -269,6 +278,8 @@ class _InternalDayViewPageState<T extends Object?>
widget.halfHourIndicatorSettings.dashSpaceWidth,
startHour: widget.startHour,
endHour: widget.endHour,
textDirection: Directionality.of(context),
timelineWidth: widget.timeLineWidth,
),
),
if (widget.showQuarterHours)
Expand Down Expand Up @@ -296,8 +307,11 @@ class _InternalDayViewPageState<T extends Object?>
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<T>(
height: widget.height,
date: widget.date,
Expand Down
5 changes: 4 additions & 1 deletion lib/src/day_view/day_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -731,10 +731,13 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
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,
Expand Down
Loading

0 comments on commit 8e5990b

Please sign in to comment.