forked from firka/firka
home: add info board list
This commit is contained in:
@@ -214,6 +214,34 @@ class KretaClient {
|
||||
return ApiResponse(items, status, err, cached);
|
||||
}
|
||||
|
||||
ApiResponse<List<InfoBoardItem>>? infoBoardCache;
|
||||
|
||||
Future<ApiResponse<List<InfoBoardItem>>> getInfoBoard(
|
||||
{bool forceCache = true}) async {
|
||||
if (forceCache && infoBoardCache != null) return infoBoardCache!;
|
||||
var (resp, status, ex, cached) = await _cachingGet(CacheId.getInfoBoard,
|
||||
KretaEndpoints.getInfoBoard(model.iss!), forceCache, 0);
|
||||
|
||||
var items = List<InfoBoardItem>.empty(growable: true);
|
||||
String? err;
|
||||
try {
|
||||
List<dynamic> rawItems = resp;
|
||||
for (var item in rawItems) {
|
||||
items.add(InfoBoardItem.fromJson(item));
|
||||
}
|
||||
} catch (ex) {
|
||||
err = ex.toString();
|
||||
}
|
||||
|
||||
if (ex != null) {
|
||||
err = ex.toString();
|
||||
}
|
||||
|
||||
if (err == null) infoBoardCache = ApiResponse(items, 200, null, true);
|
||||
|
||||
return ApiResponse(items, status, err, cached);
|
||||
}
|
||||
|
||||
ApiResponse<List<Grade>>? gradeCache;
|
||||
|
||||
Future<ApiResponse<List<Grade>>> getGrades({bool forceCache = true}) async {
|
||||
|
||||
@@ -67,6 +67,12 @@ class KretaEndpoints {
|
||||
static String getNoticeBoard(String iss) =>
|
||||
"${kreta(iss)}/ellenorzo/v3/sajat/FaliujsagElemek";
|
||||
|
||||
// for some reason the [redacted] devs decided to make
|
||||
// two different apis to get items for the notice board
|
||||
// that appears on the home screen, like wtf
|
||||
static String getInfoBoard(String iss) =>
|
||||
"${kreta(iss)}/ellenorzo/v3/sajat/Feljegyzesek";
|
||||
|
||||
static String getGrades(String iss) =>
|
||||
"${kreta(iss)}/ellenorzo/v3/sajat/Ertekelesek";
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:firka/helpers/api/model/generic.dart';
|
||||
|
||||
class NoticeBoardItem {
|
||||
final String uid;
|
||||
final String author;
|
||||
@@ -40,3 +42,50 @@ class NoticeBoardItem {
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
||||
class InfoBoardItem {
|
||||
final String uid;
|
||||
final String title;
|
||||
final DateTime date;
|
||||
final String author;
|
||||
final DateTime createdAt;
|
||||
final String contentHTML;
|
||||
final String contentText;
|
||||
final NameUidDesc type;
|
||||
|
||||
InfoBoardItem(
|
||||
{required this.uid,
|
||||
required this.title,
|
||||
required this.date,
|
||||
required this.author,
|
||||
required this.createdAt,
|
||||
required this.contentHTML,
|
||||
required this.contentText,
|
||||
required this.type});
|
||||
|
||||
factory InfoBoardItem.fromJson(Map<String, dynamic> json) {
|
||||
return InfoBoardItem(
|
||||
uid: json['Uid'],
|
||||
title: json['Cim'],
|
||||
date: DateTime.parse(json['Datum']),
|
||||
author: json['KeszitoTanarNeve'],
|
||||
createdAt: DateTime.parse(json['KeszitesDatuma']),
|
||||
contentText: json['Tartalom'],
|
||||
contentHTML: json['TartalomFormazott'],
|
||||
type: NameUidDesc.fromJson(json['Tipus']));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'InfoBoard('
|
||||
'uid: "$uid", '
|
||||
'title: "$title", '
|
||||
'date: "$date", '
|
||||
'author: "$author", '
|
||||
'createdAt: "$createdAt", '
|
||||
'contentText: "$contentText", '
|
||||
'contentHTML: "$contentHTML", '
|
||||
'type: $type'
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,14 @@ import 'package:isar/isar.dart';
|
||||
|
||||
part 'generic_cache_model.g.dart';
|
||||
|
||||
enum CacheId { getStudent, getNoticeBoard, getGrades, getOmissions, getTests }
|
||||
enum CacheId {
|
||||
getStudent,
|
||||
getNoticeBoard,
|
||||
getInfoBoard,
|
||||
getGrades,
|
||||
getOmissions,
|
||||
getTests
|
||||
}
|
||||
|
||||
@collection
|
||||
class GenericCacheModel {
|
||||
|
||||
@@ -2,10 +2,12 @@ import 'dart:async';
|
||||
|
||||
import 'package:firka/helpers/extensions.dart';
|
||||
import 'package:firka/ui/phone/widgets/home_main_starting_soon.dart';
|
||||
import 'package:firka/ui/phone/widgets/info_board_item.dart';
|
||||
import 'package:firka/ui/phone/widgets/lesson_small.dart';
|
||||
import 'package:firka/ui/widget/delayed_spinner.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../helpers/api/model/notice_board.dart';
|
||||
import '../../../../helpers/api/model/student.dart';
|
||||
import '../../../../helpers/api/model/timetable.dart';
|
||||
import '../../../../helpers/debug_helper.dart';
|
||||
@@ -31,6 +33,8 @@ class _HomeMainScreen extends State<HomeMainScreen> {
|
||||
|
||||
DateTime now = timeNow();
|
||||
List<Lesson>? lessons;
|
||||
List<NoticeBoardItem>? noticeBoard;
|
||||
List<InfoBoardItem>? infoBoard;
|
||||
Student? student;
|
||||
Timer? timer;
|
||||
|
||||
@@ -48,24 +52,36 @@ class _HomeMainScreen extends State<HomeMainScreen> {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
lessons = newData.$1;
|
||||
student = newData.$2;
|
||||
noticeBoard = newData.$2;
|
||||
infoBoard = newData.$3;
|
||||
student = newData.$4;
|
||||
});
|
||||
}
|
||||
widget.finishNotifier.update();
|
||||
}
|
||||
|
||||
Future<(List<Lesson>, Student)> loadData(DateTime now,
|
||||
{bool forceCache = true}) async {
|
||||
Future<(List<Lesson>, List<NoticeBoardItem>, List<InfoBoardItem>, Student)>
|
||||
loadData(DateTime now, {bool forceCache = true}) async {
|
||||
var midnight = now.getMidnight();
|
||||
|
||||
var respTT = await widget.data.client.getTimeTable(
|
||||
midnight, midnight.add(Duration(hours: 23, minutes: 59)),
|
||||
forceCache: forceCache);
|
||||
|
||||
var respNB =
|
||||
await widget.data.client.getNoticeBoard(forceCache: forceCache);
|
||||
|
||||
var respIB = await widget.data.client.getInfoBoard(forceCache: forceCache);
|
||||
|
||||
var respStudent =
|
||||
await widget.data.client.getStudent(forceCache: forceCache);
|
||||
|
||||
return Future.value((respTT.response!, respStudent.response!));
|
||||
return Future.value((
|
||||
respTT.response!,
|
||||
respNB.response!,
|
||||
respIB.response!,
|
||||
respStudent.response!
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -83,7 +99,9 @@ class _HomeMainScreen extends State<HomeMainScreen> {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
lessons = newData.$1;
|
||||
student = newData.$2;
|
||||
noticeBoard = newData.$2;
|
||||
infoBoard = newData.$3;
|
||||
student = newData.$4;
|
||||
});
|
||||
}
|
||||
})();
|
||||
@@ -111,7 +129,7 @@ class _HomeMainScreen extends State<HomeMainScreen> {
|
||||
Widget nextClass = SizedBox();
|
||||
bool lessonActive = false;
|
||||
|
||||
if (lessons != null && lessons!.isNotEmpty) {
|
||||
if (lessons != null && noticeBoard != null && lessons!.isNotEmpty) {
|
||||
if (now.isBefore(lessons!.first.start)) {
|
||||
welcomeWidget = StartingSoonWidget(widget.data.l10n, now, lessons!);
|
||||
} else {
|
||||
@@ -141,24 +159,37 @@ class _HomeMainScreen extends State<HomeMainScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
if (student != null && lessons != null) {
|
||||
if (student != null && noticeBoard != null && lessons != null) {
|
||||
List<Widget> noticeBoardWidgets = List.empty(growable: true);
|
||||
// TODO: Add notice board items once we actually have those
|
||||
|
||||
for (var item in infoBoard!) {
|
||||
noticeBoardWidgets.add(InfoBoardItemWidget(item));
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20.0,
|
||||
top: 24.0,
|
||||
right: 20.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
WelcomeWidget(widget.data.l10n, now, student!, lessons!),
|
||||
SizedBox(height: 48),
|
||||
welcomeWidget,
|
||||
lessonActive ? SizedBox(height: 5) : SizedBox(height: 0),
|
||||
nextClass
|
||||
],
|
||||
),
|
||||
);
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20.0,
|
||||
top: 24.0,
|
||||
right: 20.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
WelcomeWidget(widget.data.l10n, now, student!, lessons!),
|
||||
SizedBox(height: 48),
|
||||
welcomeWidget,
|
||||
lessonActive ? SizedBox(height: 5) : SizedBox(height: 0),
|
||||
nextClass,
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 1.6,
|
||||
child: ListView(
|
||||
children: noticeBoardWidgets,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return DelayedSpinnerWidget();
|
||||
}
|
||||
|
||||
66
firka/lib/ui/phone/widgets/info_board_item.dart
Normal file
66
firka/lib/ui/phone/widgets/info_board_item.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'package:firka/helpers/ui/firka_card.dart';
|
||||
import 'package:firka/ui/model/style.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../helpers/api/model/notice_board.dart';
|
||||
|
||||
// TODO: Finish
|
||||
class InfoBoardItemWidget extends StatelessWidget {
|
||||
final InfoBoardItem item;
|
||||
|
||||
const InfoBoardItemWidget(this.item, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FirkaCard(left: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
decoration: ShapeDecoration(
|
||||
color: appStyle.colors.accent,
|
||||
shape: CircleBorder(
|
||||
eccentricity: 1,
|
||||
// borderRadius: BorderRadius.circular(6)),
|
||||
)),
|
||||
child: SizedBox(
|
||||
width: 28,
|
||||
height: 28,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: Text(
|
||||
item.author[0],
|
||||
style: appStyle.fonts.H_18px.copyWith(
|
||||
fontSize: 20, color: appStyle.colors.textPrimary),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 1.4,
|
||||
child: Text(
|
||||
item.title,
|
||||
style: appStyle.fonts.B_14SB
|
||||
.apply(color: appStyle.colors.textPrimary),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
item.author,
|
||||
style: appStyle.fonts.B_14R
|
||||
.apply(color: appStyle.colors.textSecondary),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
16
firka/lib/ui/phone/widgets/notice_board_item.dart
Normal file
16
firka/lib/ui/phone/widgets/notice_board_item.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:firka/helpers/ui/firka_card.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../helpers/api/model/notice_board.dart';
|
||||
|
||||
// TODO: Finish
|
||||
class NoticeBoardItemWidget extends StatelessWidget {
|
||||
final NoticeBoardItem item;
|
||||
|
||||
const NoticeBoardItemWidget(this.item, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FirkaCard(left: [Text(item.title)]);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:firka/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(const MyApp());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user