Skip to content

Commit 1d9e822

Browse files
committed
Implement custom Calendar Event View to highlight deleted Events
1 parent 3fa09df commit 1d9e822

File tree

8 files changed

+293
-3
lines changed

8 files changed

+293
-3
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import 'package:flutter/material.dart';
2+
3+
import 'package:campus_flutter/base/util/diagonalStripePattern/stripe_pattern_painter.dart';
4+
5+
/// source: https://github.com/LuuNgocLan/flutter-snippets/blob/main/flutter_stripe_canvas/lib/diagonal_stripe/diagonal_stripe_pattern_view.dart
6+
class DiagonalStripePatternView extends StatelessWidget {
7+
final double? stripeWidth;
8+
final double? gapWidth;
9+
final double? rotateDegree;
10+
final Color? stripeColor;
11+
final Color? bgColor;
12+
13+
const DiagonalStripePatternView({
14+
super.key,
15+
this.stripeColor,
16+
this.stripeWidth,
17+
this.gapWidth,
18+
this.rotateDegree,
19+
this.bgColor,
20+
});
21+
22+
@override
23+
Widget build(BuildContext context) {
24+
return LayoutBuilder(
25+
builder: (context, constraints) {
26+
/// Cut the excess border around the frame by using ClipRRect
27+
return ClipRRect(
28+
child: CustomPaint(
29+
/// The screen size we grabbed a few lines earlie
30+
/// default: Size.zero
31+
size: Size(constraints.maxWidth, constraints.maxHeight),
32+
33+
/// use foregroundPainter as overlay mark
34+
foregroundPainter: StripePatternPainter(
35+
stripeColor: stripeColor ??
36+
const Color(0xFF222222).withValues(alpha: 0.08),
37+
bgColor: bgColor,
38+
),
39+
),
40+
);
41+
},
42+
);
43+
}
44+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import 'dart:math';
2+
3+
import 'package:flutter/material.dart';
4+
5+
/// source: https://github.com/LuuNgocLan/flutter-snippets/blob/main/flutter_stripe_canvas/lib/diagonal_stripe/stripe_pattern_painter.dart
6+
class StripePatternPainter extends CustomPainter {
7+
final double stripeWidth;
8+
final double gapWidth;
9+
final double rotateDegree;
10+
final Color stripeColor;
11+
final Color bgColor;
12+
13+
StripePatternPainter({
14+
this.stripeWidth = 5.0,
15+
this.gapWidth = 5.0,
16+
this.rotateDegree = 45.0,
17+
this.stripeColor = Colors.grey,
18+
Color? bgColor,
19+
}) : bgColor = bgColor ?? Colors.transparent;
20+
21+
@override
22+
void paint(Canvas canvas, Size size) {
23+
/// Expand canvas size
24+
const offsetX = 0.0;
25+
const offsetY = 0.0;
26+
final width = size.width + offsetX * 2;
27+
final height = size.height + offsetY * 2;
28+
29+
/// Shift canvas to top,left with offsetX,Y
30+
canvas.translate(-offsetX, -offsetY);
31+
32+
/// Calculate the biggest diagonal of the screen.
33+
final double diagonal = sqrt(width * width + height * height);
34+
35+
/// jointSize: distance from right edge of (i) stripe to right one of next stripe
36+
final double jointSize = stripeWidth + gapWidth;
37+
38+
/// Calculate the number of iterations needed to cover the diagonal of the screen.
39+
final int numIterations = (diagonal / jointSize).ceil();
40+
41+
/// convert degree to radian
42+
final rotateRadian = pi / 180 * rotateDegree;
43+
44+
/// calculate the xOffset, yOffset according to the trigonometric formula
45+
final xOffset = jointSize / sin(rotateRadian);
46+
final yOffset = jointSize / sin(pi / 2 - rotateRadian);
47+
48+
/// config stroke paint object
49+
final paint = Paint()
50+
..color = stripeColor
51+
..style = PaintingStyle.stroke
52+
..strokeWidth = stripeWidth;
53+
final path = Path();
54+
55+
/// setup the path
56+
for (int i = 0; i < numIterations; i++) {
57+
/// start point on Y axis -> xStart = 0
58+
final double yStart = i * yOffset;
59+
60+
/// end point on X axis -> yEnd = 0
61+
final double xEnd = i * xOffset;
62+
63+
/// make line start -> end
64+
path.moveTo(0, yStart);
65+
path.lineTo(xEnd, 0);
66+
}
67+
68+
/// draw path on canvas by using paint object
69+
canvas.drawPath(path, paint);
70+
71+
/// Fill the pattern area background with the patternColor.
72+
final patternPaint = Paint()
73+
..color = bgColor
74+
..style = PaintingStyle.fill;
75+
canvas.drawRect(Offset.zero & size, patternPaint);
76+
}
77+
78+
@override
79+
bool shouldRepaint(covariant CustomPainter oldDelegate) {
80+
return oldDelegate != this;
81+
}
82+
}

lib/calendarComponent/model/calendar_data_source.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ class MeetingDataSource extends CalendarDataSource {
3434
@override
3535
String getSubject(int index) {
3636
final calendarEvent = cast<CalendarEvent>(appointments![index])!;
37-
final location = calendarEvent.locations.firstOrNull ?? "";
38-
return "${calendarEvent.title}\n$location";
37+
return calendarEvent.subject;
3938
}
4039

4140
@override

lib/calendarComponent/model/calendar_event.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ class CalendarEvent extends Searchable {
3535
}
3636

3737
String get timePeriod {
38-
return "${DateFormat.Hm().format(startDate)} - ${DateFormat.Hm().format(endDate)}";
38+
return "${DateFormat.Hm().format(
39+
startDate,
40+
)} - ${DateFormat.Hm().format(
41+
endDate,
42+
)}";
3943
}
4044

