From 503c8d37eafaef74b53a52f1f291124921a7212e Mon Sep 17 00:00:00 2001
From: NaiJi <naijiworld@protonmail.com>
Date: Tue, 30 Aug 2022 06:09:09 +0300
Subject: [PATCH] Implement server jobs cubit

---
 lib/config/bloc_config.dart                   |  7 ++-
 .../client_jobs_cubit.dart}                   | 56 ++++-------------
 .../cubit/client_jobs/client_jobs_state.dart  | 26 ++++++++
 .../cubit/forms/user/ssh_form_cubit.dart      |  2 +-
 .../cubit/forms/user/user_form_cubit.dart     |  2 +-
 lib/logic/cubit/jobs/jobs_state.dart          | 34 -----------
 .../cubit/server_jobs/server_jobs_cubit.dart  | 61 +++++++++++++++++++
 .../cubit/server_jobs/server_jobs_state.dart  | 16 +++++
 .../components/jobs_content/jobs_content.dart | 13 ++--
 .../pre_styled_buttons/flash_fab.dart         |  2 +-
 .../pre_styled_buttons.dart                   |  2 +-
 lib/ui/pages/services/services.dart           |  9 +--
 lib/ui/pages/ssh_keys/ssh_keys.dart           |  2 +-
 lib/ui/pages/users/users.dart                 |  2 +-
 14 files changed, 136 insertions(+), 98 deletions(-)
 rename lib/logic/cubit/{jobs/jobs_cubit.dart => client_jobs/client_jobs_cubit.dart} (73%)
 create mode 100644 lib/logic/cubit/client_jobs/client_jobs_state.dart
 delete mode 100644 lib/logic/cubit/jobs/jobs_state.dart
 create mode 100644 lib/logic/cubit/server_jobs/server_jobs_cubit.dart
 create mode 100644 lib/logic/cubit/server_jobs/server_jobs_state.dart

diff --git a/lib/config/bloc_config.dart b/lib/config/bloc_config.dart
index 0b4fe048..fd00db2b 100644
--- a/lib/config/bloc_config.dart
+++ b/lib/config/bloc_config.dart
@@ -6,8 +6,9 @@ import 'package:selfprivacy/logic/cubit/server_installation/server_installation_
 import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
 import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
 import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
+import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
 import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
 import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
 import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
@@ -30,6 +31,7 @@ class BlocAndProviderConfig extends StatelessWidget {
     final apiDevicesCubit = ApiDevicesCubit(serverInstallationCubit);
     final apiVolumesCubit = ApiProviderVolumeCubit(serverInstallationCubit);
     final apiServerVolumesCubit = ApiServerVolumeCubit(serverInstallationCubit);
+    final serverJobsCubit = ServerJobsCubit(serverInstallationCubit);
 
     return MultiProvider(
       providers: [
@@ -73,6 +75,9 @@ class BlocAndProviderConfig extends StatelessWidget {
         BlocProvider(
           create: (final _) => apiServerVolumesCubit..load(),
         ),
+        BlocProvider(
+          create: (final _) => serverJobsCubit..load(),
+        ),
         BlocProvider(
           create: (final _) => JobsCubit(
             usersCubit: usersCubit,
diff --git a/lib/logic/cubit/jobs/jobs_cubit.dart b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart
similarity index 73%
rename from lib/logic/cubit/jobs/jobs_cubit.dart
rename to lib/logic/cubit/client_jobs/client_jobs_cubit.dart
index 4457fba5..7461a6df 100644
--- a/lib/logic/cubit/jobs/jobs_cubit.dart
+++ b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart
@@ -8,17 +8,16 @@ import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server.dart';
 import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
 import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
 import 'package:selfprivacy/logic/models/job.dart';
-import 'package:selfprivacy/logic/models/json/server_job.dart';
 
 export 'package:provider/provider.dart';
 
-part 'jobs_state.dart';
+part 'client_jobs_state.dart';
 
 class JobsCubit extends Cubit<JobsState> {
   JobsCubit({
     required this.usersCubit,
     required this.servicesCubit,
-  }) : super(const JobsStateEmpty([]));
+  }) : super(JobsStateEmpty());
 
   final ServerApi api = ServerApi();
   final UsersCubit usersCubit;
@@ -32,7 +31,7 @@ class JobsCubit extends Cubit<JobsState> {
     }
     newJobsList.add(job);
     getIt<NavigationService>().showSnackBar('jobs.jobAdded'.tr());
-    emit(JobsStateWithJobs(newJobsList, state.serverJobList));
+    emit(JobsStateWithJobs(newJobsList));
   }
 
   void removeJob(final String id) {
@@ -55,7 +54,7 @@ class JobsCubit extends Cubit<JobsState> {
     } else {
       newJobsList.add(job);
       getIt<NavigationService>().showSnackBar('jobs.jobAdded'.tr());
-      emit(JobsStateWithJobs(newJobsList, state.serverJobList));
+      emit(JobsStateWithJobs(newJobsList));
     }
   }
 
@@ -69,23 +68,23 @@ class JobsCubit extends Cubit<JobsState> {
     if (!isExistInJobList) {
       newJobsList.add(job);
       getIt<NavigationService>().showSnackBar('jobs.jobAdded'.tr());
-      emit(JobsStateWithJobs(newJobsList, state.serverJobList));
+      emit(JobsStateWithJobs(newJobsList));
     }
   }
 
   Future<void> rebootServer() async {
-    emit(JobsStateLoading(state.serverJobList));
+    emit(JobsStateLoading());
     final bool isSuccessful = await api.reboot();
     if (isSuccessful) {
       getIt<NavigationService>().showSnackBar('jobs.rebootSuccess'.tr());
     } else {
       getIt<NavigationService>().showSnackBar('jobs.rebootFailed'.tr());
     }
-    emit(JobsStateEmpty(state.serverJobList));
+    emit(JobsStateEmpty());
   }
 
   Future<void> upgradeServer() async {
-    emit(JobsStateLoading(state.serverJobList));
+    emit(JobsStateLoading());
     final bool isPullSuccessful = await api.pullConfigurationUpdate();
     final bool isSuccessful = await api.upgrade();
     if (isSuccessful) {
@@ -97,13 +96,13 @@ class JobsCubit extends Cubit<JobsState> {
     } else {
       getIt<NavigationService>().showSnackBar('jobs.upgradeFailed'.tr());
     }
-    emit(JobsStateEmpty(state.serverJobList));
+    emit(JobsStateEmpty());
   }
 
   Future<void> applyAll() async {
     if (state is JobsStateWithJobs) {
       final List<ClientJob> jobs = (state as JobsStateWithJobs).clientJobList;
-      emit(JobsStateLoading(state.serverJobList));
+      emit(JobsStateLoading());
       bool hasServiceJobs = false;
       for (final ClientJob job in jobs) {
         if (job is CreateUserJob) {
@@ -131,40 +130,7 @@ class JobsCubit extends Cubit<JobsState> {
         await servicesCubit.load();
       }
 
-      emit(JobsStateEmpty(state.serverJobList));
+      emit(JobsStateEmpty());
     }
   }
-
-  Future<void> resetRequestsTimer() async {
-    const duration = Duration(seconds: 1);
-    Timer.periodic(
-      duration,
-      (final timer) async {
-        if (timer.tick >= 10) {
-          final List<ServerJob> serverJobs = await api.getServerJobs();
-          final List<ServerJob> newServerJobs = [];
-          for (final ServerJob job in serverJobs) {
-            if (job.status == 'FINISHED') {
-              await api.removeApiJob(job.uid);
-            } else {
-              newServerJobs.add(job);
-            }
-          }
-
-          if (state is JobsStateWithJobs) {
-            emit(
-              JobsStateWithJobs(
-                (state as JobsStateWithJobs).clientJobList,
-                newServerJobs,
-              ),
-            );
-          } else {
-            emit(
-              JobsStateEmpty(newServerJobs),
-            );
-          }
-        }
-      },
-    );
-  }
 }
diff --git a/lib/logic/cubit/client_jobs/client_jobs_state.dart b/lib/logic/cubit/client_jobs/client_jobs_state.dart
new file mode 100644
index 00000000..2bb31856
--- /dev/null
+++ b/lib/logic/cubit/client_jobs/client_jobs_state.dart
@@ -0,0 +1,26 @@
+part of 'client_jobs_cubit.dart';
+
+abstract class JobsState extends Equatable {
+  @override
+  List<Object?> get props => [];
+}
+
+class JobsStateLoading extends JobsState {}
+
+class JobsStateEmpty extends JobsState {}
+
+class JobsStateWithJobs extends JobsState {
+  JobsStateWithJobs(this.clientJobList);
+  final List<ClientJob> clientJobList;
+  JobsState removeById(final String id) {
+    final List<ClientJob> newJobsList =
+        clientJobList.where((final element) => element.id != id).toList();
+    if (newJobsList.isEmpty) {
+      return JobsStateEmpty();
+    }
+    return JobsStateWithJobs(newJobsList);
+  }
+
+  @override
+  List<Object?> get props => clientJobList;
+}
diff --git a/lib/logic/cubit/forms/user/ssh_form_cubit.dart b/lib/logic/cubit/forms/user/ssh_form_cubit.dart
index b6493ee7..ba992af0 100644
--- a/lib/logic/cubit/forms/user/ssh_form_cubit.dart
+++ b/lib/logic/cubit/forms/user/ssh_form_cubit.dart
@@ -2,7 +2,7 @@ import 'dart:async';
 
 import 'package:cubit_form/cubit_form.dart';
 import 'package:easy_localization/easy_localization.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/logic/models/job.dart';
 import 'package:selfprivacy/logic/models/hive/user.dart';
 
diff --git a/lib/logic/cubit/forms/user/user_form_cubit.dart b/lib/logic/cubit/forms/user/user_form_cubit.dart
index a385befb..92f66f15 100644
--- a/lib/logic/cubit/forms/user/user_form_cubit.dart
+++ b/lib/logic/cubit/forms/user/user_form_cubit.dart
@@ -2,7 +2,7 @@ import 'dart:async';
 
 import 'package:cubit_form/cubit_form.dart';
 import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/logic/models/job.dart';
 import 'package:selfprivacy/logic/models/hive/user.dart';
 import 'package:selfprivacy/utils/password_generator.dart';
diff --git a/lib/logic/cubit/jobs/jobs_state.dart b/lib/logic/cubit/jobs/jobs_state.dart
deleted file mode 100644
index 3737cb5d..00000000
--- a/lib/logic/cubit/jobs/jobs_state.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-part of 'jobs_cubit.dart';
-
-abstract class JobsState extends Equatable {
-  const JobsState(this.serverJobList);
-  final List<ServerJob> serverJobList;
-  @override
-  List<Object?> get props => [serverJobList];
-}
-
-class JobsStateLoading extends JobsState {
-  const JobsStateLoading(super.serverJobList);
-}
-
-class JobsStateEmpty extends JobsState {
-  const JobsStateEmpty(super.serverJobList);
-}
-
-class JobsStateWithJobs extends JobsState {
-  const JobsStateWithJobs(this.clientJobList, super.serverJobList);
-  final List<ClientJob> clientJobList;
-
-  JobsState removeById(final String id) {
-    final List<ClientJob> newJobsList =
-        clientJobList.where((final element) => element.id != id).toList();
-
-    if (newJobsList.isEmpty) {
-      return JobsStateEmpty(serverJobList);
-    }
-    return JobsStateWithJobs(newJobsList, serverJobList);
-  }
-
-  @override
-  List<Object?> get props => [...super.props, clientJobList];
-}
diff --git a/lib/logic/cubit/server_jobs/server_jobs_cubit.dart b/lib/logic/cubit/server_jobs/server_jobs_cubit.dart
new file mode 100644
index 00000000..254e6380
--- /dev/null
+++ b/lib/logic/cubit/server_jobs/server_jobs_cubit.dart
@@ -0,0 +1,61 @@
+import 'dart:async';
+
+import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server.dart';
+import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
+import 'package:selfprivacy/logic/models/json/server_job.dart';
+
+export 'package:provider/provider.dart';
+
+part 'server_jobs_state.dart';
+
+class ServerJobsCubit
+    extends ServerInstallationDependendCubit<ServerJobsState> {
+  ServerJobsCubit(final ServerInstallationCubit serverInstallationCubit)
+      : super(
+          serverInstallationCubit,
+          const ServerJobsState(
+            serverJobList: [],
+          ),
+        );
+
+  Timer? timer;
+  final ServerApi api = ServerApi();
+
+  @override
+  void clear() async {
+    emit(
+      const ServerJobsState(
+        serverJobList: [],
+      ),
+    );
+    if (timer != null && timer!.isActive) {
+      timer!.cancel();
+      timer = null;
+    }
+  }
+
+  @override
+  void load() async {
+    if (serverInstallationCubit.state is ServerInstallationFinished) {
+      final List<ServerJob> jobs = await api.getServerJobs();
+      emit(
+        ServerJobsState(
+          serverJobList: jobs,
+        ),
+      );
+      timer = Timer(const Duration(seconds: 10), () => reload(useTimer: true));
+    }
+  }
+
+  Future<void> reload({final bool useTimer = false}) async {
+    final List<ServerJob> jobs = await api.getServerJobs();
+    emit(
+      ServerJobsState(
+        serverJobList: jobs,
+      ),
+    );
+    if (useTimer) {
+      timer = Timer(const Duration(seconds: 10), () => reload(useTimer: true));
+    }
+  }
+}
diff --git a/lib/logic/cubit/server_jobs/server_jobs_state.dart b/lib/logic/cubit/server_jobs/server_jobs_state.dart
new file mode 100644
index 00000000..82ac4377
--- /dev/null
+++ b/lib/logic/cubit/server_jobs/server_jobs_state.dart
@@ -0,0 +1,16 @@
+part of 'server_jobs_cubit.dart';
+
+class ServerJobsState extends ServerInstallationDependendState {
+  const ServerJobsState({this.serverJobList = const []});
+  final List<ServerJob> serverJobList;
+
+  @override
+  List<Object?> get props => serverJobList;
+
+  ServerJobsState copyWith({
+    final List<ServerJob>? serverJobList,
+  }) =>
+      ServerJobsState(
+        serverJobList: serverJobList ?? this.serverJobList,
+      );
+}
diff --git a/lib/ui/components/jobs_content/jobs_content.dart b/lib/ui/components/jobs_content/jobs_content.dart
index 3948f7c4..f7063230 100644
--- a/lib/ui/components/jobs_content/jobs_content.dart
+++ b/lib/ui/components/jobs_content/jobs_content.dart
@@ -3,8 +3,9 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:selfprivacy/config/brand_theme.dart';
 import 'package:selfprivacy/config/get_it_config.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
+import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart';
 import 'package:selfprivacy/ui/components/action_button/action_button.dart';
 import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
 import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
@@ -122,11 +123,11 @@ class JobsContent extends StatelessWidget {
               const SizedBox(height: 8),
               const Divider(),
               const SizedBox(height: 8),
-              ...state.serverJobList.map(
-                (final job) => ServerJobCard(
-                  serverJob: job,
-                ),
-              ),
+              ...context.read<ServerJobsCubit>().state.serverJobList.map(
+                    (final job) => ServerJobCard(
+                      serverJob: job,
+                    ),
+                  ),
             ],
           );
         },
diff --git a/lib/ui/components/pre_styled_buttons/flash_fab.dart b/lib/ui/components/pre_styled_buttons/flash_fab.dart
index 4ae29087..c9fb754f 100644
--- a/lib/ui/components/pre_styled_buttons/flash_fab.dart
+++ b/lib/ui/components/pre_styled_buttons/flash_fab.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:ionicons/ionicons.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
 import 'package:selfprivacy/ui/components/jobs_content/jobs_content.dart';
 import 'package:selfprivacy/ui/helpers/modals.dart';
diff --git a/lib/ui/components/pre_styled_buttons/pre_styled_buttons.dart b/lib/ui/components/pre_styled_buttons/pre_styled_buttons.dart
index ad9105fb..5649236c 100644
--- a/lib/ui/components/pre_styled_buttons/pre_styled_buttons.dart
+++ b/lib/ui/components/pre_styled_buttons/pre_styled_buttons.dart
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:ionicons/ionicons.dart';
 import 'package:selfprivacy/config/brand_colors.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/ui/components/brand_bottom_sheet/brand_bottom_sheet.dart';
 import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
 import 'package:easy_localization/easy_localization.dart';
diff --git a/lib/ui/pages/services/services.dart b/lib/ui/pages/services/services.dart
index ba8465d2..a469d06b 100644
--- a/lib/ui/pages/services/services.dart
+++ b/lib/ui/pages/services/services.dart
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
 import 'package:selfprivacy/config/brand_theme.dart';
 import 'package:selfprivacy/logic/common_enum/common_enum.dart';
 import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
 import 'package:selfprivacy/logic/models/job.dart';
 import 'package:selfprivacy/logic/models/state_types.dart';
@@ -115,11 +115,8 @@ class _Card extends StatelessWidget {
     final domainName = UiHelpers.getDomainName(config);
 
     return GestureDetector(
-      onTap: () => Navigator.of(context).push(
-        materialRoute(
-          ServicePage(serviceId: serviceType.name)
-        )
-      ),
+      onTap: () => Navigator.of(context)
+          .push(materialRoute(ServicePage(serviceId: serviceType.name))),
       child: BrandCards.big(
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
diff --git a/lib/ui/pages/ssh_keys/ssh_keys.dart b/lib/ui/pages/ssh_keys/ssh_keys.dart
index 4059ba63..64c1af9c 100644
--- a/lib/ui/pages/ssh_keys/ssh_keys.dart
+++ b/lib/ui/pages/ssh_keys/ssh_keys.dart
@@ -10,7 +10,7 @@ import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
 
 import 'package:selfprivacy/config/brand_colors.dart';
 import 'package:selfprivacy/config/brand_theme.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/logic/models/hive/user.dart';
 import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
 import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
diff --git a/lib/ui/pages/users/users.dart b/lib/ui/pages/users/users.dart
index 659453d1..3ccb696a 100644
--- a/lib/ui/pages/users/users.dart
+++ b/lib/ui/pages/users/users.dart
@@ -8,7 +8,7 @@ import 'package:selfprivacy/config/text_themes.dart';
 import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
 import 'package:selfprivacy/logic/cubit/forms/factories/field_cubit_factory.dart';
 import 'package:selfprivacy/logic/cubit/forms/user/user_form_cubit.dart';
-import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
+import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
 import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
 import 'package:selfprivacy/logic/models/job.dart';
 import 'package:selfprivacy/logic/models/hive/user.dart';