feat: complete leave approval MVP

This commit is contained in:
selfrelease
2026-07-18 19:20:07 +08:00
parent 2105fe3bac
commit 090a7e33ce
133 changed files with 7845 additions and 100 deletions
@@ -0,0 +1,53 @@
import 'dart:convert';
import 'package:aioa_mobile/core/auth/authenticated_http_client.dart';
import 'package:aioa_mobile/core/config/runtime_config.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
final pushRegistrationProvider =
AsyncNotifierProvider<PushRegistrationController, bool>(
PushRegistrationController.new,
);
class PushRegistrationController extends AsyncNotifier<bool> {
@override
Future<bool> build() async {
try {
if (Firebase.apps.isEmpty) await Firebase.initializeApp();
final messaging = FirebaseMessaging.instance;
final settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.denied) {
return false;
}
final token = await messaging.getToken();
if (token == null) return false;
await _upload(token);
messaging.onTokenRefresh.listen(_upload);
return true;
} catch (_) {
// 未提供 Firebase 平台配置时保留站内通知,应用仍可正常启动。
return false;
}
}
Future<void> _upload(String token) async {
final id = await ref.read(deviceRegistrationProvider).currentId();
final response = await ref
.read(authenticatedHttpClientProvider)
.put(
Uri.parse('${RuntimeConfig.apiBaseUrl}/devices/$id/push-token'),
headers: const {'Content-Type': 'application/json'},
body: jsonEncode({'token': token}),
);
if (response.statusCode < 200 || response.statusCode >= 300) {
throw http.ClientException('Push token registration failed');
}
}
}