Last active
August 5, 2022 14:20
-
-
Save chaudharydeepanshu/c1e3fe0386cb464514f62b73305962ee to your computer and use it in GitHub Desktop.
data_grid_jank_example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: ThemeData.light( | |
useMaterial3: true, | |
), | |
darkTheme: ThemeData.dark( | |
useMaterial3: true, | |
), | |
themeMode: ThemeMode.system, | |
home: const Home(), | |
); | |
} | |
} | |
class Home extends StatefulWidget { | |
const Home({Key? key}) : super(key: key); | |
@override | |
State<Home> createState() => _HomeState(); | |
} | |
class _HomeState extends State<Home> { | |
late PageController _controller; | |
// This points always to the mid-element in _list | |
late int _initialIndex; | |
// This should work with 3, 7, 11, ... odd elements. Mind the pattern!!! | |
List<int> list = [-2, -1, 0, 1, 2]; | |
@override | |
void initState() { | |
super.initState(); | |
// Calculate mid. | |
_initialIndex = (list.length / 2).floor(); | |
_controller = | |
PageController(initialPage: _initialIndex, viewportFraction: 1); | |
// This is where we listen to changes. | |
_controller.addListener(() { | |
// Get index according to the direction | |
// _controller.page! > _initialIndex => swiping to the right, going to the left / previous element | |
// _controller.page! < _initialIndex => swiping to the left, going to the right / next element | |
final index = _controller.page! > _initialIndex | |
? _controller.page!.floor() | |
: _controller.page!.ceil(); | |
if (index == _initialIndex) return; | |
if (index == _initialIndex - 1) { | |
_prev(); | |
} else if (index == _initialIndex + 1) { | |
_next(); | |
} | |
}); | |
} | |
@override | |
void dispose() { | |
_controller.dispose(); | |
super.dispose(); | |
} | |
// Update list and jump to the middle element | |
void _next() { | |
setState(() { | |
list | |
..removeAt(0) | |
..insert(list.length, list.last + 1); | |
// Update current DateTime here | |
}); | |
_controller.jumpToPage(_initialIndex); | |
} | |
// Update list and jump to the middle element | |
void _prev() { | |
setState(() { | |
list | |
..insert(0, list.first - 1) | |
..removeLast(); | |
// Update current DateTime here | |
}); | |
_controller.jumpToPage(_initialIndex); | |
} | |
List months = [ | |
'jan', | |
'feb', | |
'mar', | |
'apr', | |
'may', | |
'jun', | |
'jul', | |
'aug', | |
'sep', | |
'oct', | |
'nov', | |
'dec' | |
]; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
elevation: 2, | |
title: const Text("Data Grid"), | |
), | |
body: PageView.builder( | |
controller: _controller, | |
itemCount: list.length, | |
itemBuilder: (BuildContext context, int index) { | |
DateTime gridDateTime = DateTime(2022, 8 + list[index], 1); | |
List<DateTime> allDatesOfCalendarMonth = | |
getDatesForACalendarMonthAsUTC(dateTime: gridDateTime); | |
return Column( | |
children: [ | |
Text(months[gridDateTime.month - 1] + | |
" " + | |
gridDateTime.year.toString()), | |
GridView.builder( | |
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( | |
childAspectRatio: 1, | |
crossAxisCount: 7, | |
mainAxisExtent: 40, | |
), | |
itemCount: 42, | |
physics: const NeverScrollableScrollPhysics(), | |
shrinkWrap: true, | |
itemBuilder: (context, i) { | |
return DataWidget( | |
dataDateTime: allDatesOfCalendarMonth[i], | |
gridDateTime: gridDateTime, | |
); | |
}, | |
), | |
], | |
); | |
}), | |
); | |
} | |
} | |
class DataWidget extends StatelessWidget { | |
const DataWidget( | |
{Key? key, required this.dataDateTime, required this.gridDateTime}) | |
: super(key: key); | |
final DateTime dataDateTime; | |
final DateTime gridDateTime; | |
@override | |
Widget build(BuildContext context) { | |
return Row( | |
children: [ | |
const Expanded( | |
child: SizedBox(), | |
), | |
OutlinedButton( | |
style: OutlinedButton.styleFrom( | |
minimumSize: Size.zero, | |
padding: EdgeInsets.zero, | |
foregroundColor: Theme.of(context).colorScheme.onSurface, | |
tapTargetSize: MaterialTapTargetSize.shrinkWrap, | |
side: BorderSide.none, | |
shape: const RoundedRectangleBorder( | |
borderRadius: BorderRadius.all(Radius.circular(12)), | |
), | |
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)), | |
onPressed: dataDateTime.month == gridDateTime.month | |
? () { | |
//do something | |
} | |
: null, | |
child: SizedBox( | |
width: 40, | |
child: Container( | |
margin: const EdgeInsets.all(4.0), | |
child: Ink( | |
decoration: BoxDecoration( | |
border: Border.all( | |
color: Theme.of(context).dividerColor, width: 1), | |
borderRadius: const BorderRadius.all(Radius.circular(12)), | |
), | |
child: Center( | |
child: Text( | |
dataDateTime.day.toString(), | |
style: const TextStyle(), | |
), | |
), | |
), | |
), | |
), | |
), | |
const Expanded( | |
child: SizedBox(), | |
), | |
], | |
); | |
} | |
} | |
List<DateTime> getDatesForACalendarMonthAsUTC({required DateTime dateTime}) { | |
List<DateTime> calendarMonthDaysAsUTC = []; | |
DateTime currentDateTime = DateTime.utc(dateTime.year, dateTime.month, 1); | |
DateTime firstDayOfMonthAsUTC = | |
DateTime.utc(currentDateTime.year, currentDateTime.month, 1); | |
DateTime lastDayOfMonthAsUTC = | |
getLastDayOfAMonth(currentDateTime: currentDateTime); | |
List<DateTime> datesFirstToLastDayOfMonthAsUTC = | |
getDaysInBetweenIncludingStartEndDate( | |
startDateTime: firstDayOfMonthAsUTC, | |
endDateTime: lastDayOfMonthAsUTC); | |
calendarMonthDaysAsUTC = List.generate(datesFirstToLastDayOfMonthAsUTC.length, | |
(index) => datesFirstToLastDayOfMonthAsUTC[index]); | |
int firstDayOfMonthWeekDay = firstDayOfMonthAsUTC.weekday; | |
for (int i = 1; | |
i <= firstDayOfMonthWeekDay && firstDayOfMonthWeekDay != 7; | |
i++) { | |
calendarMonthDaysAsUTC.insert( | |
0, firstDayOfMonthAsUTC.subtract(Duration(days: i))); | |
} | |
int daysLeftAfterMonthEndDate = 42 - calendarMonthDaysAsUTC.length; | |
for (int i = 1; i <= daysLeftAfterMonthEndDate; i++) { | |
calendarMonthDaysAsUTC.add(lastDayOfMonthAsUTC.add(Duration(days: i))); | |
} | |
return calendarMonthDaysAsUTC; | |
} | |
List<DateTime> getDaysInBetweenIncludingStartEndDate( | |
{required DateTime startDateTime, required DateTime endDateTime}) { | |
// Converting dates provided to UTC | |
// So that all things like DST don't affect subtraction and addition on dates | |
DateTime startDateInUTC = | |
DateTime.utc(startDateTime.year, startDateTime.month, startDateTime.day); | |
DateTime endDateInUTC = | |
DateTime.utc(endDateTime.year, endDateTime.month, endDateTime.day); | |
// Created a list to hold all dates | |
List<DateTime> daysInFormat = []; | |
// Starting a loop with the initial value as the Start Date | |
// With an increment of 1 day on each loop | |
// With condition current value of loop is smaller than or same as end date | |
for (DateTime i = startDateInUTC; | |
i.isBefore(endDateInUTC) || i.isAtSameMomentAs(endDateInUTC); | |
i = i.add(const Duration(days: 1))) { | |
// Converting back UTC date to Local date before inserting in list | |
// You can keep in UTC format depending on your case | |
if (startDateTime.isUtc) { | |
daysInFormat.add(i); | |
} else { | |
daysInFormat.add(DateTime(i.year, i.month, i.day)); | |
} | |
} | |
return daysInFormat; | |
} | |
DateTime getLastDayOfAMonth({required DateTime currentDateTime}) { | |
// Getting the 15th-day date of the month for the date provided | |
DateTime fifteenthDayOfMonth = | |
DateTime(currentDateTime.year, currentDateTime.month, 15); | |
// Converting the 15th-day date to UTC | |
// So that all things like DST don't affect subtraction and addition on date | |
DateTime twentiethDayOfMonthInUTC = fifteenthDayOfMonth.toUtc(); | |
// Getting a random date of next month by adding 20 days to twentiethDayOfMonthInUTC | |
// Adding number 20 to any month 15th-day will definitely give a next month date | |
DateTime nextMonthRandomDateInUTC = | |
twentiethDayOfMonthInUTC.add(const Duration(days: 20)); | |
DateTime nextMonthRandomDateZeroDayInUTC = DateTime.utc( | |
nextMonthRandomDateInUTC.year, nextMonthRandomDateInUTC.month, 0); | |
// Now getting the 0th day date of the next month | |
// This will give us the current month last date | |
DateTime nextMonthRandomDateZeroDayInLocal = DateTime( | |
nextMonthRandomDateInUTC.year, nextMonthRandomDateInUTC.month, 0); | |
DateTime lastDayOfAMonth; | |
if (currentDateTime.isUtc) { | |
lastDayOfAMonth = nextMonthRandomDateZeroDayInUTC; | |
} else { | |
lastDayOfAMonth = nextMonthRandomDateZeroDayInLocal; | |
} | |
return lastDayOfAMonth; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment