mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-29 12:16:55 +00:00
finish
This commit is contained in:
parent
21611e63c7
commit
f53ad044c1
|
@ -19,12 +19,14 @@
|
|||
"connect": "Connect",
|
||||
"domain": "Domain",
|
||||
"saving": "Saving..",
|
||||
"nickname": "nickname",
|
||||
"nickname": "Nickname",
|
||||
"loading": "Loading...",
|
||||
"later": "I will setup it later",
|
||||
"reset": "Reset",
|
||||
"details": "Details",
|
||||
"no_data": "No data"
|
||||
"no_data": "No data",
|
||||
"wait": "Wait",
|
||||
"remove": "Remove"
|
||||
},
|
||||
"more": {
|
||||
"_comment": "'More' tab",
|
||||
|
@ -191,7 +193,6 @@
|
|||
"23": "Enter a nickname and strong password",
|
||||
"finish": "Everything is initialized",
|
||||
"checks": "Checks have been completed \n{} ouf of {}"
|
||||
|
||||
},
|
||||
"modals": {
|
||||
"_comment": "messages in modals",
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
"later": "Настрою потом",
|
||||
"reset": "Reset",
|
||||
"details": "Детальная информация",
|
||||
"no_data": "Нет данных"
|
||||
"no_data": "Нет данных",
|
||||
"wait": "Ожидайте",
|
||||
"remove": "Удалить"
|
||||
},
|
||||
"more": {
|
||||
"_comment": "вкладка еще",
|
||||
|
|
|
@ -6,6 +6,8 @@ PODS:
|
|||
- Flutter
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher (0.0.1):
|
||||
|
@ -18,6 +20,7 @@ DEPENDENCIES:
|
|||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- package_info (from `.symlinks/plugins/package_info/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
||||
|
@ -31,6 +34,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/package_info/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences:
|
||||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
url_launcher:
|
||||
|
@ -43,6 +48,7 @@ SPEC CHECKSUMS:
|
|||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
||||
|
|
|
@ -17,7 +17,7 @@ class BlocAndProviderConfig extends StatelessWidget {
|
|||
// SchedulerBinding.instance.window.platformBrightness;
|
||||
// var isDark = platformBrightness == Brightness.dark;
|
||||
var isDark = false;
|
||||
|
||||
var usersCubit = UsersCubit();
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
|
@ -31,8 +31,8 @@ class BlocAndProviderConfig extends StatelessWidget {
|
|||
create: (_) => AppConfigCubit()..load(),
|
||||
),
|
||||
BlocProvider(create: (_) => ProvidersCubit()),
|
||||
BlocProvider(create: (_) => UsersCubit()),
|
||||
BlocProvider(create: (_) => JobsCubit()),
|
||||
BlocProvider(create: (_) => usersCubit..load(), lazy: false),
|
||||
BlocProvider(create: (_) => JobsCubit(usersCubit)),
|
||||
],
|
||||
child: child,
|
||||
);
|
||||
|
|
|
@ -19,6 +19,8 @@ class HiveConfig {
|
|||
Hive.registerAdapter(HetznerDataBaseAdapter());
|
||||
|
||||
await Hive.openBox(BNames.appSettings);
|
||||
await Hive.openBox<User>(BNames.users);
|
||||
|
||||
var cipher = HiveAesCipher(await getEncriptedKey());
|
||||
|
||||
await Hive.openBox(BNames.appConfig, encryptionCipher: cipher);
|
||||
|
@ -42,6 +44,7 @@ class BNames {
|
|||
static String appConfig = 'appConfig';
|
||||
static String isDarkModeOn = 'isDarkModeOn';
|
||||
static String isOnbordingShowing = 'isOnbordingShowing';
|
||||
static String users = 'users';
|
||||
|
||||
static String appSettings = 'appSettings';
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ class HetznerApi extends ApiMap {
|
|||
var dbId = dbCreateResponse.data['volume']['id'];
|
||||
|
||||
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-20.09 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} HASHED_PASSWORD=${rootUser.hashPassword.hash} SALT=${rootUser.hashPassword.salt} 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/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-21.05 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} HASHED_PASSWORD=${rootUser.hashPassword.hash} SALT=${rootUser.hashPassword.salt} CF_TOKEN=$cloudFlareKey DB_PASSWORD=$dbPassword bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":true, "location": "fsn1"}'''
|
||||
);
|
||||
|
||||
Response serverCreateResponse = await client.post(
|
||||
|
|
|
@ -51,8 +51,9 @@ class ServerApi extends ApiMap {
|
|||
'/createUser',
|
||||
options: Options(
|
||||
headers: {
|
||||
"X-Username": user.login,
|
||||
"X-Password": user.password,
|
||||
"X-User": user.login,
|
||||
"X-Password":
|
||||
'\$6\$${user.hashPassword.salt}\$${user.hashPassword.hash}',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -68,4 +69,24 @@ class ServerApi extends ApiMap {
|
|||
|
||||
String get rootAddress =>
|
||||
throw UnimplementedError('not used in with implementation');
|
||||
|
||||
Future<bool> apply() async {
|
||||
bool res;
|
||||
Response response;
|
||||
|
||||
var client = await getClient();
|
||||
try {
|
||||
response = await client.get(
|
||||
'/apply',
|
||||
);
|
||||
|
||||
res = response.statusCode == HttpStatus.ok;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
res = false;
|
||||
}
|
||||
|
||||
close(client);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,53 @@
|
|||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/config/get_it_config.dart';
|
||||
import 'package:selfprivacy/logic/api_maps/server.dart';
|
||||
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
|
||||
import 'package:selfprivacy/logic/models/jobs/job.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:selfprivacy/logic/models/user.dart';
|
||||
export 'package:provider/provider.dart';
|
||||
|
||||
part 'jobs_state.dart';
|
||||
|
||||
class JobsCubit extends Cubit<JobsState> {
|
||||
JobsCubit() : super(JobsState.emtpy());
|
||||
JobsCubit(this.usersCubit) : super(JobsStateEmpty());
|
||||
|
||||
final api = ServerApi();
|
||||
final UsersCubit usersCubit;
|
||||
|
||||
void addJob(Job job) {
|
||||
final newState = state.addJob(job);
|
||||
emit(newState);
|
||||
var newJobsList = <Job>[];
|
||||
if (state is JobsStateWithJobs) {
|
||||
newJobsList.addAll((state as JobsStateWithJobs).jobList);
|
||||
}
|
||||
newJobsList.add(job);
|
||||
emit(JobsStateWithJobs(newJobsList));
|
||||
}
|
||||
|
||||
void removeJob(String id) {
|
||||
final newState = state.removeById(id);
|
||||
final newState = (state as JobsStateWithJobs).removeById(id);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
Future<void> applyAll() async {
|
||||
for (var job in state.jobList) {
|
||||
if (job is CreateUserJob) {
|
||||
// await api.createUser(job.user);
|
||||
if (state is JobsStateWithJobs) {
|
||||
var jobs = (state as JobsStateWithJobs).jobList;
|
||||
emit(JobsStateLoading());
|
||||
|
||||
var newUsers = <User>[];
|
||||
for (var job in jobs) {
|
||||
if (job is CreateUserJob) {
|
||||
newUsers.add(job.user);
|
||||
await api.createUser(job.user);
|
||||
}
|
||||
}
|
||||
|
||||
usersCubit.addUsers(newUsers);
|
||||
await api.apply();
|
||||
|
||||
emit(JobsStateEmpty());
|
||||
|
||||
getIt<NavigationService>().navigator!.pop();
|
||||
}
|
||||
emit(JobsState.emtpy());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
part of 'jobs_cubit.dart';
|
||||
|
||||
class JobsState extends Equatable {
|
||||
const JobsState(this.jobList);
|
||||
abstract class JobsState extends Equatable {
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class JobsStateLoading extends JobsState {}
|
||||
|
||||
class JobsStateEmpty extends JobsState {}
|
||||
|
||||
class JobsStateWithJobs extends JobsState {
|
||||
JobsStateWithJobs(this.jobList);
|
||||
final List<Job> jobList;
|
||||
|
||||
static JobsState emtpy() => JobsState([]);
|
||||
|
||||
bool get isEmpty => jobList.isEmpty;
|
||||
|
||||
JobsState addJob(Job job) {
|
||||
var newJobsList = [...jobList];
|
||||
newJobsList.add(job);
|
||||
return JobsState(newJobsList);
|
||||
}
|
||||
|
||||
JobsState removeById(String id) {
|
||||
var newJobsList = jobList.where((element) => element.id != id).toList();
|
||||
return JobsState(newJobsList);
|
||||
|
||||
if (newJobsList.isEmpty) {
|
||||
return JobsStateEmpty();
|
||||
}
|
||||
return JobsStateWithJobs(newJobsList);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => jobList;
|
||||
List<Object?> get props => jobList;
|
||||
}
|
||||
|
|
|
@ -1,23 +1,35 @@
|
|||
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/models/user.dart';
|
||||
export 'package:provider/provider.dart';
|
||||
|
||||
part 'users_state.dart';
|
||||
|
||||
class UsersCubit extends Cubit<UsersState> {
|
||||
UsersCubit() : super(UsersState([]));
|
||||
UsersCubit() : super(UsersState(<User>[]));
|
||||
Box<User> box = Hive.box<User>(BNames.users);
|
||||
|
||||
void addUser(User user) {
|
||||
var users = [...state.users];
|
||||
users.add(user);
|
||||
|
||||
emit(UsersState(users));
|
||||
void load() async {
|
||||
var loadedUsers = box.values.toList();
|
||||
if (loadedUsers.isNotEmpty) {
|
||||
emit(UsersState(loadedUsers));
|
||||
}
|
||||
}
|
||||
|
||||
void remove(User? user) {
|
||||
void addUsers(List<User> users) async {
|
||||
var newUserList = <User>[...state.users, ...users];
|
||||
|
||||
await box.addAll(users);
|
||||
emit(UsersState(newUserList));
|
||||
}
|
||||
|
||||
void remove(User user) async {
|
||||
var users = [...state.users];
|
||||
var index = users.indexOf(user);
|
||||
users.remove(user);
|
||||
await box.deleteAt(index);
|
||||
|
||||
emit(UsersState(users));
|
||||
}
|
||||
|
|
|
@ -23,40 +23,41 @@ void main() async {
|
|||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await EasyLocalization.ensureInitialized();
|
||||
|
||||
runApp(
|
||||
Localization(
|
||||
child: BlocAndProviderConfig(
|
||||
child: MyApp(),
|
||||
),
|
||||
),
|
||||
);
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppSettingsState appSettings = context.watch<AppSettingsCubit>().state;
|
||||
return Localization(
|
||||
child: BlocAndProviderConfig(
|
||||
child: Builder(builder: (context) {
|
||||
var appSettings = context.watch<AppSettingsCubit>().state;
|
||||
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
|
||||
child: MaterialApp(
|
||||
navigatorKey: getIt.get<NavigationService>().navigatorKey,
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: context.locale,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'SelfPrivacy',
|
||||
theme: appSettings.isDarkModeOn ? darkTheme : ligtTheme,
|
||||
home: appSettings.isOnbordingShowing
|
||||
? OnboardingPage(nextPage: InitializingPage())
|
||||
: RootPage(),
|
||||
builder: (BuildContext context, Widget? widget) {
|
||||
Widget error = Text('...rendering error...');
|
||||
if (widget is Scaffold || widget is Navigator)
|
||||
error = Scaffold(body: Center(child: error));
|
||||
ErrorWidget.builder = (FlutterErrorDetails errorDetails) => error;
|
||||
return widget!;
|
||||
},
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
|
||||
child: MaterialApp(
|
||||
navigatorKey: getIt.get<NavigationService>().navigatorKey,
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: context.locale,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'SelfPrivacy',
|
||||
theme: appSettings.isDarkModeOn ? darkTheme : ligtTheme,
|
||||
home: appSettings.isOnbordingShowing
|
||||
? OnboardingPage(nextPage: InitializingPage())
|
||||
: RootPage(),
|
||||
builder: (BuildContext context, Widget? widget) {
|
||||
Widget error = Text('...rendering error...');
|
||||
if (widget is Scaffold || widget is Navigator)
|
||||
error = Scaffold(body: Center(child: error));
|
||||
ErrorWidget.builder =
|
||||
(FlutterErrorDetails errorDetails) => error;
|
||||
return widget!;
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
21
lib/ui/components/brand_loader/brand_loader.dart
Normal file
21
lib/ui/components/brand_loader/brand_loader.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class BrandLoader {
|
||||
static horizontal() => _HorizontalLoader();
|
||||
}
|
||||
|
||||
class _HorizontalLoader extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('basis.wait'.tr()),
|
||||
SizedBox(height: 10),
|
||||
LinearProgressIndicator(minHeight: 3),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/text_themes.dart';
|
||||
export 'package:selfprivacy/utils/extensions/text_extensions.dart';
|
||||
|
||||
enum TextType {
|
||||
h1, // right now only at onboarding and opened providers
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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/users/users_cubit.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_loader/brand_loader.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
|
||||
|
||||
class JobsContent extends StatelessWidget {
|
||||
|
@ -12,55 +15,71 @@ class JobsContent extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var jobs = context.watch<JobsCubit>().state;
|
||||
return ListView(
|
||||
padding: paddingH15V0,
|
||||
children: [
|
||||
SizedBox(height: 15),
|
||||
Center(
|
||||
child: BrandText.h2(
|
||||
'jobs.title'.tr(),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
if (jobs.isEmpty) BrandText.body1('jobs.empty'.tr()),
|
||||
if (!jobs.isEmpty) ...[
|
||||
...jobs.jobList
|
||||
.map(
|
||||
(j) => Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BrandCards.small(
|
||||
child: Row(
|
||||
children: [
|
||||
BrandText.body1(j.title),
|
||||
],
|
||||
return BlocBuilder<JobsCubit, JobsState>(
|
||||
builder: (context, state) {
|
||||
late final List<Widget> widgets;
|
||||
if (state is JobsStateEmpty) {
|
||||
widgets = [
|
||||
SizedBox(height: 80),
|
||||
Center(child: BrandText.body1('jobs.empty'.tr())),
|
||||
];
|
||||
} else if (state is JobsStateLoading) {
|
||||
widgets = [
|
||||
SizedBox(height: 80),
|
||||
BrandLoader.horizontal(),
|
||||
];
|
||||
} else if (state is JobsStateWithJobs) {
|
||||
widgets = [
|
||||
...state.jobList
|
||||
.map(
|
||||
(j) => Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BrandCards.small(
|
||||
child: Row(
|
||||
children: [
|
||||
BrandText.body1(j.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: BrandColors.red1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
SizedBox(width: 10),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: BrandColors.red1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () =>
|
||||
context.read<JobsCubit>().removeJob(j.id),
|
||||
child: Text('basis.remove'.tr()),
|
||||
),
|
||||
onPressed: () =>
|
||||
context.read<JobsCubit>().removeJob(j.id),
|
||||
child: Text('Remove'),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.rised(
|
||||
onPressed: () => context.read<JobsCubit>().applyAll(),
|
||||
text: 'jobs.start'.tr(),
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.rised(
|
||||
onPressed: () => context.read<JobsCubit>().applyAll(),
|
||||
text: 'jobs.start'.tr(),
|
||||
),
|
||||
];
|
||||
}
|
||||
return ListView(
|
||||
padding: paddingH15V0,
|
||||
children: [
|
||||
SizedBox(height: 15),
|
||||
Center(
|
||||
child: BrandText.h2(
|
||||
'jobs.title'.tr(),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
...widgets
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,20 +42,18 @@ class _BrandFlashButtonState extends State<_BrandFlashButton>
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
late bool wasPrevStateIsEmpty;
|
||||
bool wasPrevStateIsEmpty = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var hasNoJobs = context.watch<JobsCubit>().state.isEmpty;
|
||||
wasPrevStateIsEmpty = hasNoJobs;
|
||||
var icon = hasNoJobs ? Ionicons.flash_outline : Ionicons.flash;
|
||||
|
||||
return BlocListener<JobsCubit, JobsState>(
|
||||
listener: (context, state) {
|
||||
if (wasPrevStateIsEmpty && state.jobList.isNotEmpty) {
|
||||
if (wasPrevStateIsEmpty && state is! JobsStateEmpty) {
|
||||
wasPrevStateIsEmpty = false;
|
||||
_animationController.forward();
|
||||
} else if (!wasPrevStateIsEmpty && state.jobList.isEmpty) {
|
||||
} else if (!wasPrevStateIsEmpty && state is JobsStateEmpty) {
|
||||
wasPrevStateIsEmpty = true;
|
||||
|
||||
_animationController.reverse();
|
||||
}
|
||||
},
|
||||
|
@ -73,6 +71,7 @@ class _BrandFlashButtonState extends State<_BrandFlashButton>
|
|||
animation: _colorTween,
|
||||
builder: (context, child) {
|
||||
var v = _animationController.value;
|
||||
var icon = v > 0.5 ? Ionicons.flash : Ionicons.flash_outline;
|
||||
return Transform.scale(
|
||||
scale: 1 + (v < 0.5 ? v : 1 - v) * 2,
|
||||
child: Icon(
|
||||
|
|
|
@ -82,7 +82,6 @@ class CpuChart extends StatelessWidget {
|
|||
double appliedInterval,
|
||||
double value,
|
||||
) {
|
||||
print(value);
|
||||
if (value < 0) {
|
||||
return false;
|
||||
} else if (value == 0) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
part of 'users.dart';
|
||||
|
||||
class _User extends StatelessWidget {
|
||||
const _User({Key? key, this.user}) : super(key: key);
|
||||
const _User({Key? key, required this.user}) : super(key: key);
|
||||
|
||||
final User? user;
|
||||
final User user;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
|
@ -24,12 +24,12 @@ class _User extends StatelessWidget {
|
|||
width: 17,
|
||||
height: 17,
|
||||
decoration: BoxDecoration(
|
||||
color: user!.color,
|
||||
color: user.color,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 20),
|
||||
BrandText.h4(user!.login),
|
||||
BrandText.h4(user.login),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -3,10 +3,10 @@ part of 'users.dart';
|
|||
class _UserDetails extends StatelessWidget {
|
||||
const _UserDetails({
|
||||
Key? key,
|
||||
this.user,
|
||||
required this.user,
|
||||
}) : super(key: key);
|
||||
|
||||
final User? user;
|
||||
final User user;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -23,7 +23,7 @@ class _UserDetails extends StatelessWidget {
|
|||
Container(
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
color: user!.color,
|
||||
color: user.color,
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(20),
|
||||
),
|
||||
|
@ -116,7 +116,7 @@ class _UserDetails extends StatelessWidget {
|
|||
horizontal: 15,
|
||||
),
|
||||
child: BrandText.h1(
|
||||
user!.login,
|
||||
user.login,
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)),
|
||||
|
@ -133,14 +133,14 @@ class _UserDetails extends StatelessWidget {
|
|||
Container(
|
||||
height: 40,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: BrandText.h4('${user!.login}@$domainName'),
|
||||
child: BrandText.h4('${user.login}@$domainName'),
|
||||
),
|
||||
SizedBox(height: 14),
|
||||
BrandText.small('basis.password'.tr()),
|
||||
Container(
|
||||
height: 40,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: BrandText.h4(user!.password),
|
||||
child: BrandText.h4(user.password),
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
BrandDivider(),
|
||||
|
@ -148,7 +148,10 @@ class _UserDetails extends StatelessWidget {
|
|||
BrandButton.emptyWithIconText(
|
||||
title: 'users.send_regisration_data'.tr(),
|
||||
icon: Icon(BrandIcons.share),
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
Share.share(
|
||||
'login: ${user.login}, password: ${user.password}');
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
|
|||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:selfprivacy/ui/helpers/modals.dart';
|
||||
import 'package:selfprivacy/utils/ui_helpers.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
part 'fab.dart';
|
||||
part 'new_user.dart';
|
||||
|
@ -33,7 +34,6 @@ class UsersPage extends StatelessWidget {
|
|||
var isReady = context.watch<AppConfigCubit>().state.isFullyInitilized;
|
||||
final users = usersCubitState.users;
|
||||
final isEmpty = usersCubitState.isEmpty;
|
||||
|
||||
Widget child;
|
||||
|
||||
if (!isReady) {
|
||||
|
@ -48,7 +48,7 @@ class UsersPage extends StatelessWidget {
|
|||
)
|
||||
: ListView(
|
||||
children: [
|
||||
...users.map((user) => _User(user: user)),
|
||||
...users.map((user) => _User(user: user)).toList(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
51
lib/utils/extensions/text_extensions.dart
Normal file
51
lib/utils/extensions/text_extensions.dart
Normal file
|
@ -0,0 +1,51 @@
|
|||
import 'dart:ui';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
extension TextExtension on Text {
|
||||
Text withColor(Color color) => Text(
|
||||
data!,
|
||||
key: this.key,
|
||||
strutStyle: this.strutStyle,
|
||||
textAlign: this.textAlign,
|
||||
textDirection: this.textDirection,
|
||||
locale: this.locale,
|
||||
softWrap: this.softWrap,
|
||||
overflow: this.overflow,
|
||||
textScaleFactor: this.textScaleFactor,
|
||||
maxLines: this.maxLines,
|
||||
semanticsLabel: this.semanticsLabel,
|
||||
textWidthBasis: textWidthBasis ?? this.textWidthBasis,
|
||||
style: this.style != null
|
||||
? this.style!.copyWith(color: color)
|
||||
: TextStyle(color: color),
|
||||
);
|
||||
|
||||
Text copyWith({
|
||||
Key? key,
|
||||
StrutStyle? strutStyle,
|
||||
TextAlign? textAlign,
|
||||
TextDirection? textDirection,
|
||||
Locale? locale,
|
||||
bool? softWrap,
|
||||
TextOverflow? overflow,
|
||||
double? textScaleFactor,
|
||||
int? maxLines,
|
||||
String? semanticsLabel,
|
||||
TextWidthBasis? textWidthBasis,
|
||||
TextStyle? style,
|
||||
}) {
|
||||
return Text(data!,
|
||||
key: key ?? this.key,
|
||||
strutStyle: strutStyle ?? this.strutStyle,
|
||||
textAlign: textAlign ?? this.textAlign,
|
||||
textDirection: textDirection ?? this.textDirection,
|
||||
locale: locale ?? this.locale,
|
||||
softWrap: softWrap ?? this.softWrap,
|
||||
overflow: overflow ?? this.overflow,
|
||||
textScaleFactor: textScaleFactor ?? this.textScaleFactor,
|
||||
maxLines: maxLines ?? this.maxLines,
|
||||
semanticsLabel: semanticsLabel ?? this.semanticsLabel,
|
||||
textWidthBasis: textWidthBasis ?? this.textWidthBasis,
|
||||
style: style != null ? this.style?.merge(style) ?? style : this.style);
|
||||
}
|
||||
}
|
42
pubspec.lock
42
pubspec.lock
|
@ -651,6 +651,48 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
share_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: share_plus
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
share_plus_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
share_plus_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
share_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
share_plus_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
share_plus_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
shared_preferences:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -31,6 +31,7 @@ dependencies:
|
|||
package_info: ^2.0.0
|
||||
pretty_dio_logger: ^1.1.1
|
||||
provider: ^5.0.0
|
||||
share_plus: ^2.1.4
|
||||
unicons: ^1.0.2
|
||||
url_launcher: ^6.0.2
|
||||
wakelock: ^0.5.0+2
|
||||
|
|
Loading…
Reference in a new issue