feat: Restructure providers and repositories (WIP, not compiling)

This commit is contained in:
Anton Stubenbord
2023-04-30 20:49:36 +02:00
parent 4e87a196f9
commit 88085b5662
14 changed files with 776 additions and 269 deletions

View File

@@ -14,15 +14,15 @@ class LocalUserAccount extends HiveObject {
final String id; final String id;
@HiveField(4) @HiveField(4)
LocalUserSettings settings; final LocalUserSettings settings;
@HiveField(5) @HiveField(6)
UserModel paperlessUser; final int paperlessUserId;
LocalUserAccount({ LocalUserAccount({
required this.id, required this.id,
required this.serverUrl, required this.serverUrl,
required this.settings, required this.settings,
required this.paperlessUser, required this.paperlessUserId,
}); });
} }

View File

@@ -0,0 +1,10 @@
import 'package:dio/dio.dart';
import 'package:paperless_api/paperless_api.dart';
abstract class PaperlessApiFactory {
PaperlessDocumentsApi createDocumentsApi(Dio dio, {required int apiVersion});
PaperlessSavedViewsApi createSavedViewsApi(Dio dio, {required int apiVersion});
PaperlessLabelsApi createLabelsApi(Dio dio, {required int apiVersion});
PaperlessServerStatsApi createServerStatsApi(Dio dio, {required int apiVersion});
PaperlessTasksApi createTasksApi(Dio dio, {required int apiVersion});
}

View File

