Team Color, image compression for attendance verification, improved wherebouts

This commit is contained in:
2026-03-08 12:23:28 +08:00
parent a8751ca728
commit d87b5e73d7
11 changed files with 757 additions and 191 deletions
@@ -54,12 +54,14 @@ void callbackDispatcher() {
/// Initialize Workmanager and register periodic background location task.
Future<void> initBackgroundLocationService() async {
if (kIsWeb) return; // Workmanager is not supported on web.
await Workmanager().initialize(callbackDispatcher);
}
/// Register a periodic task to report location every ~15 minutes
/// (Android minimum for periodic Workmanager tasks).
Future<void> startBackgroundLocationUpdates() async {
if (kIsWeb) return; // Workmanager is not supported on web.
await Workmanager().registerPeriodicTask(
_taskName,
_taskName,
@@ -71,5 +73,6 @@ Future<void> startBackgroundLocationUpdates() async {
/// Cancel the periodic background location task.
Future<void> stopBackgroundLocationUpdates() async {
if (kIsWeb) return; // Workmanager is not supported on web.
await Workmanager().cancelByUniqueName(_taskName);
}
+33
View File
@@ -0,0 +1,33 @@
import 'dart:typed_data';
import 'package:flutter_image_compress/flutter_image_compress.dart';
/// Compresses a JPEG image to reduce upload size.
///
/// Target: ≤ 200 KB for verification selfies. Falls back to the original
/// bytes if compression fails so the upload is never blocked.
class ImageCompressService {
ImageCompressService._();
/// Compress [bytes] (JPEG/PNG) down to [quality] (1100).
/// Resizes the longest side to at most [maxDimension] pixels.
static Future<Uint8List> compress(
Uint8List bytes, {
int quality = 70,
int maxDimension = 800,
}) async {
try {
final result = await FlutterImageCompress.compressWithList(
bytes,
minHeight: maxDimension,
minWidth: maxDimension,
quality: quality,
format: CompressFormat.jpeg,
);
return result;
} catch (_) {
// If compression fails on any platform, return original bytes.
return bytes;
}
}
}