Skip to content

Commit

Permalink
[timetable] handle QR code of Timetable patch
Browse files Browse the repository at this point in the history
  • Loading branch information
liplum committed Apr 30, 2024
1 parent 16cd9aa commit a91d2e7
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 88 deletions.
7 changes: 4 additions & 3 deletions lib/timetable/entity/loc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ class TimetableDayLoc {
static TimetableDayLoc deserialize(ByteReader reader) {
final mode = TimetableDayLocMode.values[reader.uint8()];
switch (mode) {
case TimetableDayLocMode.pos :return TimetableDayLoc.pos(TimetablePos.deserialize(reader));
case TimetableDayLocMode.date :
case TimetableDayLocMode.pos:
return TimetableDayLoc.pos(TimetablePos.deserialize(reader));
case TimetableDayLocMode.date:
final packed = reader.uint16();
return TimetableDayLoc.byDate(_unpackYear(packed), _unpackMonth(packed), _unpackDay(packed));
}
Expand Down Expand Up @@ -133,7 +134,7 @@ int _packDate(DateTime date) {
}

int _unpackYear(int packedDate) {
return (packedDate >> 9) & 0x1FFF; // Mask to get year bits and add 2000
return ((packedDate >> 9) & 0x1FFF) + 2000; // Mask to get year bits and add 2000
}

int _unpackMonth(int packedDate) {
Expand Down
8 changes: 8 additions & 0 deletions lib/timetable/entity/platte.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ class TimetablePalette {
}
}

extension TimetablePaletteX on TimetablePalette {
TimetablePalette markModified() {
return copyWith(
lastModified: DateTime.now(),
);
}
}

class BuiltinTimetablePalette implements TimetablePalette {
final int id;
final String key;
Expand Down
34 changes: 24 additions & 10 deletions lib/timetable/page/mine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,6 @@ class TimetableCard extends StatelessWidget {

@override
Widget build(BuildContext context) {
final year = '${timetable.schoolYear}–${timetable.schoolYear + 1}';
final semester = timetable.semester.l10n();

return EntryCard(
title: timetable.name,
selected: selected,
Expand Down Expand Up @@ -347,13 +344,7 @@ class TimetableCard extends StatelessWidget {
);
},
itemBuilder: (ctx) {
final textTheme = ctx.textTheme;
return [
timetable.name.text(style: textTheme.titleLarge),
"$year, $semester".text(style: textTheme.titleMedium),
if (timetable.signature.isNotEmpty) timetable.signature.text(style: textTheme.bodyMedium),
"${i18n.startWith} ${ctx.formatYmdText(timetable.startDate)}".text(style: textTheme.bodyMedium),
].column(caa: CrossAxisAlignment.start);
return TimetableInfo(timetable: timetable);
},
);
}
Expand All @@ -374,6 +365,29 @@ class TimetableCard extends StatelessWidget {
}
}

class TimetableInfo extends StatelessWidget {
final SitTimetable timetable;

const TimetableInfo({
super.key,
required this.timetable,
});

@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final year = '${timetable.schoolYear}–${timetable.schoolYear + 1}';
final semester = timetable.semester.l10n();

return [
timetable.name.text(style: textTheme.titleLarge),
"$year, $semester".text(style: textTheme.titleMedium),
if (timetable.signature.isNotEmpty) timetable.signature.text(style: textTheme.bodyMedium),
"${i18n.startWith} ${context.formatYmdText(timetable.startDate)}".text(style: textTheme.bodyMedium),
].column(caa: CrossAxisAlignment.start);
}
}

class TimetableDetailsPage extends ConsumerWidget {
final int id;
final SitTimetable timetable;
Expand Down
39 changes: 26 additions & 13 deletions lib/timetable/page/p13n/palette.dart
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class PaletteCard extends StatelessWidget {
newPalette = newPalette.copyWith(
name: newName,
colors: List.of(newPalette.colors),
);
).markModified();
}
TimetableInit.storage.palette[id] = newPalette;
}
Expand Down Expand Up @@ -244,9 +244,8 @@ class PaletteCard extends StatelessWidget {
final duplicate = palette.copyWith(
name: allocValidFileName(palette.name, all: allPaletteNames),
author: palette.author,
lastModified: DateTime.now(),
colors: List.of(palette.colors),
);
).markModified();
TimetableInit.storage.palette.add(duplicate);
onDuplicate?.call();
},
Expand Down Expand Up @@ -285,21 +284,35 @@ class PaletteCard extends StatelessWidget {
);
},
itemBuilder: (ctx) {
return [
palette.name.text(style: ctx.textTheme.titleLarge),
if (palette.author.isNotEmpty)
palette.author.text(
style: const TextStyle(
fontStyle: FontStyle.italic,
),
),
PaletteColorsPreview(palette.colors),
].column(caa: CrossAxisAlignment.start);
return PaletteInfo(palette: palette);
},
);
}
}

