d115c267f4
Cold launch flow: no server-url -> /server-url. URL set, no token -> /login. Token present -> /home with shell. VersionGate runs once when the URL changes, hits /healthz, blocks if min_client_version > package version. /home is a placeholder until Task 14. Replaces Navigator.pushReplacementNamed in server_url_screen + login_screen with context.go now that go_router owns the routes.
68 lines
2.3 KiB
Dart
68 lines
2.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:package_info_plus/package_info_plus.dart';
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
|
|
import '../../api/client.dart';
|
|
import '../../api/endpoints/health.dart';
|
|
import '../../auth/auth_provider.dart';
|
|
|
|
final _versionCheckProvider = FutureProvider<_VersionResult>((ref) async {
|
|
final url = await ref.watch(serverUrlProvider.future);
|
|
if (url == null) return _VersionResult.skipped;
|
|
final dio = ApiClient.buildDio(baseUrl: url, tokenResolver: () async => null);
|
|
final body = await HealthApi(dio).check();
|
|
final min = body['min_client_version'];
|
|
if (min == null || min.isEmpty) return _VersionResult.skipped;
|
|
final info = await PackageInfo.fromPlatform();
|
|
final mine = Version.parse(info.version);
|
|
final required = Version.parse(min);
|
|
return mine < required ? _VersionResult.tooOld : _VersionResult.ok;
|
|
});
|
|
|
|
enum _VersionResult { ok, tooOld, skipped }
|
|
|
|
class VersionGate extends ConsumerWidget {
|
|
const VersionGate({required this.child, super.key});
|
|
final Widget child;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
return ref.watch(_versionCheckProvider).when(
|
|
data: (r) => r == _VersionResult.tooOld ? const _TooOldScreen() : child,
|
|
error: (_, __) => child, // soft-fail if /healthz is unreachable; let the rest of the flow surface a real error
|
|
loading: () => const Scaffold(body: Center(child: CircularProgressIndicator())),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TooOldScreen extends StatelessWidget {
|
|
const _TooOldScreen();
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const Scaffold(
|
|
body: SafeArea(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(24),
|
|
child: Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
'Update required',
|
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w500),
|
|
),
|
|
SizedBox(height: 12),
|
|
Text(
|
|
'This client is too old for that Minstrel server. Install the latest build to continue.',
|
|
textAlign: TextAlign.center,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|