@@ -0,0 +1,35 @@
import 'package:dio/dio.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/factory/paperless_api_factory.dart';
import 'package:paperless_mobile/core/security/session_manager.dart';
class PaperlessApiFactoryImpl implements PaperlessApiFactory {
final SessionManager sessionManager;
PaperlessApiFactoryImpl(this.sessionManager);
@override
PaperlessDocumentsApi createDocumentsApi(Dio dio, {required int apiVersion}) {
return PaperlessDocumentsApiImpl(dio);
}
@override
PaperlessLabelsApi createLabelsApi(Dio dio, {required int apiVersion}) {
return PaperlessLabelApiImpl(dio);
}
@override
PaperlessSavedViewsApi createSavedViewsApi(Dio dio, {required int apiVersion}) {
return PaperlessSavedViewsApiImpl(dio);
}
@override
PaperlessServerStatsApi createServerStatsApi(Dio dio, {required int apiVersion}) {
return PaperlessServerStatsApiImpl(dio);
}
@override
PaperlessTasksApi createTasksApi(Dio dio, {required int apiVersion}) {
return PaperlessTasksApiImpl(dio);
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/saved_view_repository_state.dart'; import 'package:paperless_mobile/core/repository/saved_view_repository_state.dart';
@@ -25,6 +26,10 @@ class SavedViewRepository extends HydratedCubit<SavedViewRepositoryState> {
SavedViewRepository(this._api) : super(const SavedViewRepositoryState()); SavedViewRepository(this._api) : super(const SavedViewRepositoryState());
Future<void> initialize() {
return findAll();
}
Future<SavedView> create(SavedView object) async { Future<SavedView> create(SavedView object) async {
final created = await _api.save(object); final created = await _api.save(object);
final updatedState = {...state.savedViews}..putIfAbsent(created.id!, () => created); final updatedState = {...state.savedViews}..putIfAbsent(created.id!, () => created);

View File

@@ -2,7 +2,7 @@ import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:dio/io.dart'; import 'package:dio/io.dart';
import 'package:paperless_api/paperless_api.dart'; import 'package:flutter/material.dart';
import 'package:paperless_mobile/core/interceptor/retry_on_connection_change_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:paperless_mobile/features/login/model/client_certificate.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart';
@@ -10,15 +10,10 @@ import 'package:pretty_dio_logger/pretty_dio_logger.dart';
/// Manages the security context, authentication and base request URL for /// Manages the security context, authentication and base request URL for
/// an underlying [Dio] client which is injected into all services /// an underlying [Dio] client which is injected into all services
/// requiring authenticated access to the Paperless HTTP API. /// requiring authenticated access to the Paperless HTTP API.
class SessionManager { class SessionManager extends ValueNotifier<Dio> {
final Dio _client; Dio get client => value;
PaperlessServerInformationModel _serverInformation;
Dio get client => _client; SessionManager([List<Interceptor> interceptors = const []]) : super(_initDio(interceptors));
SessionManager([List<Interceptor> interceptors = const []])
: _client = _initDio(interceptors),
_serverInformation = PaperlessServerInformationModel();
static Dio _initDio(List<Interceptor> interceptors) { static Dio _initDio(List<Interceptor> interceptors) {
//en- and decoded by utf8 by default //en- and decoded by utf8 by default
@@ -48,7 +43,6 @@ class SessionManager {
String? baseUrl, String? baseUrl,
String? authToken, String? authToken,
ClientCertificate? clientCertificate, ClientCertificate? clientCertificate,
PaperlessServerInformationModel? serverInformation,
}) { }) {
if (clientCertificate != null) { if (clientCertificate != null) {
final context = SecurityContext() final context = SecurityContext()
@@ -81,15 +75,13 @@ class SessionManager {
}); });
} }
if (serverInformation != null) { notifyListeners();
_serverInformation = serverInformation;
}
} }
void resetSettings() { void resetSettings() {
client.httpClientAdapter = IOHttpClientAdapter(); client.httpClientAdapter = IOHttpClientAdapter();
client.options.baseUrl = ''; client.options.baseUrl = '';
client.options.headers.remove(HttpHeaders.authorizationHeader); client.options.headers.remove(HttpHeaders.authorizationHeader);
_serverInformation = PaperlessServerInformationModel(); notifyListeners();
} }
} }

View File

@@ -52,35 +52,12 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> with WidgetsBindingObserver { class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
int _currentIndex = 0; int _currentIndex = 0;
final DocumentScannerCubit _scannerCubit = DocumentScannerCubit();
late final DocumentsCubit _documentsCubit;
late final InboxCubit _inboxCubit;
late final SavedViewCubit _savedViewCubit;
late Timer _inboxTimer; late Timer _inboxTimer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
_initializeData(context);
final userId =
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser;
_documentsCubit = DocumentsCubit(
context.read(),
context.read(),
context.read(),
Hive.box<LocalUserAppState>(HiveBoxes.localUserAppState).get(userId)!,
)..reload();
_savedViewCubit = SavedViewCubit(
context.read(),
context.read(),
)..reload();
_inboxCubit = InboxCubit(
context.read(),
context.read(),
context.read(),
context.read(),
);
_listenToInboxChanges(); _listenToInboxChanges();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_listenForReceivedFiles(); _listenForReceivedFiles();
@@ -97,7 +74,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
if (!mounted) { if (!mounted) {
timer.cancel(); timer.cancel();
} else { } else {
_inboxCubit.refreshItemsInInboxCount(); context.read<InboxCubit>().refreshItemsInInboxCount();
} }
}); });
} }
@@ -127,9 +104,6 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
void dispose() { void dispose() {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
_inboxTimer.cancel(); _inboxTimer.cancel();
_inboxCubit.close();
_documentsCubit.close();
_savedViewCubit.close();
super.dispose(); super.dispose();
} }
@@ -247,7 +221,6 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
), ),
label: S.of(context)!.inbox, label: S.of(context)!.inbox,
badgeBuilder: (icon) => BlocBuilder<InboxCubit, InboxState>( badgeBuilder: (icon) => BlocBuilder<InboxCubit, InboxState>(
bloc: _inboxCubit,
builder: (context, state) { builder: (context, state) {
if (state.itemsInInboxCount > 0) { if (state.itemsInInboxCount > 0) {
return Badge.count( return Badge.count(
@@ -261,31 +234,10 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
), ),
]; ];
final routes = <Widget>[ final routes = <Widget>[
MultiBlocProvider( const DocumentsPage(),
// key: ValueKey(userId), const ScannerPage(),
providers: [ const LabelsPage(),
BlocProvider.value(value: _documentsCubit), const InboxPage(),
BlocProvider.value(value: _savedViewCubit),
],
child: const DocumentsPage(),
),
BlocProvider.value(
value: _scannerCubit,
child: const ScannerPage(),
),
MultiBlocProvider(
// key: ValueKey(userId),
providers: [
BlocProvider(
create: (context) => LabelCubit(context.read()),
)
],
child: const LabelsPage(),
),
BlocProvider<InboxCubit>.value(
value: _inboxCubit,
child: const InboxPage(),
),
]; ];
return MultiBlocListener( return MultiBlocListener(

View File

@@ -1,29 +1,139 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/bloc/server_information_cubit.dart'; import 'package:paperless_mobile/core/bloc/server_information_cubit.dart';
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
import 'package:paperless_mobile/core/factory/paperless_api_factory.dart';
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
import 'package:paperless_mobile/core/security/session_manager.dart';
import 'package:paperless_mobile/core/service/dio_file_service.dart';
import 'package:paperless_mobile/features/document_scan/cubit/document_scanner_cubit.dart';
import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
import 'package:paperless_mobile/features/home/view/home_page.dart'; import 'package:paperless_mobile/features/home/view/home_page.dart';
import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart';
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart'; import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
import 'package:provider/provider.dart';
class HomeRoute extends StatelessWidget { class HomeRoute extends StatelessWidget {
const HomeRoute({super.key}); final String localUserId;
final int paperlessApiVersion;
final PaperlessApiFactory paperlessProviderFactory;
const HomeRoute({
super.key,
required this.paperlessApiVersion,
required this.paperlessProviderFactory,
required this.localUserId,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return GlobalSettingsBuilder(
providers: [ builder: (context, settings) {
BlocProvider( final currentLocalUserId = settings.currentLoggedInUser!;
create: (context) => TaskStatusCubit( return MultiProvider(
context.read(), providers: [
), Provider<CacheManager>(
), create: (context) => CacheManager(
BlocProvider<ServerInformationCubit>( Config(
create: (context) => ServerInformationCubit( localUserId,
context.read(), fileService: DioFileService(context.read<SessionManager>().client),
)..updateInformation(), ),
), ),
], ),
child: HomePage(), ProxyProvider<SessionManager, PaperlessDocumentsApi>(
update: (context, value, previous) => paperlessProviderFactory.createDocumentsApi(
value.client,
apiVersion: paperlessApiVersion,
),
),
ProxyProvider<SessionManager, PaperlessLabelsApi>(
update: (context, value, previous) => paperlessProviderFactory.createLabelsApi(
value.client,
apiVersion: paperlessApiVersion,
),
),
ProxyProvider<SessionManager, PaperlessSavedViewsApi>(
update: (context, value, previous) => paperlessProviderFactory.createSavedViewsApi(
value.client,
apiVersion: paperlessApiVersion,
),
),
ProxyProvider<SessionManager, PaperlessServerStatsApi>(
update: (context, value, previous) => paperlessProviderFactory.createServerStatsApi(
value.client,
apiVersion: paperlessApiVersion,
),
),
ProxyProvider<SessionManager, PaperlessTasksApi>(
update: (context, value, previous) => paperlessProviderFactory.createTasksApi(
value.client,
apiVersion: paperlessApiVersion,
),
),
],
builder: (context, child) {
return MultiProvider(
providers: [
ProxyProvider<PaperlessLabelsApi, LabelRepository>(
update: (context, value, previous) => LabelRepository(value)..initialize(),
),
ProxyProvider<PaperlessSavedViewsApi, SavedViewRepository>(
update: (context, value, previous) => SavedViewRepository(value)..initialize(),
),
],
builder: (context, child) {
return MultiBlocProvider(
providers: [
ProxyProvider3<PaperlessDocumentsApi, DocumentChangedNotifier, LabelRepository,
DocumentsCubit>(
update: (context, docApi, notifier, labelRepo, previous) => DocumentsCubit(
docApi,
notifier,
labelRepo,
Hive.box<LocalUserAppState>(HiveBoxes.localUserAppState)
.get(currentLocalUserId)!,
)..reload(),
),
Provider(create: (context) => DocumentScannerCubit()),
ProxyProvider4<PaperlessDocumentsApi, PaperlessServerStatsApi, LabelRepository,
DocumentChangedNotifier, InboxCubit>(
update: (context, docApi, statsApi, labelRepo, notifier, previous) =>
InboxCubit(
docApi,
statsApi,
labelRepo,
notifier,
)..initialize(),
),
ProxyProvider2<SavedViewRepository, LabelRepository, SavedViewCubit>(
update: (context, savedViewRepo, labelRepo, previous) => SavedViewCubit(
savedViewRepo,
labelRepo,
)..initialize(),
),
ProxyProvider<PaperlessServerStatsApi, ServerInformationCubit>(
update: (context, value, previous) => ServerInformationCubit(value),
),
ProxyProvider<LabelRepository, LabelCubit>(
update: (context, value, previous) => LabelCubit(value),
),
],
child: const HomePage(),
);
},
);
},
);
},
); );
} }
} }

View File

@@ -52,16 +52,18 @@ class InboxCubit extends HydratedCubit<InboxState> with DocumentPagingBlocMixin
emit(state.copyWith(labels: labels)); emit(state.copyWith(labels: labels));
}, },
); );
refreshItemsInInboxCount(false);
loadInbox();
} }
void refreshItemsInInboxCount([bool shouldLoadInbox = true]) async { Future<void> initialize() async {
await refreshItemsInInboxCount(false);
await loadInbox();
}
Future<void> refreshItemsInInboxCount([bool shouldLoadInbox = true]) async {
final stats = await _statsApi.getServerStatistics(); final stats = await _statsApi.getServerStatistics();
if (stats.documentsInInbox != state.itemsInInboxCount && shouldLoadInbox) { if (stats.documentsInInbox != state.itemsInInboxCount && shouldLoadInbox) {
loadInbox(); await loadInbox();
} }
emit( emit(
state.copyWith( state.copyWith(

View File

@@ -3,13 +3,12 @@ import 'dart:typed_data';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive_flutter/adapters.dart'; import 'package:hive_flutter/adapters.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
import 'package:paperless_mobile/core/security/session_manager.dart'; import 'package:paperless_mobile/core/security/session_manager.dart';
import 'package:paperless_mobile/features/login/model/client_certificate.dart'; import 'package:paperless_mobile/features/login/model/client_certificate.dart';
import 'package:paperless_mobile/features/login/model/login_form_credentials.dart'; import 'package:paperless_mobile/features/login/model/login_form_credentials.dart';
@@ -19,29 +18,22 @@ import 'package:paperless_mobile/features/login/services/authentication_service.
import 'package:paperless_mobile/core/database/tables/global_settings.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart';
import 'package:paperless_mobile/core/database/tables/local_user_settings.dart'; import 'package:paperless_mobile/core/database/tables/local_user_settings.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
part 'authentication_state.dart'; part 'authentication_state.dart';
part 'authentication_cubit.freezed.dart';
class AuthenticationCubit extends Cubit<AuthenticationState> { class AuthenticationCubit extends Cubit<AuthenticationState> {
final PaperlessUserApi _userApi;
final LocalAuthenticationService _localAuthService; final LocalAuthenticationService _localAuthService;
final PaperlessAuthenticationApi _authApi; final PaperlessAuthenticationApi _authApi;
final SessionManager _sessionManager; final SessionManager _sessionManager;
final LabelRepository _labelRepository;
final SavedViewRepository _savedViewRepository;
final PaperlessServerStatsApi _serverStatsApi;
final PaperlessUserApi _userApi;
final PaperlessUserApiV3? _userApiV3;
AuthenticationCubit( AuthenticationCubit(
this._localAuthService, this._localAuthService,
this._authApi, this._authApi,
this._sessionManager, this._sessionManager,
this._labelRepository, this._userApi,
this._savedViewRepository, ) : super(const AuthenticationState.unauthenticated());
this._serverStatsApi,
this._userApi, {
PaperlessUserApiV3? userApiV3,
}) : _userApiV3 = userApiV3,
super(const AuthenticationState());
Future<void> login({ Future<void> login({
required LoginFormCredentials credentials, required LoginFormCredentials credentials,
@@ -66,14 +58,10 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!; final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
globalSettings.currentLoggedInUser = localUserId; globalSettings.currentLoggedInUser = localUserId;
await globalSettings.save(); await globalSettings.save();
emit( emit(
AuthenticationState( AuthenticationState.authenticated(
isAuthenticated: true,
username: credentials.username,
localUserId: localUserId,
fullName: serverUser.fullName,
apiVersion: apiVersion, apiVersion: apiVersion,
localUserId: localUserId,
), ),
); );
} }
@@ -116,26 +104,18 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
_sessionManager.updateSettings( _sessionManager.updateSettings(
authToken: credentials!.token, authToken: credentials!.token,
clientCertificate: credentials.clientCertificate, clientCertificate: credentials.clientCertificate,
serverInformation: PaperlessServerInformationModel(),
baseUrl: account.serverUrl, baseUrl: account.serverUrl,
); );
await _reloadRepositories();
globalSettings.currentLoggedInUser = localUserId; globalSettings.currentLoggedInUser = localUserId;
await globalSettings.save(); await globalSettings.save();
final response = await _sessionManager.client.get("/api/"); final response = await _sessionManager.client.get("/api/");
final apiVersion = response.headers["x-api-version"] as int; final apiVersion = response.headers["x-api-version"] as int;
emit(AuthenticationState.authenticated(
emit( localUserId: localUserId,
AuthenticationState( apiVersion: apiVersion,
isAuthenticated: true, ));
username: account.paperlessUser.username,
fullName: account.paperlessUser.fullName,
localUserId: localUserId,
apiVersion: apiVersion,
),
);
} }
Future<String> addAccount({ Future<String> addAccount({
@@ -179,19 +159,19 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
/// ///
Future<void> restoreSessionState() async { Future<void> restoreSessionState() async {
final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!; final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
final userId = globalSettings.currentLoggedInUser; final localUserId = globalSettings.currentLoggedInUser;
if (userId == null) { if (localUserId == null) {
// If there is nothing to restore, we can quit here. // If there is nothing to restore, we can quit here.
return; return;
} }
final userAccount = Hive.box<LocalUserAccount>(HiveBoxes.localUserAccount).get(userId)!; final userAccount = Hive.box<LocalUserAccount>(HiveBoxes.localUserAccount).get(localUserId)!;
if (userAccount.settings.isBiometricAuthenticationEnabled) { if (userAccount.settings.isBiometricAuthenticationEnabled) {
final localAuthSuccess = final localAuthSuccess =
await _localAuthService.authenticateLocalUser("Authenticate to log back in"); //TODO: INTL await _localAuthService.authenticateLocalUser("Authenticate to log back in"); //TODO: INTL
if (!localAuthSuccess) { if (!localAuthSuccess) {
emit(const AuthenticationState(showBiometricAuthenticationScreen: true)); emit(const AuthenticationState.requriresLocalAuthentication());
return; return;
} }
} }
@@ -207,18 +187,13 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
clientCertificate: authentication.clientCertificate, clientCertificate: authentication.clientCertificate,
authToken: authentication.token, authToken: authentication.token,
baseUrl: userAccount.serverUrl, baseUrl: userAccount.serverUrl,
serverInformation: PaperlessServerInformationModel(),
); );
final response = await _sessionManager.client.get("/api/"); final response = await _sessionManager.client.get("/api/");
final apiVersion = response.headers["x-api-version"] as int; final apiVersion = response.headers["x-api-version"] as int;
emit( emit(
AuthenticationState( AuthenticationState.authenticated(
isAuthenticated: true,
showBiometricAuthenticationScreen: false,
username: userAccount.paperlessUser.username,
apiVersion: apiVersion, apiVersion: apiVersion,
fullName: userAccount.paperlessUser.fullName, localUserId: localUserId,
), ),
); );
} }
@@ -229,7 +204,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
globalSettings globalSettings
..currentLoggedInUser = null ..currentLoggedInUser = null
..save(); ..save();
emit(const AuthenticationState()); emit(const AuthenticationState.unauthenticated());
} }
Future<Uint8List> _getEncryptedBoxKey() async { Future<Uint8List> _getEncryptedBoxKey() async {
@@ -254,23 +229,12 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
); );
} }
Future<void> _resetExternalState() { Future<void> _resetExternalState() async {
_sessionManager.resetSettings(); _sessionManager.resetSettings();
return Future.wait([ await HydratedBloc.storage.clear();
HydratedBloc.storage.clear(),
_labelRepository.clear(),
_savedViewRepository.clear(),
]);
} }
Future<void> _reloadRepositories() { Future<int> _addUser(
return Future.wait([
_labelRepository.initialize(),
_savedViewRepository.findAll(),
]);
}
Future<UserModel> _addUser(
String localUserId, String localUserId,
String serverUrl, String serverUrl,
LoginFormCredentials credentials, LoginFormCredentials credentials,
@@ -303,7 +267,6 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
} }
final serverUserId = await _userApi.findCurrentUserId(); final serverUserId = await _userApi.findCurrentUserId();
final serverUser = await _userApi.find(serverUserId);
// Create user account // Create user account
await userAccountBox.put( await userAccountBox.put(
@@ -312,7 +275,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
id: localUserId, id: localUserId,
settings: LocalUserSettings(), settings: LocalUserSettings(),
serverUrl: serverUrl, serverUrl: serverUrl,
paperlessUser: serverUser, paperlessUserId: 1,
), ),
); );
@@ -332,6 +295,6 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
), ),
); );
userCredentialsBox.close(); userCredentialsBox.close();
return serverUser; return serverUserId;
} }
} }