class PaletteInfo extends StatelessWidget {
final TimetablePalette palette;

const PaletteInfo({
super.key,
required this.palette,
});

@override
Widget build(BuildContext context) {
return [
palette.name.text(style: context.textTheme.titleLarge),
if (palette.author.isNotEmpty)
palette.author.text(
style: const TextStyle(
fontStyle: FontStyle.italic,
),
),
PaletteColorsPreview(palette.colors),
].column(caa: CrossAxisAlignment.start);
}
}

class PaletteDetailsPage extends ConsumerWidget {
final int id;
final TimetablePalette palette;
Expand Down
29 changes: 29 additions & 0 deletions lib/timetable/page/patch/patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,32 @@ class _TimetablePatchDraggableState extends State<TimetablePatchDraggable> {
}
}

class ReadonlyTimetablePatchEntryWidget extends StatelessWidget {
final TimetablePatchEntry entry;
final bool enableQrCode;

const ReadonlyTimetablePatchEntryWidget({
super.key,
required this.entry,
this.enableQrCode = true,
});

@override
Widget build(BuildContext context) {
final entry = this.entry;
return switch (entry) {
TimetablePatchSet() => TimetablePatchSetCard(
patchSet: entry,
enableQrCode: enableQrCode,
),
TimetablePatch() => TimetablePatchWidget<TimetablePatch>(
leading: Card.filled(
margin: EdgeInsets.zero,
child: Icon(entry.type.icon).padAll(8),
),
enableQrCode: enableQrCode,
patch: entry,
),
};
}
}
182 changes: 171 additions & 11 deletions lib/timetable/page/patch/qrcode.dart
Original file line number Diff line number Diff line change
@@ -1,30 +1,190 @@
import 'package:flutter/widgets.dart';
import 'package:sit/design/adaptive/dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:rettulf/rettulf.dart';
import 'package:sit/design/adaptive/foundation.dart';
import 'package:sit/design/widgets/card.dart';
import 'package:sit/timetable/entity/timetable.dart';
import 'package:sit/timetable/page/patch/patch.dart';
import 'package:sit/timetable/page/preview.dart';
import 'package:text_scroll/text_scroll.dart';

import '../../i18n.dart';
import '../../entity/patch.dart';
import '../../init.dart';
import '../mine.dart';

Future<void> onTimetablePatchFromQrCode({
required BuildContext context,
required TimetablePatchEntry patch,
}) async {
// await HapticFeedback.mediumImpact();
// if (!context.mounted) return;
// context.push("/timetable/p13n/custom");
context.showSheet((ctx)=>TimetablePatchFromQrCodeSheet());
await context.showSheet((ctx) => TimetablePatchFromQrCodeSheet(patch: patch));
}