4145
String _dateTimePeriod(BuildContext context) {
@@ -67,6 +71,11 @@ class CalendarEvent extends Searchable {
6771
return status == "CANCEL";
6872
}
6973

74+
String get subject {
75+
final location = locations.firstOrNull ?? "";
76+
return "$title\n$location";
77+
}
78+
7079
void setColor(Color? color) {
7180
this.color = color?.value;
7281
}

lib/calendarComponent/views/calendar_day_view.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'package:campus_flutter/calendarComponent/model/calendar_data_source.dart';
2+
import 'package:campus_flutter/calendarComponent/model/calendar_event.dart';
23
import 'package:campus_flutter/calendarComponent/services/calendar_view_service.dart';
34
import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart';
5+
import 'package:campus_flutter/calendarComponent/views/calendar_event_view.dart';
46
import 'package:campus_flutter/calendarComponent/views/calendars_view.dart';
57
import 'package:campus_flutter/main.dart';
68
import 'package:flutter/material.dart';
@@ -55,6 +57,13 @@ class CalendarDayView extends ConsumerWidget {
5557
endHour: 22,
5658
timeFormat: "HH:mm",
5759
),
60+
appointmentBuilder: (context, details) {
61+
final calendarEvent = details.appointments.first as CalendarEvent;
62+
return CalendarEventView(
63+
calendarEvent: calendarEvent,
64+
bounds: details.bounds,
65+
);
66+
},
5867
),
5968
),
6069
),
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import 'package:campus_flutter/base/util/diagonalStripePattern/diagonal_stripe_pattern_view.dart';
2+
import 'package:campus_flutter/calendarComponent/model/calendar_event.dart';
3+
import 'package:easy_localization/easy_localization.dart';
4+
import 'package:flutter/material.dart';
5+
6+
class CalendarEventView extends StatelessWidget {
7+
const CalendarEventView({
8+
super.key,
9+
required this.calendarEvent,
10+
required this.bounds,
11+
this.isMonthly = false,
12+
});
13+
14+
final CalendarEvent calendarEvent;
15+
final Rect bounds;
16+
final bool isMonthly;
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
if (!(calendarEvent.isVisible ?? true)) {
21+
return _hiddenCalendarEvent(context);
22+
} else {
23+
return _visibleCalendarEvent(context);
24+
}
25+
}
26+
27+
Widget _hiddenCalendarEvent(BuildContext context) {
28+
return SizedBox(
29+
height: bounds.height,
30+
width: bounds.width,
31+
child: Stack(
32+
children: [
33+
DiagonalStripePatternView(
34+
stripeColor: calendarEvent.getColor(),
35+
bgColor: calendarEvent.getColor().withValues(
36+
alpha: Theme.of(context).brightness == Brightness.light
37+
? 0.625
38+
: 0.5,
39+
),
40+
),
41+
_content(context),
42+
],
43+
),
44+
);
45+
}
46+
47+
Widget _visibleCalendarEvent(BuildContext context) {
48+
return Container(
49+
height: bounds.height,
50+
width: bounds.width,
51+
decoration: BoxDecoration(color: calendarEvent.getColor()),
52+
child: _content(context),
53+
);
54+
}
55+
56+
Widget _content(BuildContext context) {
57+
final padding = 2.5;
58+
final style = Theme.of(context).textTheme.bodyMedium!.copyWith(
59+
color: Colors.white,
60+
fontSize: 12,
61+
fontWeight: FontWeight.w600,
62+
);
63+
64+
return Padding(
65+
padding: EdgeInsets.only(
66+
top: padding,
67+
left: padding,
68+
right: padding,
69+
bottom: 2.5,
70+
),
71+
child: isMonthly
72+
? Column(
73+
crossAxisAlignment: CrossAxisAlignment.start,
74+
children: [
75+
Expanded(
76+
child: _text(style, padding, context),
77+
),
78+
_timePeriod(style),
79+
],
80+
)
81+
: _text(style, padding, context),
82+
);
83+
}
84+
85+
Widget _text(
86+
TextStyle? style,
87+
double padding,
88+
BuildContext context,
89+
) {
90+
return Text(
91+
calendarEvent.subject,
92+
style: style,
93+
maxLines: _calculateLineLimit(style, padding, context),
94+
);
95+
}
96+
97+
Widget _timePeriod(TextStyle? style) {
98+
return Text(
99+
calendarEvent.timePeriod,
100+
style: style,
101+
maxLines: 1,
102+
);
103+
}
104+
105+
int? _calculateLineLimit(
106+
TextStyle? style,
107+
double padding,
108+
BuildContext context,
109+
) {
110+
var absoluteHeight = bounds.height - padding * 2;
111+
112+
if (style == null) {
113+
return null;
114+
}
115+
116+
final lineHeight = (style.height ?? 0.0) * (style.fontSize ?? 0.0);
117+
118+
if (lineHeight == 0.0) {
119+
return null;
120+
}
121+
122+
if (isMonthly) {
123+
absoluteHeight = absoluteHeight - lineHeight;
124+
}
125+
126+
return (absoluteHeight / lineHeight).floor();
127+
}
128+
}

