174 lines
5.4 KiB
Dart
174 lines
5.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'features/app_shell.dart';
|
|
import 'features/devices/devices_page.dart';
|
|
import 'services/adb_service.dart';
|
|
import 'services/artifact_staging_service.dart';
|
|
import 'services/jenkins_artifact_session.dart';
|
|
import 'services/jenkins_client.dart';
|
|
import 'services/token_store.dart';
|
|
import 'theme/app_theme.dart';
|
|
|
|
class AppSokApp extends StatefulWidget {
|
|
const AppSokApp({
|
|
super.key,
|
|
this.tokenStore,
|
|
this.jenkinsClient,
|
|
this.artifactStagingService,
|
|
this.session,
|
|
this.adbDeviceLoader,
|
|
this.adbInstaller,
|
|
this.adbDiagnosticsLoader,
|
|
this.webLoginLauncher,
|
|
this.onWebLoginCompleted,
|
|
this.adbLogcatStarter,
|
|
});
|
|
|
|
final TokenStore? tokenStore;
|
|
final JenkinsClient? jenkinsClient;
|
|
final ArtifactStagingService? artifactStagingService;
|
|
final JenkinsArtifactSession? session;
|
|
final AdbDeviceLoader? adbDeviceLoader;
|
|
final AdbInstaller? adbInstaller;
|
|
final AdbDiagnosticsLoader? adbDiagnosticsLoader;
|
|
final JenkinsWebLoginLauncher? webLoginLauncher;
|
|
final void Function(JenkinsWebLoginResult result)? onWebLoginCompleted;
|
|
final AdbLogcatSessionStarter? adbLogcatStarter;
|
|
|
|
@override
|
|
State<AppSokApp> createState() => _AppSokAppState();
|
|
}
|
|
|
|
class _AppSokAppState extends State<AppSokApp> {
|
|
late final JenkinsArtifactSession _session =
|
|
widget.session ??
|
|
JenkinsArtifactSession(
|
|
store: widget.tokenStore ?? TokenStore(),
|
|
client: widget.jenkinsClient ?? JenkinsClient(),
|
|
stager: widget.artifactStagingService ?? ArtifactStagingService(),
|
|
);
|
|
|
|
late final AdbService _adbService = AdbService();
|
|
|
|
// Mutable so that _onSessionSaved and _retryRestore can trigger re-restore.
|
|
late Future<JenkinsSessionRestoreResult> _startup =
|
|
_session.restoreDetailed();
|
|
|
|
void _onSessionSaved() {
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_startup = _session.restoreDetailed();
|
|
});
|
|
}
|
|
|
|
Future<void> _clearSession() async {
|
|
await _session.clear();
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_startup = Future.value(
|
|
const JenkinsSessionRestoreResult(
|
|
kind: JenkinsSessionRestoreKind.missing,
|
|
),
|
|
);
|
|
});
|
|
}
|
|
|
|
void _retryRestore() {
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_startup = _session.restoreDetailed();
|
|
});
|
|
}
|
|
|
|
Future<bool> _saveToken(
|
|
String baseUrl,
|
|
String username,
|
|
String apiToken,
|
|
) async {
|
|
final store = _session.store;
|
|
final baseUri = Uri.tryParse(baseUrl);
|
|
if (baseUri == null ||
|
|
(baseUri.scheme != 'http' && baseUri.scheme != 'https')) {
|
|
return false;
|
|
}
|
|
try {
|
|
await store.saveSession(
|
|
JenkinsSessionConfig(
|
|
baseUrl: baseUri,
|
|
credentials: JenkinsCredentials(
|
|
username: username,
|
|
apiToken: apiToken,
|
|
),
|
|
),
|
|
);
|
|
final result = await _session.restoreDetailed();
|
|
if (!result.isRestored) {
|
|
await store.clearSession();
|
|
return false;
|
|
}
|
|
return true;
|
|
} catch (_) {
|
|
await store.clearSession();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
JenkinsConnectionStatus? _connectionStatus(JenkinsSessionRestoreResult r) {
|
|
if (r.isRestored) return null;
|
|
return switch (r.kind) {
|
|
JenkinsSessionRestoreKind.reauthRequired =>
|
|
JenkinsConnectionStatus.reauthRequired,
|
|
JenkinsSessionRestoreKind.networkFailure =>
|
|
JenkinsConnectionStatus.networkFailure,
|
|
JenkinsSessionRestoreKind.serverFailure =>
|
|
JenkinsConnectionStatus.serverFailure,
|
|
JenkinsSessionRestoreKind.missing || JenkinsSessionRestoreKind.restored =>
|
|
JenkinsConnectionStatus.missing,
|
|
};
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FutureBuilder<JenkinsSessionRestoreResult>(
|
|
future: _startup,
|
|
builder: (context, snapshot) {
|
|
final result = snapshot.data;
|
|
final isReady = result?.isRestored ?? false;
|
|
final connStatus = result != null ? _connectionStatus(result) : null;
|
|
final canRetry =
|
|
connStatus == JenkinsConnectionStatus.networkFailure ||
|
|
connStatus == JenkinsConnectionStatus.serverFailure;
|
|
|
|
return MaterialApp(
|
|
debugShowCheckedModeBanner: false,
|
|
title: 'AppSok',
|
|
theme: AppTheme.light(),
|
|
home: AppSokShell(
|
|
jobLoader: isReady ? _session.loadJobs : null,
|
|
buildLoader: isReady ? _session.loadBuilds : null,
|
|
artifactDownloader: isReady ? _session.downloadArtifact : null,
|
|
artifactStager: isReady ? _session.stageApk : null,
|
|
artifactCleaner: isReady ? _session.cleanup : null,
|
|
deviceLoader: widget.adbDeviceLoader ?? _adbService.listDevices,
|
|
installer:
|
|
widget.adbInstaller ??
|
|
(device, pending) => _adbService.installApk(
|
|
serial: device.serial,
|
|
apkPath: pending.apkPath,
|
|
),
|
|
adbDiagnosticsLoader:
|
|
widget.adbDiagnosticsLoader ?? _adbService.collectDiagnostics,
|
|
logcatStarter: widget.adbLogcatStarter ?? _adbService.startLogcat,
|
|
webLoginLauncher: widget.webLoginLauncher,
|
|
onWebLoginCompleted: widget.onWebLoginCompleted,
|
|
onSessionSaved: _onSessionSaved,
|
|
tokenSaver: _saveToken,
|
|
sessionClearer: _clearSession,
|
|
connectionStatus: connStatus,
|
|
onRetryConnection: canRetry ? _retryRestore : null,
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|