View File

@@ -0,0 +1,465 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'authentication_cubit.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc
mixin _$AuthenticationState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() unauthenticated,
required TResult Function() requriresLocalAuthentication,
required TResult Function(String localUserId, int apiVersion) authenticated,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? unauthenticated,
TResult? Function()? requriresLocalAuthentication,
TResult? Function(String localUserId, int apiVersion)? authenticated,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? unauthenticated,
TResult Function()? requriresLocalAuthentication,
TResult Function(String localUserId, int apiVersion)? authenticated,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_RequiresLocalAuthentication value)
requriresLocalAuthentication,
required TResult Function(_Authenticated value) authenticated,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult? Function(_Authenticated value)? authenticated,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult Function(_Authenticated value)? authenticated,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AuthenticationStateCopyWith<$Res> {
factory $AuthenticationStateCopyWith(
AuthenticationState value, $Res Function(AuthenticationState) then) =
_$AuthenticationStateCopyWithImpl<$Res, AuthenticationState>;
}
/// @nodoc
class _$AuthenticationStateCopyWithImpl<$Res, $Val extends AuthenticationState>
implements $AuthenticationStateCopyWith<$Res> {
_$AuthenticationStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
}
/// @nodoc
abstract class _$$_UnauthenticatedCopyWith<$Res> {
factory _$$_UnauthenticatedCopyWith(
_$_Unauthenticated value, $Res Function(_$_Unauthenticated) then) =
__$$_UnauthenticatedCopyWithImpl<$Res>;
}
/// @nodoc
class __$$_UnauthenticatedCopyWithImpl<$Res>
extends _$AuthenticationStateCopyWithImpl<$Res, _$_Unauthenticated>
implements _$$_UnauthenticatedCopyWith<$Res> {
__$$_UnauthenticatedCopyWithImpl(
_$_Unauthenticated _value, $Res Function(_$_Unauthenticated) _then)
: super(_value, _then);
}
/// @nodoc
class _$_Unauthenticated implements _Unauthenticated {
const _$_Unauthenticated();
@override
String toString() {
return 'AuthenticationState.unauthenticated()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$_Unauthenticated);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() unauthenticated,
required TResult Function() requriresLocalAuthentication,
required TResult Function(String localUserId, int apiVersion) authenticated,
}) {
return unauthenticated();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? unauthenticated,
TResult? Function()? requriresLocalAuthentication,
TResult? Function(String localUserId, int apiVersion)? authenticated,
}) {
return unauthenticated?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? unauthenticated,
TResult Function()? requriresLocalAuthentication,
TResult Function(String localUserId, int apiVersion)? authenticated,
required TResult orElse(),
}) {
if (unauthenticated != null) {
return unauthenticated();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_RequiresLocalAuthentication value)
requriresLocalAuthentication,
required TResult Function(_Authenticated value) authenticated,
}) {
return unauthenticated(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult? Function(_Authenticated value)? authenticated,
}) {
return unauthenticated?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult Function(_Authenticated value)? authenticated,
required TResult orElse(),
}) {
if (unauthenticated != null) {
return unauthenticated(this);
}
return orElse();
}
}
abstract class _Unauthenticated implements AuthenticationState {
const factory _Unauthenticated() = _$_Unauthenticated;
}
/// @nodoc
abstract class _$$_RequiresLocalAuthenticationCopyWith<$Res> {
factory _$$_RequiresLocalAuthenticationCopyWith(
_$_RequiresLocalAuthentication value,
$Res Function(_$_RequiresLocalAuthentication) then) =
__$$_RequiresLocalAuthenticationCopyWithImpl<$Res>;
}
/// @nodoc
class __$$_RequiresLocalAuthenticationCopyWithImpl<$Res>
extends _$AuthenticationStateCopyWithImpl<$Res,
_$_RequiresLocalAuthentication>
implements _$$_RequiresLocalAuthenticationCopyWith<$Res> {
__$$_RequiresLocalAuthenticationCopyWithImpl(
_$_RequiresLocalAuthentication _value,
$Res Function(_$_RequiresLocalAuthentication) _then)
: super(_value, _then);
}
/// @nodoc
class _$_RequiresLocalAuthentication implements _RequiresLocalAuthentication {
const _$_RequiresLocalAuthentication();
@override
String toString() {
return 'AuthenticationState.requriresLocalAuthentication()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$_RequiresLocalAuthentication);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() unauthenticated,
required TResult Function() requriresLocalAuthentication,
required TResult Function(String localUserId, int apiVersion) authenticated,
}) {
return requriresLocalAuthentication();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? unauthenticated,
TResult? Function()? requriresLocalAuthentication,
TResult? Function(String localUserId, int apiVersion)? authenticated,
}) {
return requriresLocalAuthentication?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? unauthenticated,
TResult Function()? requriresLocalAuthentication,
TResult Function(String localUserId, int apiVersion)? authenticated,
required TResult orElse(),
}) {
if (requriresLocalAuthentication != null) {
return requriresLocalAuthentication();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_RequiresLocalAuthentication value)
requriresLocalAuthentication,
required TResult Function(_Authenticated value) authenticated,
}) {
return requriresLocalAuthentication(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult? Function(_Authenticated value)? authenticated,
}) {
return requriresLocalAuthentication?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult Function(_Authenticated value)? authenticated,
required TResult orElse(),
}) {
if (requriresLocalAuthentication != null) {
return requriresLocalAuthentication(this);
}
return orElse();
}
}
abstract class _RequiresLocalAuthentication implements AuthenticationState {
const factory _RequiresLocalAuthentication() = _$_RequiresLocalAuthentication;
}
/// @nodoc
abstract class _$$_AuthenticatedCopyWith<$Res> {
factory _$$_AuthenticatedCopyWith(
_$_Authenticated value, $Res Function(_$_Authenticated) then) =
__$$_AuthenticatedCopyWithImpl<$Res>;
@useResult
$Res call({String localUserId, int apiVersion});
}
/// @nodoc
class __$$_AuthenticatedCopyWithImpl<$Res>
extends _$AuthenticationStateCopyWithImpl<$Res, _$_Authenticated>
implements _$$_AuthenticatedCopyWith<$Res> {
__$$_AuthenticatedCopyWithImpl(
_$_Authenticated _value, $Res Function(_$_Authenticated) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? localUserId = null,
Object? apiVersion = null,
}) {
return _then(_$_Authenticated(
localUserId: null == localUserId
? _value.localUserId
: localUserId // ignore: cast_nullable_to_non_nullable
as String,
apiVersion: null == apiVersion
? _value.apiVersion
: apiVersion // ignore: cast_nullable_to_non_nullable
as int,
));
}
}
/// @nodoc
class _$_Authenticated implements _Authenticated {
const _$_Authenticated({required this.localUserId, required this.apiVersion});
@override
final String localUserId;
@override
final int apiVersion;
@override
String toString() {
return 'AuthenticationState.authenticated(localUserId: $localUserId, apiVersion: $apiVersion)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$_Authenticated &&
(identical(other.localUserId, localUserId) ||
other.localUserId == localUserId) &&
(identical(other.apiVersion, apiVersion) ||
other.apiVersion == apiVersion));
}
@override
int get hashCode => Object.hash(runtimeType, localUserId, apiVersion);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$_AuthenticatedCopyWith<_$_Authenticated> get copyWith =>
__$$_AuthenticatedCopyWithImpl<_$_Authenticated>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() unauthenticated,
required TResult Function() requriresLocalAuthentication,
required TResult Function(String localUserId, int apiVersion) authenticated,
}) {
return authenticated(localUserId, apiVersion);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? unauthenticated,
TResult? Function()? requriresLocalAuthentication,
TResult? Function(String localUserId, int apiVersion)? authenticated,
}) {
return authenticated?.call(localUserId, apiVersion);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? unauthenticated,
TResult Function()? requriresLocalAuthentication,
TResult Function(String localUserId, int apiVersion)? authenticated,
required TResult orElse(),
}) {
if (authenticated != null) {
return authenticated(localUserId, apiVersion);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Unauthenticated value) unauthenticated,
required TResult Function(_RequiresLocalAuthentication value)
requriresLocalAuthentication,
required TResult Function(_Authenticated value) authenticated,
}) {
return authenticated(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Unauthenticated value)? unauthenticated,
TResult? Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult? Function(_Authenticated value)? authenticated,
}) {
return authenticated?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Unauthenticated value)? unauthenticated,
TResult Function(_RequiresLocalAuthentication value)?
requriresLocalAuthentication,
TResult Function(_Authenticated value)? authenticated,
required TResult orElse(),
}) {
if (authenticated != null) {
return authenticated(this);
}
return orElse();
}
}
abstract class _Authenticated implements AuthenticationState {
const factory _Authenticated(
{required final String localUserId,
required final int apiVersion}) = _$_Authenticated;
String get localUserId;
int get apiVersion;
@JsonKey(ignore: true)
_$$_AuthenticatedCopyWith<_$_Authenticated> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -1,48 +1,11 @@
part of 'authentication_cubit.dart'; part of 'authentication_cubit.dart';
class AuthenticationState with EquatableMixin { @freezed
final bool showBiometricAuthenticationScreen; class AuthenticationState with _$AuthenticationState {
final bool isAuthenticated; const factory AuthenticationState.unauthenticated() = _Unauthenticated;
final String? username; const factory AuthenticationState.requriresLocalAuthentication() = _RequiresLocalAuthentication;
final String? fullName; const factory AuthenticationState.authenticated({
final String? localUserId; required String localUserId,
final int? apiVersion; required int apiVersion,
}) = _Authenticated;
const AuthenticationState({
this.isAuthenticated = false,
this.showBiometricAuthenticationScreen = false,
this.username,
this.fullName,
this.localUserId,
this.apiVersion,
});
AuthenticationState copyWith({
bool? isAuthenticated,
bool? showBiometricAuthenticationScreen,
String? username,
String? fullName,
String? localUserId,
int? apiVersion,
}) {
return AuthenticationState(
isAuthenticated: isAuthenticated ?? this.isAuthenticated,
showBiometricAuthenticationScreen:
showBiometricAuthenticationScreen ?? this.showBiometricAuthenticationScreen,
username: username ?? this.username,
fullName: fullName ?? this.fullName,
localUserId: localUserId ?? this.localUserId,
apiVersion: apiVersion ?? this.apiVersion,
);
}
@override
List<Object?> get props => [
localUserId,
username,
fullName,
isAuthenticated,
showBiometricAuthenticationScreen,
apiVersion,
];
} }

View File

@@ -0,0 +1,48 @@
import 'package:equatable/equatable.dart';
class OldAuthenticationState with EquatableMixin {
final bool showBiometricAuthenticationScreen;
final bool isAuthenticated;
final String? username;
final String? fullName;
final String? localUserId;
final int? apiVersion;
const OldAuthenticationState({
this.isAuthenticated = false,
this.showBiometricAuthenticationScreen = false,
this.username,
this.fullName,
this.localUserId,
this.apiVersion,
});
OldAuthenticationState copyWith({
bool? isAuthenticated,
bool? showBiometricAuthenticationScreen,
String? username,
String? fullName,
String? localUserId,
int? apiVersion,
}) {
return OldAuthenticationState(
isAuthenticated: isAuthenticated ?? this.isAuthenticated,
showBiometricAuthenticationScreen:
showBiometricAuthenticationScreen ?? this.showBiometricAuthenticationScreen,
username: username ?? this.username,
fullName: fullName ?? this.fullName,
localUserId: localUserId ?? this.localUserId,
apiVersion: apiVersion ?? this.apiVersion,
);
}
@override
List<Object?> get props => [
localUserId,
username,
fullName,
isAuthenticated,
showBiometricAuthenticationScreen,
apiVersion,
];
}

View File

@@ -4,6 +4,7 @@ import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
class UserAvatar extends StatelessWidget { class UserAvatar extends StatelessWidget {
final String userId; final String userId;
final LocalUserAccount account; final LocalUserAccount account;
const UserAvatar({ const UserAvatar({
super.key, super.key,
required this.userId, required this.userId,

View File

@@ -21,6 +21,8 @@ import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/core/database/tables/global_settings.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_account.dart';
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/database/tables/local_user_app_state.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/dio_http_error_interceptor.dart'; import 'package:paperless_mobile/core/interceptor/dio_http_error_interceptor.dart';
import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart'; import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart';
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart'; import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
@@ -89,10 +91,8 @@ void main() async {
iosInfo = await DeviceInfoPlugin().iosInfo; iosInfo = await DeviceInfoPlugin().iosInfo;
} }
// Initialize External dependencies
final connectivity = Connectivity(); final connectivity = Connectivity();
final localAuthentication = LocalAuthentication(); final localAuthentication = LocalAuthentication();
// Initialize other utility classes
final connectivityStatusService = ConnectivityStatusServiceImpl(connectivity); final connectivityStatusService = ConnectivityStatusServiceImpl(connectivity);
final localAuthService = LocalAuthenticationService(localAuthentication); final localAuthService = LocalAuthenticationService(localAuthentication);
@@ -111,40 +111,12 @@ void main() async {
languageHeaderInterceptor, languageHeaderInterceptor,
]); ]);
// Initialize Paperless APIs
final authApi = PaperlessAuthenticationApiImpl(sessionManager.client);
final documentsApi = PaperlessDocumentsApiImpl(sessionManager.client);
final labelsApi = PaperlessLabelApiImpl(sessionManager.client);
final statsApi = PaperlessServerStatsApiImpl(sessionManager.client);
final savedViewsApi = PaperlessSavedViewsApiImpl(sessionManager.client);
final tasksApi = PaperlessTasksApiImpl(
sessionManager.client,
);
// Initialize Blocs/Cubits // Initialize Blocs/Cubits
final connectivityCubit = ConnectivityCubit(connectivityStatusService); final connectivityCubit = ConnectivityCubit(connectivityStatusService);
// Load application settings and stored authentication data // Load application settings and stored authentication data
await connectivityCubit.initialize(); await connectivityCubit.initialize();
// Create repositories
final labelRepository = LabelRepository(labelsApi);
final savedViewRepository = SavedViewRepository(savedViewsApi);
//Create cubits/blocs
final authCubit = AuthenticationCubit(
localAuthService,
authApi,
sessionManager,
labelRepository,
savedViewRepository,
statsApi,
);
if (globalSettings.currentLoggedInUser != null) {
await authCubit.restoreSessionState();
}
final localNotificationService = LocalNotificationService(); final localNotificationService = LocalNotificationService();
await localNotificationService.initialize(); await localNotificationService.initialize();
@@ -156,42 +128,20 @@ void main() async {
runApp( runApp(
MultiProvider( MultiProvider(
providers: [ providers: [
ChangeNotifierProvider.value(value: sessionManager),
Provider<LocalAuthenticationService>.value(value: localAuthService), Provider<LocalAuthenticationService>.value(value: localAuthService),
Provider<PaperlessAuthenticationApi>.value(value: authApi),
Provider<PaperlessDocumentsApi>.value(value: documentsApi),
Provider<PaperlessLabelsApi>.value(value: labelsApi),
Provider<PaperlessServerStatsApi>.value(value: statsApi),
Provider<PaperlessSavedViewsApi>.value(value: savedViewsApi),
Provider<PaperlessTasksApi>.value(value: tasksApi),
Provider<cm.CacheManager>(
create: (context) => cm.CacheManager(
cm.Config(
'cacheKey',
fileService: DioFileService(sessionManager.client),
),
),
),
Provider<ConnectivityStatusService>.value( Provider<ConnectivityStatusService>.value(
value: connectivityStatusService, value: connectivityStatusService,
), ),
Provider<LocalNotificationService>.value(value: localNotificationService), Provider<LocalNotificationService>.value(value: localNotificationService),
Provider.value(value: DocumentChangedNotifier()), Provider.value(value: DocumentChangedNotifier()),
], ],
child: MultiRepositoryProvider( child: MultiBlocProvider(
providers: [ providers: [
RepositoryProvider<LabelRepository>.value( BlocProvider<ConnectivityCubit>.value(value: connectivityCubit),
value: labelRepository,
),
RepositoryProvider<SavedViewRepository>.value(
value: savedViewRepository,
),
], ],
child: MultiBlocProvider( child: PaperlessMobileEntrypoint(
providers: [ paperlessProviderFactory: PaperlessApiFactoryImpl(sessionManager),
BlocProvider<AuthenticationCubit>.value(value: authCubit),
BlocProvider<ConnectivityCubit>.value(value: connectivityCubit),
],
child: const PaperlessMobileEntrypoint(),
), ),
), ),
), ),
@@ -199,8 +149,10 @@ void main() async {
} }
class PaperlessMobileEntrypoint extends StatefulWidget { class PaperlessMobileEntrypoint extends StatefulWidget {
final PaperlessApiFactory paperlessProviderFactory;
const PaperlessMobileEntrypoint({ const PaperlessMobileEntrypoint({
Key? key, Key? key,
required this.paperlessProviderFactory,
}) : super(key: key); }) : super(key: key);
@override @override
@@ -238,7 +190,9 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
routes: { routes: {
DocumentDetailsRoute.routeName: (context) => const DocumentDetailsRoute(), DocumentDetailsRoute.routeName: (context) => const DocumentDetailsRoute(),
}, },
home: const AuthenticationWrapper(), home: AuthenticationWrapper(
paperlessProviderFactory: widget.paperlessProviderFactory,
),
); );
}, },
); );
@@ -248,7 +202,12 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
} }
class AuthenticationWrapper extends StatefulWidget { class AuthenticationWrapper extends StatefulWidget {
const AuthenticationWrapper({Key? key}) : super(key: key); final PaperlessApiFactory paperlessProviderFactory;
const AuthenticationWrapper({
Key? key,
required this.paperlessProviderFactory,
}) : super(key: key);
@override @override
State<AuthenticationWrapper> createState() => _AuthenticationWrapperState(); State<AuthenticationWrapper> createState() => _AuthenticationWrapperState();
@@ -295,17 +254,19 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<AuthenticationCubit, AuthenticationState>( return BlocBuilder<AuthenticationCubit, AuthenticationState>(
builder: (context, authentication) { builder: (context, authentication) {
if (authentication.isAuthenticated) { return authentication.when(
return HomeRoute( unauthenticated: () => LoginPage(
key: ValueKey(authentication.localUserId), titleString: S.of(context)!.connectToPaperless,
); submitText: S.of(context)!.signIn,
} else if (authentication.showBiometricAuthenticationScreen) { onSubmit: _onLogin,
return const VerifyIdentityPage(); ),
} requriresLocalAuthentication: () => const VerifyIdentityPage(),
return LoginPage( authenticated: (localUserId, apiVersion) => HomeRoute(
titleString: S.of(context)!.connectToPaperless, key: ValueKey(localUserId),
submitText: S.of(context)!.signIn, paperlessApiVersion: apiVersion,
onSubmit: _onLogin, paperlessProviderFactory: widget.paperlessProviderFactory,
localUserId: localUserId,
),
); );
}, },
); );