lib/calendarComponent/views/calendar_month_view.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'package:campus_flutter/calendarComponent/model/calendar_data_source.dart';
2+
import 'package:campus_flutter/calendarComponent/model/calendar_event.dart';
23
import 'package:campus_flutter/calendarComponent/services/calendar_view_service.dart';
34
import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart';
5+
import 'package:campus_flutter/calendarComponent/views/calendar_event_view.dart';
46
import 'package:campus_flutter/calendarComponent/views/calendars_view.dart';
57
import 'package:campus_flutter/main.dart';
68
import 'package:flutter/material.dart';
@@ -59,6 +61,14 @@ class CalendarMonthView extends ConsumerWidget {
5961
}
6062
},
6163
appointmentTimeTextFormat: "HH:mm",
64+
appointmentBuilder: (context, details) {
65+
final calendarEvent = details.appointments.first as CalendarEvent;
66+
return CalendarEventView(
67+
calendarEvent: calendarEvent,
68+
bounds: details.bounds,
69+
isMonthly: true,
70+
);
71+
},
6272
),
6373
),
6474
),

lib/calendarComponent/views/calendar_week_view.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'package:campus_flutter/calendarComponent/model/calendar_data_source.dart';
2+
import 'package:campus_flutter/calendarComponent/model/calendar_event.dart';
23
import 'package:campus_flutter/calendarComponent/services/calendar_view_service.dart';
34
import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart';
5+
import 'package:campus_flutter/calendarComponent/views/calendar_event_view.dart';
46
import 'package:campus_flutter/calendarComponent/views/calendars_view.dart';
57
import 'package:campus_flutter/main.dart';
68
import 'package:campus_flutter/settingsComponent/views/settings_view.dart';
@@ -62,6 +64,13 @@ class CalendarWeekView extends ConsumerWidget {
6264
endHour: 22,
6365
timeFormat: "HH:mm",
6466
),
67+
appointmentBuilder: (context, details) {
68+
final calendarEvent = details.appointments.first as CalendarEvent;
69+
return CalendarEventView(
70+
calendarEvent: calendarEvent,
71+
bounds: details.bounds,
72+
);
73+
},
6574
),
6675
),
6776
),

0 commit comments

Comments
 (0)