service-states (#65)

Co-authored-by: Kherel <kherel@gmail.com>
Reviewed-on: kherel/selfprivacy.org.app#65
Co-authored-by: kherel <kherel@gmail.com>
Co-committed-by: kherel <kherel@gmail.com>
pull/66/head
kherel 2021-09-29 16:08:19 +03:00
parent a7e7d0ff05
commit 3e7d003f21
43 changed files with 372 additions and 680 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
ios/build
# Miscellaneous
*.class
*.log
@ -29,7 +30,7 @@
.packages
.pub-cache/
.pub/
/build/
**/build/
# Web related
lib/generated_plugin_registrant.dart

View File

@ -51,7 +51,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd
local_auth: ef62030a2731330b95df7ef1331bd15f6a64b8a6
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68

View File

@ -345,7 +345,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -360,7 +360,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = UVNTKR53DD;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -380,6 +380,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
@ -432,7 +433,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -482,7 +483,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -499,7 +500,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = UVNTKR53DD;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -520,6 +521,7 @@
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -530,7 +532,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = UVNTKR53DD;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -550,6 +552,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;

View File

@ -2,11 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleLocalizations</key>
<array>
<string>ru</string>
<string>en</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
@ -15,6 +10,11 @@
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>ru</string>
<string>en</string>
</array>
<key>CFBundleName</key>
<string>selfprivacy</string>
<key>CFBundlePackageType</key>
@ -24,7 +24,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
@ -34,8 +34,6 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -16,7 +16,8 @@ class BlocAndProviderConfig extends StatelessWidget {
Widget build(BuildContext context) {
var isDark = false;
var usersCubit = UsersCubit();
var servicesCubit = ServicesCubit();
var appConfigCubit = AppConfigCubit()..load();
var servicesCubit = ServicesCubit(appConfigCubit);
return MultiProvider(
providers: [
BlocProvider(
@ -25,18 +26,13 @@ class BlocAndProviderConfig extends StatelessWidget {
isOnbordingShowing: true,
)..load(),
),
BlocProvider(
lazy: false,
create: (_) => AppConfigCubit(servicesCubit)..load(),
),
BlocProvider(lazy: false, create: (_) => appConfigCubit),
BlocProvider(create: (_) => ProvidersCubit()),
BlocProvider(create: (_) => usersCubit..load(), lazy: false),
BlocProvider(create: (_) => servicesCubit..load(), lazy: false),
BlocProvider(
create: (_) => JobsCubit(
usersCubit: usersCubit,
servicesCubit: servicesCubit,
),
create: (_) =>
JobsCubit(usersCubit: usersCubit, servicesCubit: servicesCubit),
),
],
child: child,

View File

@ -94,7 +94,7 @@ class HetznerApi extends ApiMap {
/// check the branch name, it could be "development" or "master".
var data = jsonDecode(
'''{"name":"$domainName","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[$dbId], "networks":[], "user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} CF_TOKEN=$cloudFlareKey DB_PASSWORD=$dbPassword bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":true, "location": "fsn1"}''');
'''{"name":"$domainName","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[$dbId], "networks":[], "user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/development/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} CF_TOKEN=$cloudFlareKey DB_PASSWORD=$dbPassword bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":true, "location": "fsn1"}''');
Response serverCreateResponse = await client.post(
'/servers',

View File

@ -105,6 +105,20 @@ class ServerApi extends ApiMap {
);
client.close();
}
Future<Map<ServiceTypes, bool>> servicesPowerCheck() async {
var client = await getClient();
Response response = await client.get('/services/status');
close(client);
return {
ServiceTypes.passwordManager: response.data['bitwarden'] == 0,
ServiceTypes.git: response.data['gitea'] == 0,
ServiceTypes.cloud: response.data['nextcloud'] == 0,
ServiceTypes.vpn: response.data['ocserv'] == 0,
ServiceTypes.socialNetwork: response.data['pleroma'] == 0,
};
}
}
extension UrlServerExt on ServiceTypes {

View File

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/get_it/ssh.dart';
import 'package:selfprivacy/logic/models/backblaze_credential.dart';
import 'package:selfprivacy/logic/models/cloudflare_domain.dart';
@ -46,32 +45,35 @@ part 'app_config_state.dart';
/// c. if server is okay set that fully checked
class AppConfigCubit extends Cubit<AppConfigState> {
AppConfigCubit(this.servicesCubit) : super(InitialAppConfigState());
AppConfigCubit() : super(AppConfigEmpty());
final repository = AppConfigRepository();
final ServicesCubit servicesCubit;
Future<void> load() async {
var state = await repository.load();
if (state.progress < 6 || state.isFullyInitilized) {
if (state is AppConfigFinished) {
emit(state);
} else if (state.progress == 6) {
startServerIfDnsIsOkay(state: state, isImmediate: true);
} else if (state.progress == 7) {
resetServerIfServerIsOkay(state: state, isImmediate: true);
} else if (state.progress == 8) {
oneMoreReset(state: state, isImmediate: true);
} else if (state.progress == 9) {
finishCheckIfServerIsOkay(state: state, isImmediate: true);
} else if (state is AppConfigNotFinished) {
if (state.progress == 6) {
startServerIfDnsIsOkay(state: state, isImmediate: true);
} else if (state.progress == 7) {
resetServerIfServerIsOkay(state: state, isImmediate: true);
} else if (state.progress == 8) {
oneMoreReset(state: state, isImmediate: true);
} else if (state.progress == 9) {
finishCheckIfServerIsOkay(state: state, isImmediate: true);
}
} else {
throw 'wrong state';
}
}
void startServerIfDnsIsOkay({
AppConfigState? state,
AppConfigNotFinished? state,
bool isImmediate = false,
}) async {
state = state ?? this.state;
state = state ?? this.state as AppConfigNotFinished;
final work = () async {
emit(TimerState(dataState: state!, isLoading: true));
@ -116,10 +118,10 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
void oneMoreReset({
AppConfigState? state,
AppConfigNotFinished? state,
bool isImmediate = false,
}) async {
var dataState = state ?? this.state;
var dataState = state ?? this.state as AppConfigNotFinished;
var work = () async {
emit(TimerState(dataState: dataState, isLoading: true));
@ -169,10 +171,10 @@ class AppConfigCubit extends Cubit<AppConfigState> {
}
void resetServerIfServerIsOkay({
AppConfigState? state,
AppConfigNotFinished? state,
bool isImmediate = false,
}) async {
var dataState = state ?? this.state;
var dataState = state ?? this.state as AppConfigNotFinished;
var work = () async {
emit(TimerState(dataState: dataState, isLoading: true));
@ -224,10 +226,10 @@ class AppConfigCubit extends Cubit<AppConfigState> {
Timer? timer;
void finishCheckIfServerIsOkay({
AppConfigState? state,
AppConfigNotFinished? state,
bool isImmediate = false,
}) async {
state = state ?? this.state;
state = state ?? this.state as AppConfigNotFinished;
var work = () async {
emit(TimerState(dataState: state!, isLoading: true));
@ -236,12 +238,8 @@ class AppConfigCubit extends Cubit<AppConfigState> {
if (isServerWorking) {
await repository.saveHasFinalChecked(true);
servicesCubit.allOn();
emit(state.copyWith(
hasFinalChecked: true,
isLoading: false,
));
emit(state.finish());
} else {
finishCheckIfServerIsOkay();
}
@ -264,45 +262,31 @@ class AppConfigCubit extends Cubit<AppConfigState> {
void clearAppConfig() {
closeTimer();
servicesCubit.allOff();
repository.clearAppConfig();
emit(InitialAppConfigState());
emit(AppConfigEmpty());
}
Future<void> serverDelete() async {
closeTimer();
servicesCubit.allOff();
if (state.hetznerServer != null) {
await repository.deleteServer(state.cloudFlareDomain!);
await getIt<SSHModel>().clear();
}
await repository.deleteRecords();
emit(AppConfigState(
hetznerKey: state.hetznerKey,
cloudFlareKey: state.cloudFlareKey,
backblazeCredential: state.backblazeCredential,
cloudFlareDomain: state.cloudFlareDomain,
rootUser: state.rootUser,
hetznerServer: null,
isServerStarted: false,
isServerResetedFirstTime: false,
isServerResetedSecondTime: false,
hasFinalChecked: false,
isLoading: false,
error: null,
));
emit(AppConfigEmpty());
}
void setHetznerKey(String hetznerKey) async {
await repository.saveHetznerKey(hetznerKey);
emit(state.copyWith(hetznerKey: hetznerKey));
emit((state as AppConfigNotFinished).copyWith(hetznerKey: hetznerKey));
}
void setCloudflareKey(String cloudFlareKey) async {
await repository.saveCloudFlareKey(cloudFlareKey);
emit(state.copyWith(cloudFlareKey: cloudFlareKey));
emit(
(state as AppConfigNotFinished).copyWith(cloudFlareKey: cloudFlareKey));
}
void setBackblazeKey(String keyId, String applicationKey) async {
@ -311,38 +295,41 @@ class AppConfigCubit extends Cubit<AppConfigState> {
applicationKey: applicationKey,
);
await repository.saveBackblazeKey(backblazeCredential);
emit(state.copyWith(backblazeCredential: backblazeCredential));
emit((state as AppConfigNotFinished)
.copyWith(backblazeCredential: backblazeCredential));
}
void setDomain(CloudFlareDomain cloudFlareDomain) async {
await repository.saveDomain(cloudFlareDomain);
emit(state.copyWith(cloudFlareDomain: cloudFlareDomain));
emit((state as AppConfigNotFinished)
.copyWith(cloudFlareDomain: cloudFlareDomain));
}
void setRootUser(User rootUser) async {
await repository.saveRootUser(rootUser);
emit(state.copyWith(rootUser: rootUser));
emit((state as AppConfigNotFinished).copyWith(rootUser: rootUser));
}
void createServerAndSetDnsRecords() async {
AppConfigState _stateCopy = state;
AppConfigNotFinished _stateCopy = state as AppConfigNotFinished;
var onSuccess = (HetznerServerDetails serverDetails) async {
await repository.createDnsRecords(
serverDetails.ip4,
state.cloudFlareDomain!,
);
emit(state.copyWith(
emit((state as AppConfigNotFinished).copyWith(
isLoading: false,
hetznerServer: serverDetails,
));
startServerIfDnsIsOkay();
};
var onCancel = () => emit(state.copyWith(isLoading: false));
var onCancel =
() => emit((state as AppConfigNotFinished).copyWith(isLoading: false));
try {
emit(state.copyWith(isLoading: true));
emit((state as AppConfigNotFinished).copyWith(isLoading: true));
await repository.createServer(
state.rootUser!,
state.cloudFlareDomain!.domainName,

View File

@ -22,22 +22,37 @@ class AppConfigRepository {
Box box = Hive.box(BNames.appConfig);
Future<AppConfigState> load() async {
var res = AppConfigState(
hetznerKey: getIt<ApiConfigModel>().hetznerKey,
cloudFlareKey: getIt<ApiConfigModel>().cloudFlareKey,
cloudFlareDomain: getIt<ApiConfigModel>().cloudFlareDomain,
backblazeCredential: getIt<ApiConfigModel>().backblazeCredential,
hetznerServer: getIt<ApiConfigModel>().hetznerServer,
rootUser: box.get(BNames.rootUser),
isServerStarted: box.get(BNames.isServerStarted, defaultValue: false),
isServerResetedFirstTime:
box.get(BNames.isServerResetedFirstTime, defaultValue: false),
isServerResetedSecondTime:
box.get(BNames.isServerResetedSecondTime, defaultValue: false),
hasFinalChecked: box.get(BNames.hasFinalChecked, defaultValue: false),
error: null,
isLoading: box.get(BNames.isLoading, defaultValue: false),
);
late AppConfigState res;
if (box.get(BNames.hasFinalChecked, defaultValue: false)) {
res = AppConfigFinished(
hetznerKey: getIt<ApiConfigModel>().hetznerKey!,
cloudFlareKey: getIt<ApiConfigModel>().cloudFlareKey!,
cloudFlareDomain: getIt<ApiConfigModel>().cloudFlareDomain!,
backblazeCredential: getIt<ApiConfigModel>().backblazeCredential!,
hetznerServer: getIt<ApiConfigModel>().hetznerServer!,
rootUser: box.get(BNames.rootUser),
isServerStarted: box.get(BNames.isServerStarted, defaultValue: false),
isServerResetedFirstTime:
box.get(BNames.isServerResetedFirstTime, defaultValue: false),
isServerResetedSecondTime:
box.get(BNames.isServerResetedSecondTime, defaultValue: false),
);
} else {
res = AppConfigNotFinished(
hetznerKey: getIt<ApiConfigModel>().hetznerKey,
cloudFlareKey: getIt<ApiConfigModel>().cloudFlareKey,
cloudFlareDomain: getIt<ApiConfigModel>().cloudFlareDomain,
backblazeCredential: getIt<ApiConfigModel>().backblazeCredential,
hetznerServer: getIt<ApiConfigModel>().hetznerServer,
rootUser: box.get(BNames.rootUser),
isServerStarted: box.get(BNames.isServerStarted, defaultValue: false),
isServerResetedFirstTime:
box.get(BNames.isServerResetedFirstTime, defaultValue: false),
isServerResetedSecondTime:
box.get(BNames.isServerResetedSecondTime, defaultValue: false),
isLoading: box.get(BNames.isLoading, defaultValue: false),
);
}
return res;
}

View File

@ -11,9 +11,6 @@ class AppConfigState extends Equatable {
required this.isServerStarted,
required this.isServerResetedFirstTime,
required this.isServerResetedSecondTime,
required this.hasFinalChecked,
required this.isLoading,
required this.error,
});
@override
@ -26,9 +23,6 @@ class AppConfigState extends Equatable {
hetznerServer,
isServerStarted,
isServerResetedFirstTime,
hasFinalChecked,
isLoading,
error,
];
final String? hetznerKey;
@ -41,42 +35,6 @@ class AppConfigState extends Equatable {
final bool isServerResetedFirstTime;
final bool isServerResetedSecondTime;
final bool hasFinalChecked;
final bool isLoading;
final Exception? error;
AppConfigState copyWith({
String? hetznerKey,
String? cloudFlareKey,
BackblazeCredential? backblazeCredential,
CloudFlareDomain? cloudFlareDomain,
User? rootUser,
HetznerServerDetails? hetznerServer,
bool? isServerStarted,
bool? isServerResetedFirstTime,
bool? isServerResetedSecondTime,
bool? hasFinalChecked,
bool? isLoading,
Exception? error,
}) =>
AppConfigState(
hetznerKey: hetznerKey ?? this.hetznerKey,
cloudFlareKey: cloudFlareKey ?? this.cloudFlareKey,
backblazeCredential: backblazeCredential ?? this.backblazeCredential,
cloudFlareDomain: cloudFlareDomain ?? this.cloudFlareDomain,
rootUser: rootUser ?? this.rootUser,
hetznerServer: hetznerServer ?? this.hetznerServer,
isServerStarted: isServerStarted ?? this.isServerStarted,
isServerResetedFirstTime:
isServerResetedFirstTime ?? this.isServerResetedFirstTime,
isServerResetedSecondTime:
isServerResetedSecondTime ?? this.isServerResetedSecondTime,
hasFinalChecked: hasFinalChecked ?? this.hasFinalChecked,
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
);
bool get isHetznerFilled => hetznerKey != null;
bool get isCloudFlareFilled => cloudFlareKey != null;
bool get isBackblazeFilled => backblazeCredential != null;
@ -84,8 +42,8 @@ class AppConfigState extends Equatable {
bool get isUserFilled => rootUser != null;
bool get isServerCreated => hetznerServer != null;
bool get isFullyInitilized => _fulfilementList.every((el) => el!);
int get progress => _fulfilementList.where((el) => el!).length ;
// bool get isFullyInitilized => _fulfilementList.every((el) => el!);
int get progress => _fulfilementList.where((el) => el!).length;
int get porgressBar {
if (progress < 6) {
@ -108,32 +66,13 @@ class AppConfigState extends Equatable {
isServerStarted,
isServerResetedFirstTime,
isServerResetedSecondTime,
hasFinalChecked,
];
return res;
}
}
class InitialAppConfigState extends AppConfigState {
InitialAppConfigState()
: super(
hetznerKey: null,
cloudFlareKey: null,
backblazeCredential: null,
cloudFlareDomain: null,
rootUser: null,
hetznerServer: null,
isServerStarted: false,
isServerResetedFirstTime: false,
isServerResetedSecondTime: false,
hasFinalChecked: false,
isLoading: false,
error: null,
);
}
class TimerState extends AppConfigState {
class TimerState extends AppConfigNotFinished {
TimerState({
required this.dataState,
this.timerStart,
@ -149,12 +88,10 @@ class TimerState extends AppConfigState {
isServerStarted: dataState.isServerStarted,
isServerResetedFirstTime: dataState.isServerResetedFirstTime,
isServerResetedSecondTime: dataState.isServerResetedSecondTime,
hasFinalChecked: dataState.hasFinalChecked,
isLoading: isLoading,
error: dataState.error,
);
final AppConfigState dataState;
final AppConfigNotFinished dataState;
final DateTime? timerStart;
final Duration? duration;
@ -165,3 +102,134 @@ class TimerState extends AppConfigState {
duration,
];
}
class AppConfigNotFinished extends AppConfigState {
final bool isLoading;
AppConfigNotFinished({
String? hetznerKey,
String? cloudFlareKey,
BackblazeCredential? backblazeCredential,
CloudFlareDomain? cloudFlareDomain,
User? rootUser,
HetznerServerDetails? hetznerServer,
required bool isServerStarted,
required bool isServerResetedFirstTime,
required bool isServerResetedSecondTime,
required this.isLoading,
}) : super(
hetznerKey: hetznerKey,
cloudFlareKey: cloudFlareKey,
backblazeCredential: backblazeCredential,
cloudFlareDomain: cloudFlareDomain,
rootUser: rootUser,
hetznerServer: hetznerServer,
isServerStarted: isServerStarted,
isServerResetedFirstTime: isServerResetedFirstTime,
isServerResetedSecondTime: isServerResetedSecondTime,
);
@override
List<Object?> get props => [
hetznerKey,
cloudFlareKey,
backblazeCredential,
cloudFlareDomain,
rootUser,
hetznerServer,
isServerStarted,
isServerResetedFirstTime,
isLoading
];
AppConfigNotFinished copyWith({
String? hetznerKey,
String? cloudFlareKey,
BackblazeCredential? backblazeCredential,
CloudFlareDomain? cloudFlareDomain,
User? rootUser,
HetznerServerDetails? hetznerServer,
bool? isServerStarted,
bool? isServerResetedFirstTime,
bool? isServerResetedSecondTime,
bool? isLoading,
}) =>
AppConfigNotFinished(
hetznerKey: hetznerKey ?? this.hetznerKey,
cloudFlareKey: cloudFlareKey ?? this.cloudFlareKey,
backblazeCredential: backblazeCredential ?? this.backblazeCredential,
cloudFlareDomain: cloudFlareDomain ?? this.cloudFlareDomain,
rootUser: rootUser ?? this.rootUser,
hetznerServer: hetznerServer ?? this.hetznerServer,
isServerStarted: isServerStarted ?? this.isServerStarted,
isServerResetedFirstTime:
isServerResetedFirstTime ?? this.isServerResetedFirstTime,
isServerResetedSecondTime:
isServerResetedSecondTime ?? this.isServerResetedSecondTime,
isLoading: isLoading ?? this.isLoading,
);
AppConfigFinished finish() => AppConfigFinished(
hetznerKey: hetznerKey!,
cloudFlareKey: cloudFlareKey!,
backblazeCredential: backblazeCredential!,
cloudFlareDomain: cloudFlareDomain!,
rootUser: rootUser!,
hetznerServer: hetznerServer!,
isServerStarted: isServerStarted,
isServerResetedFirstTime: isServerResetedFirstTime,
isServerResetedSecondTime: isServerResetedSecondTime,
);
}
class AppConfigEmpty extends AppConfigNotFinished {
AppConfigEmpty()
: super(
hetznerKey: null,
cloudFlareKey: null,
backblazeCredential: null,
cloudFlareDomain: null,
rootUser: null,
hetznerServer: null,
isServerStarted: false,
isServerResetedFirstTime: false,
isServerResetedSecondTime: false,
isLoading: false,
);
}
class AppConfigFinished extends AppConfigState {
const AppConfigFinished({
required String hetznerKey,
required String cloudFlareKey,
required BackblazeCredential backblazeCredential,
required CloudFlareDomain cloudFlareDomain,
required User rootUser,
required HetznerServerDetails hetznerServer,
required bool isServerStarted,
required bool isServerResetedFirstTime,
required bool isServerResetedSecondTime,
}) : super(
hetznerKey: hetznerKey,
cloudFlareKey: cloudFlareKey,
backblazeCredential: backblazeCredential,
cloudFlareDomain: cloudFlareDomain,
rootUser: rootUser,
hetznerServer: hetznerServer,
isServerStarted: isServerStarted,
isServerResetedFirstTime: isServerResetedFirstTime,
isServerResetedSecondTime: isServerResetedSecondTime,
);
@override
List<Object?> get props => [
hetznerKey,
cloudFlareKey,
backblazeCredential,
cloudFlareDomain,
rootUser,
hetznerServer,
isServerStarted,
isServerResetedFirstTime,
];
}

View File

@ -0,0 +1,39 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
export 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
part 'authentication_dependend_state.dart';
abstract class AppConfigDependendCubit<T extends AppConfigDependendState>
extends Cubit<T> {
AppConfigDependendCubit(
this.appConfigCubit,
T initState,
) : super(initState) {
authCubitSubscription = appConfigCubit.stream.listen(checkAuthStatus);
checkAuthStatus(appConfigCubit.state);
}
void checkAuthStatus(AppConfigState state) {
if (state is AppConfigFinished) {
load();
} else if (state is AppConfigEmpty) {
clear();
}
}
late StreamSubscription authCubitSubscription;
final AppConfigCubit appConfigCubit;
void load();
void clear();
@override
Future<void> close() {
authCubitSubscription.cancel();
return super.close();
}
}

View File

@ -0,0 +1,5 @@
part of 'authentication_dependend_cubit.dart';
abstract class AppConfigDependendState extends Equatable {
const AppConfigDependendState();
}

View File

@ -1,8 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/config/text_themes.dart';
import 'package:selfprivacy/logic/api_maps/server.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
@ -76,17 +73,14 @@ class JobsCubit extends Cubit<JobsState> {
var jobs = (state as JobsStateWithJobs).jobList;
emit(JobsStateLoading());
var newUsers = <User>[];
var hasServiceJobs = false;
for (var job in jobs) {
if (job is CreateUserJob) {
newUsers.add(job.user);
await api.createUser(job.user);
} else if (job is ServiceToggleJob) {
hasServiceJobs = true;
await api.switchService(job.type, job.needToTurnOn);
if (job.needToTurnOn) {
servicesCubit.turnOnist([job.type]);
} else {
servicesCubit.turnOffList([job.type]);
}
}
if (job is CreateSSHKeyJob) {
await getIt<SSHModel>().generateKeys();
@ -96,6 +90,9 @@ class JobsCubit extends Cubit<JobsState> {
usersCubit.addUsers(newUsers);
await api.apply();
if (hasServiceJobs) {
await servicesCubit.load();
}
emit(JobsStateEmpty());

View File

@ -1,63 +1,34 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart';
import 'package:selfprivacy/config/hive_config.dart';
import 'package:selfprivacy/logic/api_maps/server.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
part 'services_state.dart';
class ServicesCubit extends Cubit<ServicesState> {
ServicesCubit() : super(ServicesState.allOff());
class ServicesCubit extends AppConfigDependendCubit<ServicesState> {
ServicesCubit(AppConfigCubit appConfigCubit)
: super(appConfigCubit, ServicesState.allOff());
Box box = Hive.box(BNames.servicesState);
void load() {
final api = ServerApi();
Future<void> load() async {
var statuses = await api.servicesPowerCheck();
emit(
ServicesState(
isPasswordManagerEnable:
box.get(ServiceTypes.passwordManager.txt, defaultValue: false),
isCloudEnable: box.get(ServiceTypes.cloud.txt, defaultValue: false),
isGitEnable: box.get(ServiceTypes.git.txt, defaultValue: false),
isSocialNetworkEnable:
box.get(ServiceTypes.socialNetwork.txt, defaultValue: false),
isVpnEnable: box.get(ServiceTypes.vpn.txt, defaultValue: false),
isPasswordManagerEnable: statuses[ServiceTypes.passwordManager]!,
isCloudEnable: statuses[ServiceTypes.cloud]!,
isGitEnable: statuses[ServiceTypes.git]!,
isSocialNetworkEnable: statuses[ServiceTypes.socialNetwork]!,
isVpnEnable: statuses[ServiceTypes.vpn]!,
),
);
}
void allOn() {
box.put(ServiceTypes.passwordManager.txt, true);
box.put(ServiceTypes.cloud.txt, true);
box.put(ServiceTypes.git.txt, true);
box.put(ServiceTypes.socialNetwork.txt, true);
box.put(ServiceTypes.vpn.txt, true);
emit(ServicesState.allOn());
}
void allOff() {
box.put(ServiceTypes.passwordManager.txt, false);
box.put(ServiceTypes.cloud.txt, false);
box.put(ServiceTypes.git.txt, false);
box.put(ServiceTypes.socialNetwork.txt, false);
box.put(ServiceTypes.vpn.txt, false);
@override
void clear() async {
box.clear();
emit(ServicesState.allOff());
}
void turnOffList(List<ServiceTypes> list) {
for (final service in list) {
box.put(service.txt, false);
}
emit(state.disableList(list));
}
void turnOnist(List<ServiceTypes> list) {
for (final service in list) {
box.put(service.txt, true);
}
emit(state.enableList(list));
}
}

View File

@ -1,6 +1,6 @@
part of 'services_cubit.dart';
class ServicesState extends Equatable {
class ServicesState extends AppConfigDependendState {
const ServicesState({
required this.isPasswordManagerEnable,
required this.isCloudEnable,

View File

@ -40,7 +40,7 @@ class InitializingPage extends StatelessWidget {
][cubit.state.progress]();
return BlocListener<AppConfigCubit, AppConfigState>(
listener: (context, state) {
if (state.isFullyInitilized) {
if (cubit.state is AppConfigFinished) {
Navigator.of(context).pushReplacement(materialRoute(RootPage()));
}
},
@ -80,7 +80,7 @@ class InitializingPage extends StatelessWidget {
child: Container(
alignment: Alignment.center,
child: BrandButton.text(
title: cubit.state.isFullyInitilized
title: cubit.state is AppConfigFinished
? 'basis.close'.tr()
: 'basis.later'.tr(),
onPressed: () {
@ -411,7 +411,7 @@ class InitializingPage extends StatelessWidget {
}
Widget _stepServer(AppConfigCubit appConfigCubit) {
var isLoading = appConfigCubit.state.isLoading;
var isLoading = (appConfigCubit.state as AppConfigNotFinished).isLoading;
return Builder(builder: (context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -438,7 +438,7 @@ class InitializingPage extends StatelessWidget {
}
Widget _stepCheck(AppConfigCubit appConfigCubit) {
assert(appConfigCubit.state is TimerState, 'wronge state');
assert(appConfigCubit.state is AppConfigNotFinished, 'wronge state');
var state = appConfigCubit.state as TimerState;
late int doneCount;
late String? text;

View File

@ -36,7 +36,7 @@ class MorePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var jobsCubit = context.watch<JobsCubit>();
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = context.watch<AppConfigCubit>().state is AppConfigFinished;
return Scaffold(
appBar: PreferredSize(

View File

@ -28,7 +28,7 @@ class ProvidersPage extends StatefulWidget {
class _ProvidersPageState extends State<ProvidersPage> {
@override
Widget build(BuildContext context) {
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = context.watch<AppConfigCubit>().state is AppConfigFinished;
final cards = ProviderType.values
.map(
@ -75,7 +75,7 @@ class _Card extends StatelessWidget {
String? message;
late String stableText;
late VoidCallback onTap;
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = context.watch<AppConfigCubit>().state is AppConfigFinished;
AppConfigState appConfig = context.watch<AppConfigCubit>().state;
var domainName =

View File

@ -53,7 +53,7 @@ class _ServerDetailsState extends State<ServerDetails>
@override
Widget build(BuildContext context) {
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = context.watch<AppConfigCubit>().state is AppConfigFinished;
var providerState = isReady ? StateType.stable : StateType.uninitialized;
return Scaffold(

View File

@ -41,7 +41,7 @@ class ServicesPage extends StatefulWidget {
class _ServicesPageState extends State<ServicesPage> {
@override
Widget build(BuildContext context) {
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = context.watch<AppConfigCubit>().state is AppConfigFinished;
return Scaffold(
appBar: PreferredSize(
@ -77,7 +77,7 @@ class _Card extends StatelessWidget {
final ServiceTypes serviceType;
@override
Widget build(BuildContext context) {
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = context.watch<AppConfigCubit>().state is AppConfigFinished;
var changeTab = context.read<ChangeTab>().onPress;
var serviceState = context.watch<ServicesCubit>().state;

View File

@ -32,7 +32,7 @@ class UsersPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final usersCubitState = context.watch<UsersCubit>().state;
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
var isReady = context.watch<AppConfigCubit>().state is AppConfigFinished;
final users = usersCubitState.users;
final isEmpty = usersCubitState.isEmpty;
Widget child;

View File

@ -28,7 +28,7 @@ packages:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
version: "2.0.0"
asn1lib:
dependency: transitive
description:
@ -49,14 +49,14 @@ packages:
name: basic_utils
url: "https://pub.dartlang.org"
source: hosted
version: "3.5.0"
version: "3.6.0"
bloc:
dependency: transitive
description:
name: bloc
url: "https://pub.dartlang.org"
source: hosted
version: "7.1.0"
version: "7.2.0"
boolean_selector:
dependency: transitive
description:
@ -91,14 +91,14 @@ packages:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.3"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.2"
build_runner_core:
dependency: transitive
description:
@ -119,7 +119,7 @@ packages:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.2"
version: "8.1.0"
characters:
dependency: transitive
description:
@ -147,7 +147,7 @@ packages:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3"
version: "0.3.0"
clock:
dependency: transitive
description:
@ -175,7 +175,7 @@ packages:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.0"
coverage:
dependency: transitive
description:
@ -203,7 +203,7 @@ packages:
name: cubit_form
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.18"
version: "1.0.16"
cupertino_icons:
dependency: "direct main"
description:
@ -217,7 +217,7 @@ packages:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.1"
dio:
dependency: "direct main"
description:
@ -266,7 +266,7 @@ packages:
name: extended_masked_text
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
version: "2.2.1"
fake_async:
dependency: transitive
description:
@ -313,14 +313,14 @@ packages:
name: flutter_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.0"
version: "7.3.0"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.2"
version: "0.9.0"
flutter_localizations:
dependency: transitive
description: flutter
@ -332,7 +332,7 @@ packages:
name: flutter_markdown
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.5"
version: "0.6.2"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@ -346,7 +346,7 @@ packages:
name: flutter_secure_storage
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.1"
version: "4.2.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -384,7 +384,7 @@ packages:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.1.0"
hive:
dependency: "direct main"
description:
@ -447,7 +447,7 @@ packages:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.0"
ionicons:
dependency: "direct main"
description:
@ -475,14 +475,14 @@ packages:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.4"
version: "4.1.3"
local_auth:
dependency: "direct main"
description:
name: local_auth
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.7"
version: "1.1.8"
logging:
dependency: transitive
description:
@ -580,14 +580,14 @@ packages:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.0"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.0"
path_provider_platform_interface:
dependency: transitive
description:
@ -601,7 +601,7 @@ packages:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.1"
pedantic:
dependency: transitive
description:
@ -622,21 +622,21 @@ packages:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
version: "3.0.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.0"
pointycastle:
dependency: "direct main"
description:
name: pointycastle
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.2"
version: "3.3.4"
pool:
dependency: transitive
description:
@ -657,7 +657,7 @@ packages:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.3"
version: "4.2.1"
provider:
dependency: "direct main"
description:
@ -706,7 +706,7 @@ packages:
name: share_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.3"
share_plus_macos:
dependency: transitive
description:
@ -741,21 +741,21 @@ packages:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
version: "2.0.6"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.0"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.0"
shared_preferences_platform_interface:
dependency: transitive
description:
@ -769,21 +769,21 @@ packages:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.0"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.1.4"
shelf_packages_handler:
dependency: transitive
description:
@ -797,7 +797,7 @@ packages:
name: shelf_static
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.0.0"
shelf_web_socket:
dependency: transitive
description:
@ -816,14 +816,14 @@ packages:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.2"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "1.1.0"
source_map_stack_trace:
dependency: transitive
description:
@ -935,42 +935,42 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.9"
version: "6.0.6"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.0"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.3"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.1"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.0"
vector_math:
dependency: transitive
description:
@ -991,35 +991,35 @@ packages:
name: wakelock
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.3+3"
version: "0.5.2"
wakelock_macos:
dependency: transitive
description:
name: wakelock_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0+2"
version: "0.1.0+1"
wakelock_platform_interface:
dependency: transitive
description:
name: wakelock_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1+2"
version: "0.2.1+1"
wakelock_web:
dependency: transitive
description:
name: wakelock_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+2"
version: "0.2.0+1"
wakelock_windows:
dependency: transitive
description:
name: wakelock_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0+1"
version: "0.1.0"
watcher:
dependency: transitive
description:
@ -1047,7 +1047,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.7"
version: "2.2.1"
xdg_directories:
dependency: transitive
description:
@ -1070,5 +1070,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.13.4 <3.0.0"
flutter: ">=2.2.3"
dart: ">=2.14.0 <3.0.0"
flutter: ">=2.5.0"

View File

@ -5,7 +5,7 @@ version: 0.1.3+5
environment:
sdk: '>=2.13.4 <3.0.0'
flutter: ">=2.2.3"
flutter: ">=2.5.0"
dependencies:
flutter:
@ -18,7 +18,7 @@ dependencies:
either_option: ^2.0.1-dev.1
equatable: ^2.0.3
fl_chart: ^0.40.0
flutter_bloc: ^7.1.0
flutter_bloc: ^7.3.0
flutter_markdown: ^0.6.0
flutter_secure_storage: ^4.1.0
get_it: ^7.2.0