class TimetablePatchFromQrCodeSheet extends StatefulWidget {
const TimetablePatchFromQrCodeSheet({super.key});
class TimetablePatchFromQrCodeSheet extends ConsumerStatefulWidget {
final TimetablePatchEntry patch;

const TimetablePatchFromQrCodeSheet({
super.key,
required this.patch,
});

@override
ConsumerState<TimetablePatchFromQrCodeSheet> createState() => _TimetablePatchFromQrCodeSheetState();
}

class _TimetablePatchFromQrCodeSheetState extends ConsumerState<TimetablePatchFromQrCodeSheet> {
@override
Widget build(BuildContext context) {
final storage = TimetableInit.storage.timetable;
final timetables = ref.watch(storage.$rows);
final patch = widget.patch;
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar.medium(
title: patch is TimetablePatchSet
? [
const Icon(Icons.dashboard_customize).padOnly(r: 8),
TextScroll(patch.name).expanded(),
].row()
: i18n.patch.title.text(),
actions: [
PlatformTextButton(
onPressed: timetables.isEmpty
? null
: () async {
final timetable = await context.showSheet<SitTimetable>(
(context) => TimetablePatchUseSheet(patch: patch),
);
if (timetable == null) return;
if (!context.mounted) return;
context.pop();
},
child: i18n.use.text(),
)
],
),
if (patch is TimetablePatchSet)
SliverList.builder(
itemCount: patch.patches.length,
itemBuilder: (ctx, i) {
final p = patch.patches[i];
return ReadonlyTimetablePatchEntryWidget(
entry: p,
enableQrCode: false,
);
},
)
else
SliverList.list(children: [
ReadonlyTimetablePatchEntryWidget(
entry: patch,
enableQrCode: false,
)
]),
],
),
);
}
}

class TimetablePatchUseSheet extends ConsumerStatefulWidget {
final TimetablePatchEntry patch;

const TimetablePatchUseSheet({
super.key,
required this.patch,
});

@override
State<TimetablePatchFromQrCodeSheet> createState() => _TimetablePatchFromQrCodeSheetState();
ConsumerState<TimetablePatchUseSheet> createState() => _TimetablePatchUseSheetState();
}

class _TimetablePatchUseSheetState extends ConsumerState<TimetablePatchUseSheet> {
@override
Widget build(BuildContext context) {
final storage = TimetableInit.storage.timetable;
final timetables = ref.watch(storage.$rows);
assert(timetables.isNotEmpty);
final patch = widget.patch;
timetables.sort((a, b) => b.row.lastModified.compareTo(a.row.lastModified));
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar.medium(
title: i18n.mine.title.text(),
),
SliverList.builder(
itemCount: timetables.length,
itemBuilder: (ctx, i) {
final (:id, row: timetable) = timetables[i];
return TimetablePatchReceiverCard(
id: id,
timetable: timetable,
onAdded: () {
final newTimetable = buildTimetable(timetable, patch).markModified();
storage[id] = newTimetable;
ctx.pop(newTimetable);
},
onPreview: () async {
await previewTimetable(
context,
timetable: buildTimetable(timetable, patch),
);
},
).padH(6);
},
),
],
),
);
}

SitTimetable buildTimetable(SitTimetable timetable, TimetablePatchEntry patch) {
return timetable.copyWith(
patches: List.of(timetable.patches)..add(patch),
);
}
}

class _TimetablePatchFromQrCodeSheetState extends State<TimetablePatchFromQrCodeSheet> {
class TimetablePatchReceiverCard extends StatelessWidget {
final int id;
final SitTimetable timetable;
final VoidCallback? onAdded;
final VoidCallback? onPreview;

const TimetablePatchReceiverCard({
super.key,
required this.id,
required this.timetable,
this.onAdded,
this.onPreview,
});

@override
Widget build(BuildContext context) {
return const Placeholder();
final onAdded = this.onAdded;
final onPreview = this.onPreview;
return [
TimetableInfo(timetable: timetable),
OverflowBar(
children: [
[
if (onAdded != null)
FilledButton(
onPressed: onAdded,
child: i18n.add.text(),
),
if (onPreview != null)
OutlinedButton(
onPressed: onPreview,
child: i18n.preview.text(),
),
].wrap(spacing: 4),
],
),
].column(caa: CrossAxisAlignment.start).padSymmetric(v: 10, h: 15).inOutlinedCard();
}
}
Loading

0 comments on commit a91d2e7

Please sign in to comment.