forked from firka/firka
tt: add monthly screen
This commit is contained in:
@@ -33,7 +33,7 @@ extension DurationExtension on Duration {
|
||||
}
|
||||
}
|
||||
|
||||
enum FormatMode { yearly, grades, welcome, hmm, da, dd, yyyymmddwedd }
|
||||
enum FormatMode { yearly, grades, welcome, hmm, da, dd, yyyymmddwedd, yyyymmmm }
|
||||
|
||||
enum Cycle { morning, day, afternoon, night }
|
||||
|
||||
@@ -81,6 +81,8 @@ extension DateExtension on DateTime {
|
||||
return DateFormat('dd').format(this);
|
||||
case FormatMode.yyyymmddwedd:
|
||||
return "${DateFormat('yyyy MMM. dd').format(weekStart).toLowerCase()}-${DateFormat('dd').format(weekEnd)}";
|
||||
case FormatMode.yyyymmmm:
|
||||
return DateFormat('yyyy MMMM').format(weekStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import '../../../model/style.dart';
|
||||
|
||||
class HomeGradesScreen extends StatelessAsyncWidget {
|
||||
final AppInitialization data;
|
||||
final void Function(ActiveHomePage) cb;
|
||||
final void Function(ActiveHomePage, bool) cb;
|
||||
|
||||
const HomeGradesScreen(this.data, this.cb, {super.key});
|
||||
|
||||
@@ -57,7 +57,7 @@ class HomeGradesScreen extends StatelessAsyncWidget {
|
||||
gradeCards.add(GestureDetector(
|
||||
child: GradeSmallCard(grades.response!, subject),
|
||||
onTap: () {
|
||||
cb(ActiveHomePage(HomePages.grades, subPageUid: subject.uid));
|
||||
cb(ActiveHomePage(HomePages.grades, subPageUid: subject.uid), true);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
@@ -10,13 +10,15 @@ import 'package:transparent_pointer/transparent_pointer.dart';
|
||||
|
||||
import '../../../../main.dart';
|
||||
import '../../../widget/firka_icon.dart';
|
||||
import '../../screens/home/home_screen.dart';
|
||||
import '../../widgets/bottom_tt_icon.dart';
|
||||
import '../../widgets/tt_day.dart';
|
||||
|
||||
class HomeTimetableScreen extends StatefulWidget {
|
||||
final AppInitialization data;
|
||||
final void Function(ActiveHomePage, bool) cb;
|
||||
|
||||
const HomeTimetableScreen(this.data, {super.key});
|
||||
const HomeTimetableScreen(this.data, this.cb, {super.key});
|
||||
|
||||
@override
|
||||
State<HomeTimetableScreen> createState() => _HomeTimetableScreen();
|
||||
@@ -130,17 +132,23 @@ class _HomeTimetableScreen extends State<HomeTimetableScreen> {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Card(
|
||||
color: appStyle.colors.buttonSecondaryFill,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: FirkaIconWidget(
|
||||
FirkaIconType.majesticons,
|
||||
Majesticon.tableSolid,
|
||||
size: 26.0,
|
||||
color: appStyle.colors.accent,
|
||||
GestureDetector(
|
||||
child: Card(
|
||||
color: appStyle.colors.buttonSecondaryFill,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: FirkaIconWidget(
|
||||
FirkaIconType.majesticons,
|
||||
Majesticon.tableSolid,
|
||||
size: 26.0,
|
||||
color: appStyle.colors.accent,
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
widget.cb(
|
||||
ActiveHomePage(HomePages.timetableMo), false);
|
||||
},
|
||||
),
|
||||
Card(
|
||||
color: appStyle.colors.buttonSecondaryFill,
|
||||
|
||||
308
firka/lib/ui/phone/pages/home/home_timetable_mo.dart
Normal file
308
firka/lib/ui/phone/pages/home/home_timetable_mo.dart
Normal file
@@ -0,0 +1,308 @@
|
||||
import 'package:carousel_slider/carousel_slider.dart';
|
||||
import 'package:firka/helpers/api/model/timetable.dart';
|
||||
import 'package:firka/helpers/debug_helper.dart';
|
||||
import 'package:firka/helpers/extensions.dart';
|
||||
import 'package:firka/ui/model/style.dart';
|
||||
import 'package:firka/ui/widget/delayed_spinner.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:majesticons_flutter/majesticons_flutter.dart';
|
||||
import 'package:transparent_pointer/transparent_pointer.dart';
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
|
||||
import '../../../../main.dart';
|
||||
import '../../../widget/firka_icon.dart';
|
||||
import '../../screens/home/home_screen.dart';
|
||||
|
||||
class HomeTimetableMonthlyScreen extends StatefulWidget {
|
||||
final AppInitialization data;
|
||||
final void Function(ActiveHomePage, bool) cb;
|
||||
|
||||
const HomeTimetableMonthlyScreen(this.data, this.cb, {super.key});
|
||||
|
||||
@override
|
||||
State<HomeTimetableMonthlyScreen> createState() =>
|
||||
_HomeTimetableMonthlyScreen();
|
||||
}
|
||||
|
||||
class _HomeTimetableMonthlyScreen extends State<HomeTimetableMonthlyScreen> {
|
||||
List<Lesson>? lessons;
|
||||
List<DateTime>? dates;
|
||||
DateTime? now;
|
||||
int active = 0;
|
||||
bool disposed = false;
|
||||
|
||||
_HomeTimetableMonthlyScreen();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
Future<void> initForMonth(DateTime now) async {
|
||||
final monthStart = DateTime.utc(now.year, now.month, 1);
|
||||
final monthEnd =
|
||||
DateTime.utc(now.year, now.month + 1).subtract(Duration(days: 1));
|
||||
|
||||
final start = monthStart.subtract(Duration(days: 7)).getMonday();
|
||||
var end =
|
||||
monthEnd.add(Duration(days: 7)).getMonday().add(Duration(days: 7));
|
||||
|
||||
var days = end.difference(start).inDays;
|
||||
|
||||
var lessonsResp =
|
||||
await widget.data.client.getTimeTable(monthStart, monthEnd);
|
||||
List<DateTime> dates = List.empty(growable: true);
|
||||
|
||||
for (var i = 0; i < days; i++) {
|
||||
dates.add(start.add(Duration(days: i)));
|
||||
}
|
||||
|
||||
if (lessonsResp.response != null) {
|
||||
lessons = lessonsResp.response;
|
||||
}
|
||||
|
||||
if (disposed) return;
|
||||
setState(() {
|
||||
this.dates = dates;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
now = timeNow();
|
||||
initForMonth(now!);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (lessons != null && dates != null) {
|
||||
List<Widget> ttDays = [];
|
||||
|
||||
final meow = dates![20];
|
||||
final currentMonthStart = DateTime.utc(meow.year, meow.month, 1);
|
||||
final currentMonthEnd =
|
||||
DateTime.utc(meow.year, meow.month + 1).subtract(Duration(days: 1));
|
||||
|
||||
for (var d in dates!) {
|
||||
if (d.isBefore(currentMonthStart) || d.isAfter(currentMonthEnd)) {
|
||||
ttDays.add(Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: ShapeDecoration(
|
||||
color: appStyle.colors.cardTranslucent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6)),
|
||||
)),
|
||||
SizedBox(height: 4),
|
||||
Text(d.format(widget.data.l10n, FormatMode.dd),
|
||||
style: appStyle.fonts.B_14R.apply(
|
||||
color: (d.weekday == DateTime.saturday ||
|
||||
d.weekday == DateTime.sunday)
|
||||
? appStyle.colors.errorText
|
||||
: appStyle.colors.textTertiary)),
|
||||
SizedBox(height: 12),
|
||||
],
|
||||
));
|
||||
} else {
|
||||
Widget body = SizedBox();
|
||||
|
||||
var lessonsToday = lessons!.where((lesson) =>
|
||||
lesson.start.isAfter(d.getMidnight()) &&
|
||||
lesson.end.isBefore(
|
||||
d.getMidnight().add(Duration(hours: 23, minutes: 59))));
|
||||
|
||||
if (lessonsToday.isNotEmpty) {
|
||||
body = Center(
|
||||
child: Text(lessonsToday.length.toString(),
|
||||
style: appStyle.fonts.H_16px
|
||||
.apply(color: appStyle.colors.secondary)),
|
||||
);
|
||||
}
|
||||
ttDays.add(Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: ShapeDecoration(
|
||||
color: appStyle.colors.card,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6)),
|
||||
),
|
||||
child: body,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(d.format(widget.data.l10n, FormatMode.dd),
|
||||
style: appStyle.fonts.B_14R.apply(
|
||||
color: (d.weekday == DateTime.saturday ||
|
||||
d.weekday == DateTime.sunday) &&
|
||||
lessonsToday.isEmpty
|
||||
? appStyle.colors.errorText
|
||||
: appStyle.colors.textSecondary)),
|
||||
SizedBox(height: 12),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return Stack(children: [
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: 74 + 16,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.data.l10n.timetable,
|
||||
style: appStyle.fonts.H_H2
|
||||
.apply(color: appStyle.colors.textPrimary),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
child: Card(
|
||||
color: appStyle.colors.buttonSecondaryFill,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: FirkaIconWidget(
|
||||
FirkaIconType.majesticons,
|
||||
Majesticon.tableSolid,
|
||||
size: 26.0,
|
||||
color: appStyle.colors.accent,
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
widget.cb(
|
||||
ActiveHomePage(HomePages.timetable), false);
|
||||
},
|
||||
),
|
||||
Card(
|
||||
color: appStyle.colors.buttonSecondaryFill,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: FirkaIconWidget(
|
||||
FirkaIconType.majesticons,
|
||||
Majesticon.plusLine,
|
||||
size: 32.0,
|
||||
color: appStyle.colors.accent,
|
||||
),
|
||||
),
|
||||
),
|
||||
Card(
|
||||
color: appStyle.colors.buttonSecondaryFill,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: FirkaIconWidget(
|
||||
FirkaIconType.majesticons,
|
||||
Majesticon.settingsCogSolid,
|
||||
size: 26.0,
|
||||
color: appStyle.colors.accent,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: FirkaIconWidget(
|
||||
FirkaIconType.icons,
|
||||
"dropdownLeft",
|
||||
size: 24,
|
||||
color: appStyle.colors.accent,
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
var newNow = now!.subtract(Duration(days: 30));
|
||||
setState(() {
|
||||
now = newNow;
|
||||
lessons = null;
|
||||
dates = null;
|
||||
});
|
||||
await initForMonth(newNow);
|
||||
setState(() {
|
||||
now = newNow;
|
||||
});
|
||||
},
|
||||
),
|
||||
Text(
|
||||
now!
|
||||
.format(widget.data.l10n, FormatMode.yyyymmmm)
|
||||
.toLowerCase(),
|
||||
style: appStyle.fonts.B_14R),
|
||||
GestureDetector(
|
||||
child: FirkaIconWidget(
|
||||
FirkaIconType.icons,
|
||||
"dropdownRight",
|
||||
size: 24,
|
||||
color: appStyle.colors.accent,
|
||||
),
|
||||
onTap: () async {
|
||||
var newNow = now!.add(Duration(days: 30));
|
||||
setState(() {
|
||||
now = newNow;
|
||||
lessons = null;
|
||||
dates = null;
|
||||
});
|
||||
await initForMonth(newNow);
|
||||
setState(() {
|
||||
now = newNow;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
TransparentPointer(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 74 + 16 + 12),
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height / 1.45,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: StaggeredGrid.count(
|
||||
crossAxisCount: 7,
|
||||
children: ttDays,
|
||||
),
|
||||
)),
|
||||
)),
|
||||
]);
|
||||
} else {
|
||||
return SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 1.35,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(),
|
||||
DelayedSpinnerWidget(),
|
||||
SizedBox(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import 'package:firka/main.dart';
|
||||
import 'package:firka/ui/model/style.dart';
|
||||
import 'package:firka/ui/phone/pages/home/home_grades.dart';
|
||||
import 'package:firka/ui/phone/pages/home/home_main.dart';
|
||||
import 'package:firka/ui/phone/pages/home/home_timetable_mo.dart';
|
||||
import 'package:firka/ui/phone/widgets/bottom_nav_icon.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -30,7 +31,7 @@ class HomeScreen extends StatefulWidget {
|
||||
State<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
enum HomePages { home, grades, timetable }
|
||||
enum HomePages { home, grades, timetable, timetableMo }
|
||||
|
||||
enum ActiveToastType { fetching, error, none }
|
||||
|
||||
@@ -63,9 +64,9 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
|
||||
ActiveToastType activeToast = ActiveToastType.none;
|
||||
|
||||
void setPageCB(ActiveHomePage newPage) {
|
||||
void setPageCB(ActiveHomePage newPage, bool setPrev) {
|
||||
setState(() {
|
||||
previousPages.add(page);
|
||||
if (setPrev) previousPages.add(page);
|
||||
canPop = false;
|
||||
page = newPage;
|
||||
});
|
||||
@@ -126,9 +127,8 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
color: appStyle.colors.errorCard,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(200)),
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(200)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 8),
|
||||
child: Row(
|
||||
@@ -370,7 +370,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
|
||||
class HomeSubPage extends StatelessWidget {
|
||||
final ActiveHomePage page;
|
||||
final void Function(ActiveHomePage) cb;
|
||||
final void Function(ActiveHomePage, bool) cb;
|
||||
final AppInitialization data;
|
||||
|
||||
const HomeSubPage(this.page, this.cb, this.data, {super.key});
|
||||
@@ -387,7 +387,9 @@ class HomeSubPage extends StatelessWidget {
|
||||
return HomeGradesScreen(data, cb);
|
||||
}
|
||||
case HomePages.timetable:
|
||||
return HomeTimetableScreen(data);
|
||||
return HomeTimetableScreen(data, cb);
|
||||
case HomePages.timetableMo:
|
||||
return HomeTimetableMonthlyScreen(data, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ dependencies:
|
||||
brotli: ^0.6.0
|
||||
crypto: ^3.0.6
|
||||
transparent_pointer: ^1.0.1
|
||||
flutter_staggered_grid_view: ^0.7.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user