mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-15 08:12:28 -06:00
feat: Add login integration test (WIP), update notes feature
This commit is contained in:
25
lib/core/database/hive/hive_initialization.dart
Normal file
25
lib/core/database/hive/hive_initialization.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
||||
|
||||
Future<void> initHive(Directory directory, String defaultLocale) async {
|
||||
Hive.init(directory.path);
|
||||
registerHiveAdapters();
|
||||
await Hive.openBox<LocalUserAccount>(HiveBoxes.localUserAccount);
|
||||
await Hive.openBox<LocalUserAppState>(HiveBoxes.localUserAppState);
|
||||
await Hive.openBox<bool>(HiveBoxes.hintStateBox);
|
||||
await Hive.openBox<String>(HiveBoxes.hosts);
|
||||
final globalSettingsBox =
|
||||
await Hive.openBox<GlobalSettings>(HiveBoxes.globalSettings);
|
||||
|
||||
if (!globalSettingsBox.hasValue) {
|
||||
await globalSettingsBox.setValue(
|
||||
GlobalSettings(preferredLocaleSubtag: defaultLocale),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class LanguageHeaderInterceptor extends Interceptor {
|
||||
String preferredLocaleSubtag;
|
||||
LanguageHeaderInterceptor(this.preferredLocaleSubtag);
|
||||
final String Function() preferredLocaleSubtagBuilder;
|
||||
LanguageHeaderInterceptor(this.preferredLocaleSubtagBuilder);
|
||||
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
late String languages;
|
||||
if (preferredLocaleSubtag == "en") {
|
||||
if (preferredLocaleSubtagBuilder() == "en") {
|
||||
languages = "en";
|
||||
} else {
|
||||
languages = "$preferredLocaleSubtag,en;q=0.7,en-US;q=0.6";
|
||||
languages = "${preferredLocaleSubtagBuilder()},en;q=0.7,en-US;q=0.6";
|
||||
}
|
||||
options.headers.addAll({"Accept-Language": languages});
|
||||
handler.next(options);
|
||||
|
||||
@@ -1,93 +1,14 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:dio/io.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_api/src/interceptor/dio_http_error_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/dio_offline_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/dio_unauthorized_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/retry_on_connection_change_interceptor.dart';
|
||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
|
||||
|
||||
/// Manages the security context, authentication and base request URL for
|
||||
/// an underlying [Dio] client which is injected into all services
|
||||
/// requiring authenticated access to the Paperless REST API.
|
||||
class SessionManager extends ValueNotifier<Dio> {
|
||||
Dio get client => value;
|
||||
|
||||
SessionManager([List<Interceptor> interceptors = const []])
|
||||
: super(_initDio(interceptors));
|
||||
|
||||
static Dio _initDio(List<Interceptor> interceptors) {
|
||||
//en- and decoded by utf8 by default
|
||||
final Dio dio = Dio(
|
||||
BaseOptions(
|
||||
contentType: Headers.jsonContentType,
|
||||
followRedirects: true,
|
||||
maxRedirects: 10,
|
||||
),
|
||||
);
|
||||
dio.options
|
||||
..receiveTimeout = const Duration(seconds: 30)
|
||||
..sendTimeout = const Duration(seconds: 60)
|
||||
..responseType = ResponseType.json;
|
||||
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient =
|
||||
() => HttpClient()..badCertificateCallback = (cert, host, port) => true;
|
||||
dio.interceptors.addAll([
|
||||
...interceptors,
|
||||
DioUnauthorizedInterceptor(),
|
||||
DioHttpErrorInterceptor(),
|
||||
DioOfflineInterceptor(),
|
||||
RetryOnConnectionChangeInterceptor(dio: dio)
|
||||
]);
|
||||
return dio;
|
||||
}
|
||||
abstract interface class SessionManager implements ChangeNotifier {
|
||||
Dio get client;
|
||||
|
||||
void updateSettings({
|
||||
String? baseUrl,
|
||||
String? authToken,
|
||||
ClientCertificate? clientCertificate,
|
||||
}) {
|
||||
if (clientCertificate != null) {
|
||||
final context = SecurityContext()
|
||||
..usePrivateKeyBytes(
|
||||
clientCertificate.bytes,
|
||||
password: clientCertificate.passphrase,
|
||||
)
|
||||
..useCertificateChainBytes(
|
||||
clientCertificate.bytes,
|
||||
password: clientCertificate.passphrase,
|
||||
)
|
||||
..setTrustedCertificatesBytes(
|
||||
clientCertificate.bytes,
|
||||
password: clientCertificate.passphrase,
|
||||
);
|
||||
final adapter = IOHttpClientAdapter()
|
||||
..createHttpClient = () => HttpClient(context: context)
|
||||
..badCertificateCallback =
|
||||
(X509Certificate cert, String host, int port) => true;
|
||||
|
||||
client.httpClientAdapter = adapter;
|
||||
}
|
||||
|
||||
if (baseUrl != null) {
|
||||
client.options.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
if (authToken != null) {
|
||||
client.options.headers.addAll({
|
||||
HttpHeaders.authorizationHeader: 'Token $authToken',
|
||||
});
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void resetSettings() {
|
||||
client.httpClientAdapter = IOHttpClientAdapter();
|
||||
client.options.baseUrl = '';
|
||||
client.options.headers.remove(HttpHeaders.authorizationHeader);
|
||||
notifyListeners();
|
||||
}
|
||||
});
|
||||
void resetSettings();
|
||||
}
|
||||
|
||||
96
lib/core/security/session_manager_impl.dart
Normal file
96
lib/core/security/session_manager_impl.dart
Normal file
@@ -0,0 +1,96 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:dio/io.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/dio_offline_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/dio_unauthorized_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/retry_on_connection_change_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/security/session_manager.dart';
|
||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||
|
||||
/// Manages the security context, authentication and base request URL for
|
||||
/// an underlying [Dio] client which is injected into all services
|
||||
/// requiring authenticated access to the Paperless REST API.
|
||||
class SessionManagerImpl extends ValueNotifier<Dio> implements SessionManager {
|
||||
@override
|
||||
Dio get client => value;
|
||||
|
||||
SessionManagerImpl([List<Interceptor> interceptors = const []])
|
||||
: super(_initDio(interceptors));
|
||||
|
||||
static Dio _initDio(List<Interceptor> interceptors) {
|
||||
//en- and decoded by utf8 by default
|
||||
final Dio dio = Dio(
|
||||
BaseOptions(
|
||||
contentType: Headers.jsonContentType,
|
||||
followRedirects: true,
|
||||
maxRedirects: 10,
|
||||
),
|
||||
);
|
||||
dio.options
|
||||
..receiveTimeout = const Duration(seconds: 30)
|
||||
..sendTimeout = const Duration(seconds: 60)
|
||||
..responseType = ResponseType.json;
|
||||
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient =
|
||||
() => HttpClient()..badCertificateCallback = (cert, host, port) => true;
|
||||
dio.interceptors.addAll([
|
||||
...interceptors,
|
||||
DioUnauthorizedInterceptor(),
|
||||
DioHttpErrorInterceptor(),
|
||||
DioOfflineInterceptor(),
|
||||
RetryOnConnectionChangeInterceptor(dio: dio)
|
||||
]);
|
||||
return dio;
|
||||
}
|
||||
|
||||
@override
|
||||
void updateSettings({
|
||||
String? baseUrl,
|
||||
String? authToken,
|
||||
ClientCertificate? clientCertificate,
|
||||
}) {
|
||||
if (clientCertificate != null) {
|
||||
final context = SecurityContext()
|
||||
..usePrivateKeyBytes(
|
||||
clientCertificate.bytes,
|
||||
password: clientCertificate.passphrase,
|
||||
)
|
||||
..useCertificateChainBytes(
|
||||
clientCertificate.bytes,
|
||||
password: clientCertificate.passphrase,
|
||||
)
|
||||
..setTrustedCertificatesBytes(
|
||||
clientCertificate.bytes,
|
||||
password: clientCertificate.passphrase,
|
||||
);
|
||||
final adapter = IOHttpClientAdapter()
|
||||
..createHttpClient = () => HttpClient(context: context)
|
||||
..badCertificateCallback =
|
||||
(X509Certificate cert, String host, int port) => true;
|
||||
|
||||
client.httpClientAdapter = adapter;
|
||||
}
|
||||
|
||||
if (baseUrl != null) {
|
||||
client.options.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
if (authToken != null) {
|
||||
client.options.headers.addAll({
|
||||
HttpHeaders.authorizationHeader: 'Token $authToken',
|
||||
});
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@override
|
||||
void resetSettings() {
|
||||
client.httpClientAdapter = IOHttpClientAdapter();
|
||||
client.options.baseUrl = '';
|
||||
client.options.headers.remove(HttpHeaders.authorizationHeader);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:paperless_mobile/core/global/os_error_codes.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/server_reachability_error_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/security/session_manager.dart';
|
||||
import 'package:paperless_mobile/core/security/session_manager_impl.dart';
|
||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||
import 'package:paperless_mobile/features/login/model/reachability_status.dart';
|
||||
import 'package:rxdart/subjects.dart';
|
||||
@@ -79,7 +80,7 @@ class ConnectivityStatusServiceImpl implements ConnectivityStatusService {
|
||||
}
|
||||
try {
|
||||
SessionManager manager =
|
||||
SessionManager([ServerReachabilityErrorInterceptor()])
|
||||
SessionManagerImpl([ServerReachabilityErrorInterceptor()])
|
||||
..updateSettings(clientCertificate: clientCertificate)
|
||||
..client.options.connectTimeout = const Duration(seconds: 5)
|
||||
..client.options.receiveTimeout = const Duration(seconds: 5);
|
||||
|
||||
@@ -92,6 +92,8 @@ class _DocumentNotesWidgetState extends State<DocumentNotesWidget> {
|
||||
label: Text(S.of(context)!.addNote),
|
||||
onPressed: () async {
|
||||
_formKey.currentState?.save();
|
||||
FocusScope.of(context).unfocus();
|
||||
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
setState(() {
|
||||
_isNoteSubmitting = true;
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/bloc/transient_error.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_extensions.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||
@@ -13,6 +14,7 @@ import 'package:paperless_mobile/core/database/tables/local_user_settings.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/user_credentials.dart';
|
||||
import 'package:paperless_mobile/core/factory/paperless_api_factory.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart';
|
||||
import 'package:paperless_mobile/core/security/session_manager_impl.dart';
|
||||
import 'package:paperless_mobile/features/logging/data/logger.dart';
|
||||
import 'package:paperless_mobile/features/logging/utils/redaction_utils.dart';
|
||||
import 'package:paperless_mobile/core/model/info_message_exception.dart';
|
||||
@@ -83,7 +85,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
AuthenticatingStage.persistingLocalUserData));
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
} on PaperlessApiException catch (exception, stackTrace) {
|
||||
emit(
|
||||
AuthenticationErrorState(
|
||||
serverUrl: serverUrl,
|
||||
@@ -207,8 +209,8 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
methodName: 'switchAccount',
|
||||
);
|
||||
|
||||
final sessionManager = SessionManager([
|
||||
LanguageHeaderInterceptor(locale),
|
||||
final SessionManager sessionManager = SessionManagerImpl([
|
||||
LanguageHeaderInterceptor(() => locale),
|
||||
]);
|
||||
await _addUser(
|
||||
localUserId,
|
||||
@@ -462,14 +464,12 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
|
||||
final authApi = _apiFactory.createAuthenticationApi(sessionManager.client);
|
||||
|
||||
await onPerformLogin?.call();
|
||||
logger.fd(
|
||||
"Fetching bearer token from the server...",
|
||||
className: runtimeType.toString(),
|
||||
methodName: '_addUser',
|
||||
);
|
||||
|
||||
await onPerformLogin?.call();
|
||||
|
||||
final token = await authApi.login(
|
||||
username: credentials.username!,
|
||||
password: credentials.password!,
|
||||
@@ -486,7 +486,6 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
clientCertificate: clientCert,
|
||||
authToken: token,
|
||||
);
|
||||
|
||||
final userAccountBox =
|
||||
Hive.box<LocalUserAccount>(HiveBoxes.localUserAccount);
|
||||
final userStateBox =
|
||||
@@ -586,12 +585,14 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
clientCertificate: clientCert,
|
||||
),
|
||||
);
|
||||
|
||||
logger.fd(
|
||||
"User credentials successfully saved.",
|
||||
className: runtimeType.toString(),
|
||||
methodName: '_addUser',
|
||||
);
|
||||
});
|
||||
|
||||
final hostsBox = Hive.box<String>(HiveBoxes.hosts);
|
||||
if (!hostsBox.values.contains(serverUrl)) {
|
||||
await hostsBox.add(serverUrl);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
@@ -17,7 +16,6 @@ import 'package:paperless_mobile/features/login/model/client_certificate_form_mo
|
||||
import 'package:paperless_mobile/features/login/model/login_form_credentials.dart';
|
||||
import 'package:paperless_mobile/features/login/model/reachability_status.dart';
|
||||
import 'package:paperless_mobile/features/login/view/widgets/form_fields/client_certificate_form_field.dart';
|
||||
import 'package:paperless_mobile/features/login/view/widgets/form_fields/login_settings_page.dart';
|
||||
import 'package:paperless_mobile/features/login/view/widgets/form_fields/server_address_form_field.dart';
|
||||
import 'package:paperless_mobile/features/login/view/widgets/form_fields/user_credentials_form_field.dart';
|
||||
import 'package:paperless_mobile/generated/assets.gen.dart';
|
||||
@@ -44,6 +42,7 @@ class AddAccountPage extends StatefulWidget {
|
||||
final bool showLocalAccounts;
|
||||
|
||||
final Widget? bottomLeftButton;
|
||||
|
||||
const AddAccountPage({
|
||||
Key? key,
|
||||
required this.onSubmit,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:hive_flutter/adapters.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
import 'package:paperless_mobile/keys.dart';
|
||||
|
||||
class ServerAddressFormField extends StatefulWidget {
|
||||
static const String fkServerAddress = "serverAddress";
|
||||
@@ -59,7 +60,7 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField>
|
||||
maxWidth: MediaQuery.sizeOf(context).width - 40,
|
||||
);
|
||||
},
|
||||
key: const ValueKey('login-server-address'),
|
||||
key: TestKeys.login.serverAddressFormField,
|
||||
optionsBuilder: (textEditingValue) {
|
||||
return Hive.box<String>(HiveBoxes.hosts)
|
||||
.values
|
||||
|
||||
19
lib/keys.dart
Normal file
19
lib/keys.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class TestKeys {
|
||||
TestKeys._();
|
||||
|
||||
static final login = _LoginTestKeys();
|
||||
}
|
||||
|
||||
class _LoginTestKeys {
|
||||
final serverAddressFormField = const Key('login-server-address');
|
||||
final continueButton = const Key('login-continue-button');
|
||||
final usernameFormField = const Key('login-username');
|
||||
final passwordFormField = const Key('login-password');
|
||||
final loginButton = const Key('login-login-button');
|
||||
final clientCertificateFormField = const Key('login-client-certificate');
|
||||
final clientCertificatePassphraseFormField =
|
||||
const Key('login-client-certificate-passphrase');
|
||||
final loggingInScreen = const Key('login-logging-in-screen');
|
||||
}
|
||||
172
lib/main.dart
172
lib/main.dart
@@ -24,6 +24,8 @@ import 'package:paperless_mobile/constants.dart';
|
||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||
import 'package:paperless_mobile/core/bloc/my_bloc_observer.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_extensions.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_initialization.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
||||
@@ -31,7 +33,7 @@ import 'package:paperless_mobile/core/exception/server_message_exception.dart';
|
||||
import 'package:paperless_mobile/core/factory/paperless_api_factory.dart';
|
||||
import 'package:paperless_mobile/core/factory/paperless_api_factory_impl.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart';
|
||||
import 'package:paperless_mobile/core/notifier/go_router_refresh_stream.dart';
|
||||
import 'package:paperless_mobile/core/security/session_manager_impl.dart';
|
||||
import 'package:paperless_mobile/features/logging/data/formatted_printer.dart';
|
||||
import 'package:paperless_mobile/features/logging/data/logger.dart';
|
||||
import 'package:paperless_mobile/features/logging/data/mirrored_file_output.dart';
|
||||
@@ -105,65 +107,36 @@ Future<void> performMigrations() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initHive() async {
|
||||
await Hive.initFlutter();
|
||||
await performMigrations();
|
||||
registerHiveAdapters();
|
||||
await Hive.openBox<LocalUserAccount>(HiveBoxes.localUserAccount);
|
||||
await Hive.openBox<LocalUserAppState>(HiveBoxes.localUserAppState);
|
||||
await Hive.openBox<bool>(HiveBoxes.hintStateBox);
|
||||
await Hive.openBox<String>(HiveBoxes.hosts);
|
||||
final globalSettingsBox =
|
||||
await Hive.openBox<GlobalSettings>(HiveBoxes.globalSettings);
|
||||
Future<void> initializeDefaultParameters() async {
|
||||
Bloc.observer = MyBlocObserver();
|
||||
await FileService.instance.initialize();
|
||||
logger = l.Logger(
|
||||
output: MirroredFileOutput(),
|
||||
printer: FormattedPrinter(),
|
||||
level: l.Level.trace,
|
||||
filter: l.ProductionFilter(),
|
||||
);
|
||||
|
||||
if (!globalSettingsBox.hasValue) {
|
||||
await globalSettingsBox.setValue(
|
||||
GlobalSettings(preferredLocaleSubtag: defaultPreferredLocale.toString()),
|
||||
);
|
||||
packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
}
|
||||
if (Platform.isIOS) {
|
||||
iosInfo = await DeviceInfoPlugin().iosInfo;
|
||||
}
|
||||
|
||||
await findSystemLocale();
|
||||
}
|
||||
|
||||
void main() async {
|
||||
runZonedGuarded(() async {
|
||||
Bloc.observer = MyBlocObserver();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await FileService.instance.initialize();
|
||||
|
||||
logger = l.Logger(
|
||||
output: MirroredFileOutput(),
|
||||
printer: FormattedPrinter(),
|
||||
level: l.Level.trace,
|
||||
filter: l.ProductionFilter(),
|
||||
);
|
||||
Paint.enableDithering = true;
|
||||
|
||||
// if (kDebugMode) {
|
||||
// // URL: http://localhost:3131
|
||||
// // Login: admin:test
|
||||
// await LocalMockApiServer(
|
||||
// // RandomDelayGenerator(
|
||||
// // const Duration(milliseconds: 100),
|
||||
// // const Duration(milliseconds: 800),
|
||||
// // ),
|
||||
// )
|
||||
// .start();
|
||||
// }
|
||||
|
||||
packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
}
|
||||
if (Platform.isIOS) {
|
||||
iosInfo = await DeviceInfoPlugin().iosInfo;
|
||||
}
|
||||
await _initHive();
|
||||
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||
final globalSettingsBox =
|
||||
Hive.box<GlobalSettings>(HiveBoxes.globalSettings);
|
||||
final globalSettings = globalSettingsBox.getValue()!;
|
||||
|
||||
await findSystemLocale();
|
||||
final hiveDirectory = await getApplicationDocumentsDirectory();
|
||||
final defaultLocale = defaultPreferredLocale.languageCode;
|
||||
await initializeDefaultParameters();
|
||||
await initHive(hiveDirectory, defaultLocale);
|
||||
await performMigrations();
|
||||
|
||||
final connectivityStatusService = ConnectivityStatusServiceImpl(
|
||||
Connectivity(),
|
||||
@@ -179,10 +152,10 @@ void main() async {
|
||||
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||
|
||||
final languageHeaderInterceptor = LanguageHeaderInterceptor(
|
||||
globalSettings.preferredLocaleSubtag,
|
||||
() => Hive.globalSettingsBox.getValue()!.preferredLocaleSubtag,
|
||||
);
|
||||
// Manages security context, required for self signed client certificates
|
||||
final sessionManager = SessionManager([
|
||||
final SessionManager sessionManager = SessionManagerImpl([
|
||||
PrettyDioLogger(
|
||||
compact: true,
|
||||
responseBody: false,
|
||||
@@ -195,21 +168,9 @@ void main() async {
|
||||
languageHeaderInterceptor,
|
||||
]);
|
||||
|
||||
// Initialize Blocs/Cubits
|
||||
final connectivityCubit = ConnectivityCubit(connectivityStatusService);
|
||||
|
||||
// Load application settings and stored authentication data
|
||||
await connectivityCubit.initialize();
|
||||
|
||||
final localNotificationService = LocalNotificationService();
|
||||
await localNotificationService.initialize();
|
||||
|
||||
//Update language header in interceptor on language change.
|
||||
globalSettingsBox.listenable().addListener(() {
|
||||
languageHeaderInterceptor.preferredLocaleSubtag =
|
||||
globalSettings.preferredLocaleSubtag;
|
||||
});
|
||||
|
||||
final apiFactory = PaperlessApiFactoryImpl(sessionManager);
|
||||
final authenticationCubit = AuthenticationCubit(
|
||||
localAuthService,
|
||||
@@ -219,33 +180,19 @@ void main() async {
|
||||
localNotificationService,
|
||||
);
|
||||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider.value(value: sessionManager),
|
||||
Provider<LocalAuthenticationService>.value(value: localAuthService),
|
||||
Provider<ConnectivityStatusService>.value(
|
||||
value: connectivityStatusService),
|
||||
Provider<LocalNotificationService>.value(
|
||||
value: localNotificationService),
|
||||
Provider.value(value: DocumentChangedNotifier()),
|
||||
],
|
||||
child: MultiProvider(
|
||||
providers: [
|
||||
Provider<ConnectivityCubit>.value(value: connectivityCubit),
|
||||
Provider.value(value: authenticationCubit),
|
||||
],
|
||||
child: GoRouterShell(
|
||||
apiFactory: apiFactory,
|
||||
),
|
||||
),
|
||||
AppEntrypoint(
|
||||
sessionManager: sessionManager,
|
||||
apiFactory: apiFactory,
|
||||
authenticationCubit: authenticationCubit,
|
||||
connectivityStatusService: connectivityStatusService,
|
||||
localNotificationService: localNotificationService,
|
||||
localAuthService: localAuthService,
|
||||
),
|
||||
);
|
||||
}, (error, stackTrace) {
|
||||
if (error is StateError &&
|
||||
error.message.contains("Cannot emit new states")) {
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Catches all unexpected/uncaught errors and prints them to the console.
|
||||
final message = switch (error) {
|
||||
@@ -262,9 +209,52 @@ void main() async {
|
||||
});
|
||||
}
|
||||
|
||||
class AppEntrypoint extends StatelessWidget {
|
||||
final PaperlessApiFactory apiFactory;
|
||||
final AuthenticationCubit authenticationCubit;
|
||||
final ConnectivityStatusService connectivityStatusService;
|
||||
final LocalNotificationService localNotificationService;
|
||||
final LocalAuthenticationService localAuthService;
|
||||
final SessionManager sessionManager;
|
||||
|
||||
const AppEntrypoint({
|
||||
super.key,
|
||||
required this.apiFactory,
|
||||
required this.authenticationCubit,
|
||||
required this.connectivityStatusService,
|
||||
required this.localNotificationService,
|
||||
required this.localAuthService,
|
||||
required this.sessionManager,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
Provider.value(value: DocumentChangedNotifier()),
|
||||
Provider.value(value: authenticationCubit),
|
||||
Provider.value(
|
||||
value: ConnectivityCubit(connectivityStatusService)..initialize(),
|
||||
),
|
||||
ChangeNotifierProvider.value(value: sessionManager),
|
||||
Provider.value(value: connectivityStatusService),
|
||||
Provider.value(value: localNotificationService),
|
||||
Provider.value(value: localAuthService),
|
||||
],
|
||||
child: GoRouterShell(
|
||||
apiFactory: apiFactory,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GoRouterShell extends StatefulWidget {
|
||||
final PaperlessApiFactory apiFactory;
|
||||
const GoRouterShell({super.key, required this.apiFactory});
|
||||
|
||||
const GoRouterShell({
|
||||
super.key,
|
||||
required this.apiFactory,
|
||||
});
|
||||
|
||||
@override
|
||||
State<GoRouterShell> createState() => _GoRouterShellState();
|
||||
@@ -397,7 +387,7 @@ class _GoRouterShellState extends State<GoRouterShell> {
|
||||
dynamicScheme: darkDynamic,
|
||||
preferredColorScheme: settings.preferredColorSchemeOption,
|
||||
),
|
||||
themeMode: settings.preferredThemeMode,
|
||||
themeMode: settings.preferredThemeMode,
|
||||
supportedLocales: const [
|
||||
Locale('en'),
|
||||
Locale('de'),
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:paperless_mobile/features/login/view/login_to_existing_account_p
|
||||
import 'package:paperless_mobile/features/login/view/verify_identity_page.dart';
|
||||
import 'package:paperless_mobile/features/login/view/widgets/login_transition_page.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
import 'package:paperless_mobile/keys.dart';
|
||||
import 'package:paperless_mobile/routing/navigation_keys.dart';
|
||||
import 'package:paperless_mobile/routing/routes.dart';
|
||||
part 'login_route.g.dart';
|
||||
@@ -108,6 +109,7 @@ class AuthenticatingRoute extends GoRouteData {
|
||||
};
|
||||
return NoTransitionPage(
|
||||
child: LoginTransitionPage(
|
||||
key: TestKeys.login.loggingInScreen,
|
||||
text: text,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -82,14 +82,14 @@ SystemUiOverlayStyle buildOverlayStyle(
|
||||
Brightness.light => SystemUiOverlayStyle.dark.copyWith(
|
||||
systemNavigationBarColor: color,
|
||||
systemNavigationBarDividerColor: color,
|
||||
// statusBarColor: theme.colorScheme.background,
|
||||
statusBarColor: theme.colorScheme.background,
|
||||
// statusBarColor: theme.colorScheme.background,
|
||||
// systemNavigationBarDividerColor: theme.colorScheme.surface,
|
||||
),
|
||||
Brightness.dark => SystemUiOverlayStyle.light.copyWith(
|
||||
systemNavigationBarColor: color,
|
||||
systemNavigationBarDividerColor: color,
|
||||
// statusBarColor: theme.colorScheme.background,
|
||||
statusBarColor: theme.colorScheme.background,
|
||||
// statusBarColor: theme.colorScheme.background,
|
||||
// systemNavigationBarDividerColor: theme.colorScheme.surface,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user