mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-07 13:15:55 -06:00
feat: More resturcturings, adapt code to previous changes
This commit is contained in:
@@ -16,13 +16,13 @@ class LocalUserAccount extends HiveObject {
|
||||
@HiveField(4)
|
||||
final LocalUserSettings settings;
|
||||
|
||||
@HiveField(6)
|
||||
final int paperlessUserId;
|
||||
@HiveField(7)
|
||||
final UserModel paperlessUser;
|
||||
|
||||
LocalUserAccount({
|
||||
required this.id,
|
||||
required this.serverUrl,
|
||||
required this.settings,
|
||||
required this.paperlessUserId,
|
||||
required this.paperlessUser,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,4 +7,6 @@ abstract class PaperlessApiFactory {
|
||||
PaperlessLabelsApi createLabelsApi(Dio dio, {required int apiVersion});
|
||||
PaperlessServerStatsApi createServerStatsApi(Dio dio, {required int apiVersion});
|
||||
PaperlessTasksApi createTasksApi(Dio dio, {required int apiVersion});
|
||||
PaperlessAuthenticationApi createAuthenticationApi(Dio dio);
|
||||
PaperlessUserApi createUserApi(Dio dio, {required int apiVersion});
|
||||
}
|
||||
|
||||
@@ -32,4 +32,19 @@ class PaperlessApiFactoryImpl implements PaperlessApiFactory {
|
||||
PaperlessTasksApi createTasksApi(Dio dio, {required int apiVersion}) {
|
||||
return PaperlessTasksApiImpl(dio);
|
||||
}
|
||||
|
||||
@override
|
||||
PaperlessAuthenticationApi createAuthenticationApi(Dio dio) {
|
||||
return PaperlessAuthenticationApiImpl(dio);
|
||||
}
|
||||
|
||||
@override
|
||||
PaperlessUserApi createUserApi(Dio dio, {required int apiVersion}) {
|
||||
if (apiVersion == 3) {
|
||||
return PaperlessUserApiV3Impl(dio);
|
||||
} else if (apiVersion == 1 || apiVersion == 2) {
|
||||
return PaperlessUserApiV2Impl(dio);
|
||||
}
|
||||
throw Exception("API $apiVersion not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,28 +4,13 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
||||
|
||||
class LabelRepository extends HydratedCubit<LabelRepositoryState> {
|
||||
class LabelRepository extends PersistentRepository<LabelRepositoryState> {
|
||||
final PaperlessLabelsApi _api;
|
||||
final Map<Object, StreamSubscription> _subscribers = {};
|
||||
|
||||
LabelRepository(this._api) : super(const LabelRepositoryState());
|
||||
|
||||
void addListener(
|
||||
Object source, {
|
||||
required void Function(LabelRepositoryState) onChanged,
|
||||
}) {
|
||||
onChanged(state);
|
||||
_subscribers.putIfAbsent(source, () {
|
||||
return stream.listen((event) => onChanged(event));
|
||||
});
|
||||
}
|
||||
|
||||
void removeListener(Object source) async {
|
||||
await _subscribers[source]?.cancel();
|
||||
_subscribers.remove(source);
|
||||
}
|
||||
|
||||
Future<void> initialize() {
|
||||
debugPrint("Initializing labels...");
|
||||
return Future.wait([
|
||||
@@ -195,14 +180,6 @@ class LabelRepository extends HydratedCubit<LabelRepositoryState> {
|
||||
return updated;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscribers.forEach((key, subscription) {
|
||||
subscription.cancel();
|
||||
});
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clear() async {
|
||||
await super.clear();
|
||||
|
||||
32
lib/core/repository/persistent_repository.dart
Normal file
32
lib/core/repository/persistent_repository.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
|
||||
abstract class PersistentRepository<T> extends HydratedCubit<T> {
|
||||
final Map<Object, StreamSubscription> _subscribers = {};
|
||||
|
||||
PersistentRepository(T initialState) : super(initialState);
|
||||
|
||||
void addListener(
|
||||
Object source, {
|
||||
required void Function(T) onChanged,
|
||||
}) {
|
||||
onChanged(state);
|
||||
_subscribers.putIfAbsent(source, () {
|
||||
return stream.listen((event) => onChanged(event));
|
||||
});
|
||||
}
|
||||
|
||||
void removeListener(Object source) async {
|
||||
await _subscribers[source]?.cancel();
|
||||
_subscribers.remove(source);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscribers.forEach((key, subscription) {
|
||||
subscription.cancel();
|
||||
});
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository_state.dart';
|
||||
|
||||
class SavedViewRepository extends HydratedCubit<SavedViewRepositoryState> {
|
||||
class SavedViewRepository extends PersistentRepository<SavedViewRepositoryState> {
|
||||
final PaperlessSavedViewsApi _api;
|
||||
final Map<Object, StreamSubscription> _subscribers = {};
|
||||
|
||||
void subscribe(
|
||||
Object source,
|
||||
void Function(Map<int, SavedView>) onChanged,
|
||||
) {
|
||||
_subscribers.putIfAbsent(source, () {
|
||||
onChanged(state.savedViews);
|
||||
return stream.listen((event) => onChanged(event.savedViews));
|
||||
});
|
||||
}
|
||||
|
||||
void unsubscribe(Object source) async {
|
||||
await _subscribers[source]?.cancel();
|
||||
_subscribers.remove(source);
|
||||
}
|
||||
|
||||
SavedViewRepository(this._api) : super(const SavedViewRepositoryState());
|
||||
|
||||
@@ -63,14 +46,6 @@ class SavedViewRepository extends HydratedCubit<SavedViewRepositoryState> {
|
||||
return found;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscribers.forEach((key, subscription) {
|
||||
subscription.cancel();
|
||||
});
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clear() async {
|
||||
await super.clear();
|
||||
|
||||
40
lib/core/repository/user_repository.dart
Normal file
40
lib/core/repository/user_repository.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
||||
|
||||
part 'user_repository_state.dart';
|
||||
part 'user_repository.freezed.dart';
|
||||
part 'user_repository.g.dart';
|
||||
|
||||
/// Repository for new users (API v3, server version 1.14.2+)
|
||||
class UserRepository extends PersistentRepository<UserRepositoryState> {
|
||||
final PaperlessUserApiV3 _userApiV3;
|
||||
|
||||
UserRepository(this._userApiV3) : super(const UserRepositoryState());
|
||||
|
||||
Future<void> initialize() async {
|
||||
await findAll();
|
||||
}
|
||||
|
||||
Future<Iterable<UserModel>> findAll() async {
|
||||
final users = await _userApiV3.findAll();
|
||||
emit(state.copyWith(users: {for (var e in users) e.id: e}));
|
||||
return users;
|
||||
}
|
||||
|
||||
Future<UserModel?> find(int id) async {
|
||||
final user = await _userApiV3.find(id);
|
||||
emit(state.copyWith(users: state.users..[id] = user));
|
||||
return user;
|
||||
}
|
||||
|
||||
@override
|
||||
UserRepositoryState? fromJson(Map<String, dynamic> json) {
|
||||
return UserRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic>? toJson(UserRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
161
lib/core/repository/user_repository.freezed.dart
Normal file
161
lib/core/repository/user_repository.freezed.dart
Normal file
@@ -0,0 +1,161 @@
|
||||
// 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 'user_repository.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');
|
||||
|
||||
UserRepositoryState _$UserRepositoryStateFromJson(Map<String, dynamic> json) {
|
||||
return _UserRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UserRepositoryState {
|
||||
Map<int, UserModel> get users => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$UserRepositoryStateCopyWith<UserRepositoryState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UserRepositoryStateCopyWith<$Res> {
|
||||
factory $UserRepositoryStateCopyWith(
|
||||
UserRepositoryState value, $Res Function(UserRepositoryState) then) =
|
||||
_$UserRepositoryStateCopyWithImpl<$Res, UserRepositoryState>;
|
||||
@useResult
|
||||
$Res call({Map<int, UserModel> users});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UserRepositoryStateCopyWithImpl<$Res, $Val extends UserRepositoryState>
|
||||
implements $UserRepositoryStateCopyWith<$Res> {
|
||||
_$UserRepositoryStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? users = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
users: null == users
|
||||
? _value.users
|
||||
: users // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, UserModel>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_UserRepositoryStateCopyWith<$Res>
|
||||
implements $UserRepositoryStateCopyWith<$Res> {
|
||||
factory _$$_UserRepositoryStateCopyWith(_$_UserRepositoryState value,
|
||||
$Res Function(_$_UserRepositoryState) then) =
|
||||
__$$_UserRepositoryStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({Map<int, UserModel> users});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_UserRepositoryStateCopyWithImpl<$Res>
|
||||
extends _$UserRepositoryStateCopyWithImpl<$Res, _$_UserRepositoryState>
|
||||
implements _$$_UserRepositoryStateCopyWith<$Res> {
|
||||
__$$_UserRepositoryStateCopyWithImpl(_$_UserRepositoryState _value,
|
||||
$Res Function(_$_UserRepositoryState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? users = null,
|
||||
}) {
|
||||
return _then(_$_UserRepositoryState(
|
||||
users: null == users
|
||||
? _value._users
|
||||
: users // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, UserModel>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$_UserRepositoryState implements _UserRepositoryState {
|
||||
const _$_UserRepositoryState({final Map<int, UserModel> users = const {}})
|
||||
: _users = users;
|
||||
|
||||
factory _$_UserRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$$_UserRepositoryStateFromJson(json);
|
||||
|
||||
final Map<int, UserModel> _users;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, UserModel> get users {
|
||||
if (_users is EqualUnmodifiableMapView) return _users;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_users);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserRepositoryState(users: $users)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_UserRepositoryState &&
|
||||
const DeepCollectionEquality().equals(other._users, _users));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(_users));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_UserRepositoryStateCopyWith<_$_UserRepositoryState> get copyWith =>
|
||||
__$$_UserRepositoryStateCopyWithImpl<_$_UserRepositoryState>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$_UserRepositoryStateToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _UserRepositoryState implements UserRepositoryState {
|
||||
const factory _UserRepositoryState({final Map<int, UserModel> users}) =
|
||||
_$_UserRepositoryState;
|
||||
|
||||
factory _UserRepositoryState.fromJson(Map<String, dynamic> json) =
|
||||
_$_UserRepositoryState.fromJson;
|
||||
|
||||
@override
|
||||
Map<int, UserModel> get users;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_UserRepositoryStateCopyWith<_$_UserRepositoryState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
11
lib/core/repository/user_repository_state.dart
Normal file
11
lib/core/repository/user_repository_state.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
part of 'user_repository.dart';
|
||||
|
||||
@freezed
|
||||
class UserRepositoryState with _$UserRepositoryState {
|
||||
const factory UserRepositoryState({
|
||||
@Default({}) Map<int, UserModel> users,
|
||||
}) = _UserRepositoryState;
|
||||
|
||||
factory UserRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$UserRepositoryStateFromJson(json);
|
||||
}
|
||||
@@ -39,20 +39,13 @@ class DocumentDetailsPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
late Future<DocumentMetaData> _metaData;
|
||||
static const double _itemSpacing = 24;
|
||||
|
||||
final _pagingScrollController = ScrollController();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadMetaData();
|
||||
}
|
||||
|
||||
void _loadMetaData() {
|
||||
_metaData = context
|
||||
.read<PaperlessDocumentsApi>()
|
||||
.getMetaData(context.read<DocumentDetailsCubit>().state.document);
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -67,8 +60,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
child: BlocListener<ConnectivityCubit, ConnectivityState>(
|
||||
listenWhen: (previous, current) => !previous.isConnected && current.isConnected,
|
||||
listener: (context, state) {
|
||||
_loadMetaData();
|
||||
setState(() {});
|
||||
context.read<DocumentDetailsCubit>().loadMetaData();
|
||||
},
|
||||
child: Scaffold(
|
||||
extendBodyBehindAppBar: false,
|
||||
@@ -285,7 +277,6 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
DocumentDownloadButton(
|
||||
document: state.document,
|
||||
enabled: isConnected,
|
||||
metaData: _metaData,
|
||||
),
|
||||
IconButton(
|
||||
tooltip: S.of(context)!.previewTooltip,
|
||||
|
||||
@@ -20,12 +20,10 @@ import 'package:permission_handler/permission_handler.dart';
|
||||
class DocumentDownloadButton extends StatefulWidget {
|
||||
final DocumentModel? document;
|
||||
final bool enabled;
|
||||
final Future<DocumentMetaData> metaData;
|
||||
const DocumentDownloadButton({
|
||||
super.key,
|
||||
required this.document,
|
||||
this.enabled = true,
|
||||
required this.metaData,
|
||||
});
|
||||
|
||||
@override
|
||||
|
||||
@@ -38,12 +38,9 @@ class ScannerPage extends StatefulWidget {
|
||||
State<ScannerPage> createState() => _ScannerPageState();
|
||||
}
|
||||
|
||||
class _ScannerPageState extends State<ScannerPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
final SliverOverlapAbsorberHandle searchBarHandle =
|
||||
SliverOverlapAbsorberHandle();
|
||||
final SliverOverlapAbsorberHandle actionsHandle =
|
||||
SliverOverlapAbsorberHandle();
|
||||
class _ScannerPageState extends State<ScannerPage> with SingleTickerProviderStateMixin {
|
||||
final SliverOverlapAbsorberHandle searchBarHandle = SliverOverlapAbsorberHandle();
|
||||
final SliverOverlapAbsorberHandle actionsHandle = SliverOverlapAbsorberHandle();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -180,8 +177,7 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
final success = await EdgeDetection.detectEdge(file.path);
|
||||
if (!success) {
|
||||
if (kDebugMode) {
|
||||
dev.log(
|
||||
'[ScannerPage] Scan either not successful or canceled by user.');
|
||||
dev.log('[ScannerPage] Scan either not successful or canceled by user.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -198,7 +194,7 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
final uploadResult = await Navigator.of(context).push<DocumentUploadResult>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => BlocProvider(
|
||||
create: (context) => DocumentUploadCubit(
|
||||
create: (_) => DocumentUploadCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
@@ -212,9 +208,7 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
if ((uploadResult?.success ?? false) && uploadResult?.taskId != null) {
|
||||
// For paperless version older than 1.11.3, task id will always be null!
|
||||
context.read<DocumentScannerCubit>().reset();
|
||||
context
|
||||
.read<TaskStatusCubit>()
|
||||
.listenToTaskChanges(uploadResult!.taskId!);
|
||||
context.read<TaskStatusCubit>().listenToTaskChanges(uploadResult!.taskId!);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -226,13 +226,10 @@ class _DocumentSearchPageState extends State<DocumentSearchPage> {
|
||||
hasLoaded: state.hasLoaded,
|
||||
enableHeroAnimation: false,
|
||||
onTap: (document) {
|
||||
Navigator.pushNamed(
|
||||
pushDocumentDetailsRoute(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
document: document,
|
||||
isLabelClickable: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
correspondents: state.correspondents,
|
||||
|
||||
@@ -47,7 +47,10 @@ class SliverSearchBar extends StatelessWidget {
|
||||
Hive.box<LocalUserAccount>(HiveBoxes.localUserAccount).listenable(),
|
||||
builder: (context, box, _) {
|
||||
final account = box.get(settings.currentLoggedInUser!)!;
|
||||
return UserAvatar(userId: settings.currentLoggedInUser!, account: account);
|
||||
return UserAvatar(
|
||||
userId: settings.currentLoggedInUser!,
|
||||
account: account,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -32,6 +32,7 @@ class DocumentUploadPreparationPage extends StatefulWidget {
|
||||
final String? filename;
|
||||
final String? fileExtension;
|
||||
|
||||
|
||||
const DocumentUploadPreparationPage({
|
||||
Key? key,
|
||||
required this.fileBytes,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||
import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart';
|
||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
||||
@@ -443,12 +444,9 @@ class _DocumentsPageState extends State<DocumentsPage> with SingleTickerProvider
|
||||
}
|
||||
|
||||
void _openDetails(DocumentModel document) {
|
||||
Navigator.pushNamed(
|
||||
pushDocumentDetailsRoute(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
document: document,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/pages/document_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
|
||||
@@ -23,8 +23,13 @@ import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class HomeRoute extends StatelessWidget {
|
||||
/// The id of the currently authenticated user (e.g. demo@paperless.example.com)
|
||||
final String localUserId;
|
||||
|
||||
/// The Paperless API version of the currently connected instance
|
||||
final int paperlessApiVersion;
|
||||
|
||||
// A factory providing the API implementations given an API version
|
||||
final PaperlessApiFactory paperlessProviderFactory;
|
||||
|
||||
const HomeRoute({
|
||||
@@ -44,6 +49,7 @@ class HomeRoute extends StatelessWidget {
|
||||
Provider<CacheManager>(
|
||||
create: (context) => CacheManager(
|
||||
Config(
|
||||
// Isolated cache per user.
|
||||
localUserId,
|
||||
fileService: DioFileService(context.read<SessionManager>().client),
|
||||
),
|
||||
@@ -121,11 +127,15 @@ class HomeRoute extends StatelessWidget {
|
||||
)..initialize(),
|
||||
),
|
||||
ProxyProvider<PaperlessServerStatsApi, ServerInformationCubit>(
|
||||
update: (context, value, previous) => ServerInformationCubit(value),
|
||||
update: (context, value, previous) =>
|
||||
ServerInformationCubit(value)..updateInformation(),
|
||||
),
|
||||
ProxyProvider<LabelRepository, LabelCubit>(
|
||||
update: (context, value, previous) => LabelCubit(value),
|
||||
),
|
||||
ProxyProvider<PaperlessTasksApi, TaskStatusCubit>(
|
||||
update: (context, value, previous) => TaskStatusCubit(value),
|
||||
),
|
||||
],
|
||||
child: const HomePage(),
|
||||
);
|
||||
|
||||
@@ -37,14 +37,11 @@ class _InboxItemState extends State<InboxItem> {
|
||||
builder: (context, state) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
Navigator.pushNamed(
|
||||
onTap: () {
|
||||
pushDocumentDetailsRoute(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
document: widget.document,
|
||||
isLabelClickable: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
|
||||
@@ -52,13 +52,10 @@ class _LinkedDocumentsPageState extends State<LinkedDocumentsPage>
|
||||
isLoading: state.isLoading,
|
||||
hasLoaded: state.hasLoaded,
|
||||
onTap: (document) {
|
||||
Navigator.pushNamed(
|
||||
pushDocumentDetailsRoute(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
document: document,
|
||||
isLabelClickable: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
correspondents: state.correspondents,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
@@ -9,6 +9,7 @@ import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.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/security/session_manager.dart';
|
||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||
import 'package:paperless_mobile/features/login/model/login_form_credentials.dart';
|
||||
@@ -23,16 +24,14 @@ part 'authentication_state.dart';
|
||||
part 'authentication_cubit.freezed.dart';
|
||||
|
||||
class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
final PaperlessUserApi _userApi;
|
||||
final LocalAuthenticationService _localAuthService;
|
||||
final PaperlessAuthenticationApi _authApi;
|
||||
final PaperlessApiFactory _apiFactory;
|
||||
final SessionManager _sessionManager;
|
||||
|
||||
AuthenticationCubit(
|
||||
this._localAuthService,
|
||||
this._authApi,
|
||||
this._apiFactory,
|
||||
this._sessionManager,
|
||||
this._userApi,
|
||||
) : super(const AuthenticationState.unauthenticated());
|
||||
|
||||
Future<void> login({
|
||||
@@ -43,7 +42,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
assert(credentials.username != null && credentials.password != null);
|
||||
final localUserId = "${credentials.username}@$serverUrl";
|
||||
|
||||
final serverUser = await _addUser(
|
||||
await _addUser(
|
||||
localUserId,
|
||||
serverUrl,
|
||||
credentials,
|
||||
@@ -51,13 +50,13 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
_sessionManager,
|
||||
);
|
||||
|
||||
final response = await _sessionManager.client.get("/api/");
|
||||
final apiVersion = response.headers["x-api-version"] as int;
|
||||
final apiVersion = await _getApiVersion(_sessionManager.client);
|
||||
|
||||
// Mark logged in user as currently active user.
|
||||
final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
|
||||
globalSettings.currentLoggedInUser = localUserId;
|
||||
await globalSettings.save();
|
||||
|
||||
emit(
|
||||
AuthenticationState.authenticated(
|
||||
apiVersion: apiVersion,
|
||||
@@ -110,8 +109,8 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
globalSettings.currentLoggedInUser = localUserId;
|
||||
await globalSettings.save();
|
||||
|
||||
final response = await _sessionManager.client.get("/api/");
|
||||
final apiVersion = response.headers["x-api-version"] as int;
|
||||
final apiVersion = await _getApiVersion(_sessionManager.client);
|
||||
|
||||
emit(AuthenticationState.authenticated(
|
||||
localUserId: localUserId,
|
||||
apiVersion: apiVersion,
|
||||
@@ -188,8 +187,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
authToken: authentication.token,
|
||||
baseUrl: userAccount.serverUrl,
|
||||
);
|
||||
final response = await _sessionManager.client.get("/api/");
|
||||
final apiVersion = response.headers["x-api-version"] as int;
|
||||
final apiVersion = await _getApiVersion(_sessionManager.client);
|
||||
emit(
|
||||
AuthenticationState.authenticated(
|
||||
apiVersion: apiVersion,
|
||||
@@ -247,12 +245,14 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
baseUrl: serverUrl,
|
||||
clientCertificate: clientCert,
|
||||
);
|
||||
final authApi = PaperlessAuthenticationApiImpl(sessionManager.client);
|
||||
|
||||
final authApi = _apiFactory.createAuthenticationApi(sessionManager.client);
|
||||
|
||||
final token = await authApi.login(
|
||||
username: credentials.username!,
|
||||
password: credentials.password!,
|
||||
);
|
||||
|
||||
sessionManager.updateSettings(
|
||||
baseUrl: serverUrl,
|
||||
clientCertificate: clientCert,
|
||||
@@ -265,8 +265,14 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
if (userAccountBox.containsKey(localUserId)) {
|
||||
throw Exception("User with id $localUserId already exists!");
|
||||
}
|
||||
final apiVersion = await _getApiVersion(sessionManager.client);
|
||||
|
||||
final serverUserId = await _userApi.findCurrentUserId();
|
||||
final serverUser = await _apiFactory
|
||||
.createUserApi(
|
||||
sessionManager.client,
|
||||
apiVersion: apiVersion,
|
||||
)
|
||||
.findCurrentUser();
|
||||
|
||||
// Create user account
|
||||
await userAccountBox.put(
|
||||
@@ -275,7 +281,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
id: localUserId,
|
||||
settings: LocalUserSettings(),
|
||||
serverUrl: serverUrl,
|
||||
paperlessUserId: 1,
|
||||
paperlessUser: serverUser,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -295,6 +301,11 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
),
|
||||
);
|
||||
userCredentialsBox.close();
|
||||
return serverUserId;
|
||||
return serverUser.id;
|
||||
}
|
||||
|
||||
Future<int> _getApiVersion(Dio dio) async {
|
||||
final response = await dio.get("/api/");
|
||||
return int.parse(response.headers.value('x-api-version') ?? "3");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
@@ -37,18 +36,20 @@ class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
},
|
||||
);
|
||||
|
||||
_savedViewRepository.subscribe(this, (views) {
|
||||
_savedViewRepository.addListener(
|
||||
this,
|
||||
onChanged: (views) {
|
||||
emit(
|
||||
state.maybeWhen(
|
||||
loaded:
|
||||
(savedViews, correspondents, documentTypes, tags, storagePaths) =>
|
||||
loaded: (savedViews, correspondents, documentTypes, tags, storagePaths) =>
|
||||
(state as _SavedViewLoadedState).copyWith(
|
||||
savedViews: views,
|
||||
savedViews: views.savedViews,
|
||||
),
|
||||
orElse: () => state,
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<SavedView> add(SavedView view) async {
|
||||
@@ -77,7 +78,7 @@ class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_savedViewRepository.unsubscribe(this);
|
||||
_savedViewRepository.removeListener(this);
|
||||
_labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@@ -76,13 +76,14 @@ class _SavedViewDetailsPageState extends State<SavedViewDetailsPage>
|
||||
isLoading: state.isLoading,
|
||||
hasLoaded: state.hasLoaded,
|
||||
onTap: (document) {
|
||||
Navigator.pushNamed(
|
||||
Navigator.push(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DocumentDetailsRoute(
|
||||
document: document,
|
||||
isLabelClickable: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
viewType: state.viewType,
|
||||
|
||||
@@ -86,11 +86,11 @@ class ManageAccountsPage extends StatelessWidget {
|
||||
final child = SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: ListTile(
|
||||
title: Text(account.username),
|
||||
title: Text(account.paperlessUser.username),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (account.fullName != null) Text(account.fullName!),
|
||||
if (account.paperlessUser.fullName != null) Text(account.paperlessUser.fullName!),
|
||||
Text(
|
||||
account.serverUrl.replaceFirst(RegExp(r'https://?'), ''),
|
||||
style: TextStyle(
|
||||
@@ -99,7 +99,7 @@ class ManageAccountsPage extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
isThreeLine: account.fullName != null,
|
||||
isThreeLine: account.paperlessUser.fullName != null,
|
||||
leading: UserAvatar(
|
||||
account: account,
|
||||
userId: userId,
|
||||
|
||||
@@ -22,7 +22,7 @@ class SettingsPage extends StatelessWidget {
|
||||
final host = user!.serverUrl.replaceFirst(RegExp(r"https?://"), "");
|
||||
return ListTile(
|
||||
title: Text(
|
||||
S.of(context)!.loggedInAs(user.username) + "@$host",
|
||||
S.of(context)!.loggedInAs(user.paperlessUser.username) + "@$host",
|
||||
style: Theme.of(context).textTheme.labelSmall,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||
import 'package:paperless_mobile/core/repository/user_repository.dart';
|
||||
|
||||
class UserAvatar extends StatelessWidget {
|
||||
final String userId;
|
||||
@@ -16,7 +19,7 @@ class UserAvatar extends StatelessWidget {
|
||||
final backgroundColor = Colors.primaries[userId.hashCode % Colors.primaries.length];
|
||||
final foregroundColor = backgroundColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
|
||||
return CircleAvatar(
|
||||
child: Text((account.fullName ?? account.username)
|
||||
child: Text((account.paperlessUser.fullName ?? account.paperlessUser.username)
|
||||
.split(" ")
|
||||
.take(2)
|
||||
.map((e) => e.substring(0, 1))
|
||||
|
||||
@@ -36,10 +36,8 @@ class _SimilarDocumentsViewState extends State<SimilarDocumentsView>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocConsumer<ConnectivityCubit, ConnectivityState>(
|
||||
listenWhen: (previous, current) =>
|
||||
!previous.isConnected && current.isConnected,
|
||||
listener: (context, state) =>
|
||||
context.read<SimilarDocumentsCubit>().initialize(),
|
||||
listenWhen: (previous, current) => !previous.isConnected && current.isConnected,
|
||||
listener: (context, state) => context.read<SimilarDocumentsCubit>().initialize(),
|
||||
builder: (context, connectivity) {
|
||||
return BlocBuilder<SimilarDocumentsCubit, SimilarDocumentsState>(
|
||||
builder: (context, state) {
|
||||
@@ -48,9 +46,7 @@ class _SimilarDocumentsViewState extends State<SimilarDocumentsView>
|
||||
child: OfflineWidget(),
|
||||
);
|
||||
}
|
||||
if (state.hasLoaded &&
|
||||
!state.isLoading &&
|
||||
state.documents.isEmpty) {
|
||||
if (state.hasLoaded && !state.isLoading && state.documents.isEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: Text(S.of(context)!.noItemsFound),
|
||||
@@ -65,13 +61,10 @@ class _SimilarDocumentsViewState extends State<SimilarDocumentsView>
|
||||
hasLoaded: state.hasLoaded,
|
||||
enableHeroAnimation: false,
|
||||
onTap: (document) {
|
||||
Navigator.pushNamed(
|
||||
pushDocumentDetailsRoute(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
document: document,
|
||||
isLabelClickable: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
correspondents: state.correspondents,
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart' as cm;
|
||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||
import 'package:hive_flutter/adapters.dart';
|
||||
@@ -26,11 +25,8 @@ 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/language_header.interceptor.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/connectivity_status_service.dart';
|
||||
import 'package:paperless_mobile/core/service/dio_file_service.dart';
|
||||
import 'package:paperless_mobile/core/type/types.dart';
|
||||
import 'package:paperless_mobile/features/app_intro/application_intro_slideshow.dart';
|
||||
import 'package:paperless_mobile/features/home/view/home_route.dart';
|
||||
@@ -125,6 +121,8 @@ void main() async {
|
||||
languageHeaderInterceptor.preferredLocaleSubtag = globalSettings.preferredLocaleSubtag;
|
||||
});
|
||||
|
||||
final apiFactory = PaperlessApiFactoryImpl(sessionManager);
|
||||
|
||||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
@@ -139,9 +137,17 @@ void main() async {
|
||||
child: MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<ConnectivityCubit>.value(value: connectivityCubit),
|
||||
BlocProvider(
|
||||
create: (context) => AuthenticationCubit(
|
||||
localAuthService,
|
||||
apiFactory,
|
||||
sessionManager,
|
||||
),
|
||||
child: Container(),
|
||||
)
|
||||
],
|
||||
child: PaperlessMobileEntrypoint(
|
||||
paperlessProviderFactory: PaperlessApiFactoryImpl(sessionManager),
|
||||
paperlessProviderFactory: apiFactory,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -187,9 +193,6 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
|
||||
localizationsDelegates: const [
|
||||
...S.localizationsDelegates,
|
||||
],
|
||||
routes: {
|
||||
DocumentDetailsRoute.routeName: (context) => const DocumentDetailsRoute(),
|
||||
},
|
||||
home: AuthenticationWrapper(
|
||||
paperlessProviderFactory: widget.paperlessProviderFactory,
|
||||
),
|
||||
@@ -217,7 +220,10 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
FlutterNativeSplash.remove();
|
||||
context
|
||||
.read<AuthenticationCubit>()
|
||||
.restoreSessionState()
|
||||
.then((value) => FlutterNativeSplash.remove());
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,34 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/features/document_details/cubit/document_details_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
|
||||
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class DocumentDetailsRoute extends StatelessWidget {
|
||||
static const String routeName = "/documentDetails";
|
||||
const DocumentDetailsRoute({super.key});
|
||||
final DocumentModel document;
|
||||
final bool isLabelClickable;
|
||||
final bool allowEdit;
|
||||
final String? titleAndContentQueryString;
|
||||
|
||||
const DocumentDetailsRoute({
|
||||
super.key,
|
||||
required this.document,
|
||||
this.isLabelClickable = true,
|
||||
this.allowEdit = true,
|
||||
this.titleAndContentQueryString,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final args = ModalRoute.of(context)!.settings.arguments
|
||||
as DocumentDetailsRouteArguments;
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => DocumentDetailsCubit(
|
||||
create: (_) => DocumentDetailsCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
initialDocument: args.document,
|
||||
initialDocument: document,
|
||||
),
|
||||
child: RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
lazy: false,
|
||||
child: DocumentDetailsPage(
|
||||
allowEdit: args.allowEdit,
|
||||
isLabelClickable: args.isLabelClickable,
|
||||
titleAndContentQueryString: args.titleAndContentQueryString,
|
||||
),
|
||||
allowEdit: allowEdit,
|
||||
isLabelClickable: isLabelClickable,
|
||||
titleAndContentQueryString: titleAndContentQueryString,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -47,3 +57,33 @@ class DocumentDetailsRouteArguments {
|
||||
this.titleAndContentQueryString,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> pushDocumentDetailsRoute(
|
||||
BuildContext context, {
|
||||
required DocumentModel document,
|
||||
bool isLabelClickable = true,
|
||||
bool allowEdit = true,
|
||||
String? titleAndContentQueryString,
|
||||
}) {
|
||||
final LabelRepository labelRepository = context.read();
|
||||
final DocumentChangedNotifier changeNotifier = context.read();
|
||||
final PaperlessDocumentsApi documentsApi = context.read();
|
||||
final LocalNotificationService notificationservice = context.read();
|
||||
final CacheManager cacheManager = context.read();
|
||||
return Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => MultiProvider(
|
||||
providers: [
|
||||
Provider.value(value: documentsApi),
|
||||
Provider.value(value: labelRepository),
|
||||
Provider.value(value: changeNotifier),
|
||||
Provider.value(value: notificationservice),
|
||||
Provider.value(value: cacheManager),
|
||||
],
|
||||
child: DocumentDetailsRoute(
|
||||
document: document,
|
||||
allowEdit: allowEdit,
|
||||
isLabelClickable: isLabelClickable,
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class UserModel with _$UserModel {
|
||||
if (value.firstName == null) {
|
||||
return value.lastName;
|
||||
}
|
||||
return value.firstName! + (value.lastName ?? '');
|
||||
return "${value.firstName!} ${value.lastName ?? ''}";
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -18,7 +18,12 @@ class PaperlessServerStatsApiImpl implements PaperlessServerStatsApi {
|
||||
|
||||
@override
|
||||
Future<PaperlessServerInformationModel> getServerInformation() async {
|
||||
final response = await client.get("/api/");
|
||||
final response = await client.get("/api/remote_version/");
|
||||
if (response.statusCode == 200) {
|
||||
final version = response.data["version"] as String;
|
||||
final updateAvailable = response.data["update_available"] as bool;
|
||||
}
|
||||
throw PaperlessServerException.unknown();
|
||||
final version =
|
||||
response.headers[PaperlessServerInformationModel.versionHeader]?.first ?? 'unknown';
|
||||
final apiVersion = int.tryParse(
|
||||
|
||||
@@ -2,5 +2,5 @@ import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
abstract class PaperlessUserApi {
|
||||
Future<int> findCurrentUserId();
|
||||
Future<UserModel> find(int id);
|
||||
Future<UserModel> findCurrentUser();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_api/src/modules/user_api/paperless_user_api.dart';
|
||||
|
||||
class PaperlessUserApiV2Impl implements PaperlessUserApi {
|
||||
final Dio client;
|
||||
@@ -11,13 +10,13 @@ class PaperlessUserApiV2Impl implements PaperlessUserApi {
|
||||
Future<int> findCurrentUserId() async {
|
||||
final response = await client.get("/api/ui_settings/");
|
||||
if (response.statusCode == 200) {
|
||||
return response.data['user']['id'];
|
||||
return response.data['user_id'];
|
||||
}
|
||||
throw const PaperlessServerException.unknown();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserModel> find(int id) async {
|
||||
Future<UserModel> findCurrentUser() async {
|
||||
final response = await client.get("/api/ui_settings/");
|
||||
if (response.statusCode == 200) {
|
||||
return UserModelV2.fromJson(response.data);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'package:paperless_api/src/models/user_model.dart';
|
||||
|
||||
abstract class PaperlessUserApiV3 {
|
||||
Future<Iterable<UserModel>> findWhere({
|
||||
Future<UserModelV3> find(int id);
|
||||
Future<Iterable<UserModelV3>> findAll();
|
||||
Future<Iterable<UserModelV3>> findWhere({
|
||||
String startsWith,
|
||||
String endsWith,
|
||||
String contains,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_api/src/modules/user_api/paperless_user_api.dart';
|
||||
import 'package:paperless_api/src/modules/user_api/paperless_user_api_v3.dart';
|
||||
|
||||
class PaperlessUserApiV3Impl implements PaperlessUserApi, PaperlessUserApiV3 {
|
||||
final Dio dio;
|
||||
@@ -9,7 +7,7 @@ class PaperlessUserApiV3Impl implements PaperlessUserApi, PaperlessUserApiV3 {
|
||||
PaperlessUserApiV3Impl(this.dio);
|
||||
|
||||
@override
|
||||
Future<UserModel> find(int id) async {
|
||||
Future<UserModelV3> find(int id) async {
|
||||
final response = await dio.get("/api/users/$id/");
|
||||
if (response.statusCode == 200) {
|
||||
return UserModelV3.fromJson(response.data);
|
||||
@@ -18,7 +16,7 @@ class PaperlessUserApiV3Impl implements PaperlessUserApi, PaperlessUserApiV3 {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<UserModel>> findWhere({
|
||||
Future<Iterable<UserModelV3>> findWhere({
|
||||
String startsWith = '',
|
||||
String endsWith = '',
|
||||
String contains = '',
|
||||
@@ -31,9 +29,9 @@ class PaperlessUserApiV3Impl implements PaperlessUserApi, PaperlessUserApiV3 {
|
||||
"username__iexact": username,
|
||||
});
|
||||
if (response.statusCode == 200) {
|
||||
return PagedSearchResult<UserModel>.fromJson(
|
||||
return PagedSearchResult<UserModelV3>.fromJson(
|
||||
response.data,
|
||||
UserModelV3.fromJson as UserModel Function(Object?),
|
||||
UserModelV3.fromJson as UserModelV3 Function(Object?),
|
||||
).results;
|
||||
}
|
||||
throw const PaperlessServerException.unknown();
|
||||
@@ -43,8 +41,26 @@ class PaperlessUserApiV3Impl implements PaperlessUserApi, PaperlessUserApiV3 {
|
||||
Future<int> findCurrentUserId() async {
|
||||
final response = await dio.get("/api/ui_settings/");
|
||||
if (response.statusCode == 200) {
|
||||
return response.data['user_id'];
|
||||
return response.data['user']['id'];
|
||||
}
|
||||
throw const PaperlessServerException.unknown();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<UserModelV3>> findAll() async {
|
||||
final response = await dio.get("/api/users/");
|
||||
if (response.statusCode == 200) {
|
||||
return PagedSearchResult<UserModelV3>.fromJson(
|
||||
response.data,
|
||||
UserModelV3.fromJson as UserModelV3 Function(Object?),
|
||||
).results;
|
||||
}
|
||||
throw const PaperlessServerException.unknown();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserModel> findCurrentUser() async {
|
||||
final id = await findCurrentUserId();
|
||||
return find(id);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user