fdroid
Kherel 2020-12-30 15:13:25 +01:00
parent 91aa2b860b
commit 6613949d12
31 changed files with 1093 additions and 465 deletions

Binary file not shown.

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" fill="white"/>
<path d="M14.72 8.79L10.43 13.09L8.78 11.44C8.69036 11.3353 8.58004 11.2503 8.45597 11.1903C8.33191 11.1302 8.19678 11.0965 8.05906 11.0912C7.92134 11.0859 7.78401 11.1091 7.65568 11.1594C7.52736 11.2096 7.41081 11.2859 7.31335 11.3833C7.2159 11.4808 7.13964 11.5973 7.08937 11.7257C7.03909 11.854 7.01589 11.9913 7.02121 12.1291C7.02652 12.2668 7.06025 12.4019 7.12028 12.526C7.1803 12.65 7.26532 12.7604 7.37 12.85L9.72 15.21C9.81344 15.3027 9.92426 15.376 10.0461 15.4258C10.1679 15.4755 10.2984 15.5008 10.43 15.5C10.6923 15.4989 10.9437 15.3947 11.13 15.21L16.13 10.21C16.2237 10.117 16.2981 10.0064 16.3489 9.88457C16.3997 9.76272 16.4258 9.63201 16.4258 9.5C16.4258 9.36799 16.3997 9.23728 16.3489 9.11542C16.2981 8.99356 16.2237 8.88296 16.13 8.79C15.9426 8.60375 15.6892 8.49921 15.425 8.49921C15.1608 8.49921 14.9074 8.60375 14.72 8.79ZM12 2C10.0222 2 8.08879 2.58649 6.4443 3.6853C4.79981 4.78412 3.51809 6.3459 2.76121 8.17316C2.00433 10.0004 1.8063 12.0111 2.19215 13.9509C2.578 15.8907 3.53041 17.6725 4.92894 19.0711C6.32746 20.4696 8.10929 21.422 10.0491 21.8078C11.9889 22.1937 13.9996 21.9957 15.8268 21.2388C17.6541 20.4819 19.2159 19.2002 20.3147 17.5557C21.4135 15.9112 22 13.9778 22 12C22 10.6868 21.7413 9.38642 21.2388 8.17316C20.7362 6.95991 19.9997 5.85752 19.0711 4.92893C18.1425 4.00035 17.0401 3.26375 15.8268 2.7612C14.6136 2.25866 13.3132 2 12 2V2ZM12 20C10.4178 20 8.87103 19.5308 7.55544 18.6518C6.23985 17.7727 5.21447 16.5233 4.60897 15.0615C4.00347 13.5997 3.84504 11.9911 4.15372 10.4393C4.4624 8.88743 5.22433 7.46196 6.34315 6.34314C7.46197 5.22432 8.88743 4.4624 10.4393 4.15372C11.9911 3.84504 13.5997 4.00346 15.0615 4.60896C16.5233 5.21446 17.7727 6.23984 18.6518 7.55544C19.5308 8.87103 20 10.4177 20 12C20 14.1217 19.1571 16.1566 17.6569 17.6568C16.1566 19.1571 14.1217 20 12 20V20Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
import 'package:selfprivacy/logic/cubit/initializing/initializing_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
@ -20,6 +21,7 @@ class BlocAndProviderConfig extends StatelessWidget {
return MultiProvider(
providers: [
BlocProvider(create: (_) => AppSettingsCubit(isDarkModeOn: isDark)),
BlocProvider(create: (_) => InitializingCubit()),
BlocProvider(create: (_) => ServicesCubit()),
BlocProvider(create: (_) => ProvidersCubit()),
BlocProvider(create: (_) => UsersCubit()),

View File

@ -30,7 +30,6 @@ class BrandColors {
/// ![](https://www.colorhexa.com/0F8849.png)
static const Color green2 = Color(0xFF0F8849);
static get navBackgroundLight => white.withOpacity(0.8);
static get navBackgroundDark => black.withOpacity(0.8);
@ -42,12 +41,16 @@ class BrandColors {
Color(0xFF093CEF),
Color(0xFF14A1CB),
];
static const List<Color> progressGradientColors = [
Color(0xFF093CEF),
Color(0xFF14A1CB),
];
static const List<Color> warningGradientColors = [
Color(0xFFEF4E09),
Color(0xFFEFD135),
];
static const primary = blue;
static const headlineColor = black;
static const inactive = gray2;
@ -58,6 +61,4 @@ class BrandColors {
static const textColor2 = gray1;
static const dividerColor = gray5;
static const warning = red;
}

View File

@ -18,7 +18,7 @@ final headline1Style = GoogleFonts.inter(
);
final headline2Style = GoogleFonts.inter(
fontSize: 24,
fontSize: 30,
fontWeight: NamedFontWeight.extraBold,
color: BrandColors.headlineColor,
);
@ -41,3 +41,19 @@ final body2Style = defaultTextStyle.copyWith(
);
final smallStyle = defaultTextStyle.copyWith(fontSize: 11, height: 1.45);
final linkStyle = defaultTextStyle.copyWith(color: BrandColors.blue);
final progressTextStyleLight = GoogleFonts.inter(
textStyle: TextStyle(
fontSize: 13,
color: BrandColors.textColor1,
),
);
final progressTextStyleDark = GoogleFonts.inter(
textStyle: TextStyle(
fontSize: 13,
color: BrandColors.white,
),
);

View File

@ -0,0 +1,44 @@
import 'dart:async';
import 'package:cubit_form/cubit_form.dart';
import 'package:selfprivacy/logic/cubit/initializing/initializing_cubit.dart';
class HetznerFormCubit extends FormCubit {
HetznerFormCubit(this.initializingCubit) {
var regExp = RegExp(r"\s+|[-!$%^&*()_@+|~=`{}\[\]:" ";<>?,.\/]");
apiKey = FieldCubit(
initalValue: '',
validations: [
RequiredStringValidation('required'),
ValidationModel<String>(
(s) => regExp.hasMatch(s), 'invalid key format'),
LegnthStringValidation(11, 'length is [] shoud be 11')
],
);
super.setFields([apiKey]);
}
@override
FutureOr<void> onSubmit() async {
print(apiKey.state.value);
await Future.delayed(const Duration(milliseconds: 300));
// initializingCubit.setHetznerKey(apiKey.state.value);
}
final InitializingCubit initializingCubit;
FieldCubit<String> apiKey;
}
class LegnthStringValidation extends ValidationModel<String> {
LegnthStringValidation(int length, String errorText)
: super((n) => n.length != length, errorText);
@override
String check(String val) {
var length = val.length;
var errorMassage = this.errorMassage.replaceAll("[]", length.toString());
return test(val) ? errorMassage : null;
}
}

View File

@ -0,0 +1,30 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:selfprivacy/logic/models/config.dart';
import 'package:selfprivacy/logic/models/user.dart';
part 'initializing_state.dart';
class InitializingCubit extends Cubit<InitializingState> {
InitializingCubit() : super(InitialInitializingState());
void setHetznerKey(String key) {
var newCofig = state.appConfig.copyWith(hatzner: key);
emit(InitializingState(newCofig));
}
void setCloudFlare(String cloudFlareKey) {
var newCofig = state.appConfig.copyWith(cloudFlare: cloudFlareKey);
emit(InitializingState(newCofig));
}
void setDomain(String domain) {
var newCofig = state.appConfig.copyWith(domain: domain);
emit(InitializingState(newCofig));
}
void setRootUser(User rootUser) {
var newCofig = state.appConfig.copyWith(rootUser: rootUser);
emit(InitializingState(newCofig));
}
}

View File

@ -0,0 +1,26 @@
part of 'initializing_cubit.dart';
class InitializingState extends Equatable {
const InitializingState(this.appConfig);
final AppConfig appConfig;
@override
List<Object> get props => [appConfig];
bool get isHatznerFilled => appConfig.hatzner != null;
bool get isCloudFlareFilled => appConfig.cloudFlare != null;
bool get isDomainFilled => appConfig.domain != null;
bool get isUserFilled => appConfig.rootUser != null;
bool get isFullyInitilized => _fulfilementList.every((el) => el);
int get progress => _fulfilementList.where((el) => el).length;
List<bool> get _fulfilementList =>
[isHatznerFilled, isCloudFlareFilled, isDomainFilled, isUserFilled];
}
class InitialInitializingState extends InitializingState {
InitialInitializingState() : super(AppConfig.empty());
}

View File

@ -9,7 +9,7 @@ export 'package:provider/provider.dart';
part 'providers_state.dart';
class ProvidersCubit extends Cubit<ProvidersState> {
ProvidersCubit() : super(ProvidersState(all));
ProvidersCubit() : super(InitialProviderState());
void connect(ProviderModel provider) {
var newState = state.updateElement(provider, StateType.stable);
@ -17,11 +17,4 @@ class ProvidersCubit extends Cubit<ProvidersState> {
}
}
final all = ProviderType.values
.map(
(type) => ProviderModel(
state: StateType.uninitialized,
type: type,
),
)
.toList();

View File

@ -23,3 +23,17 @@ class ProvidersState extends Equatable {
@override
List<Object> get props => all;
}
class InitialProviderState extends ProvidersState {
InitialProviderState()
: super(
ProviderType.values
.map(
(type) => ProviderModel(
state: StateType.uninitialized,
type: type,
),
)
.toList(),
);
}

View File

@ -0,0 +1,36 @@
import 'package:equatable/equatable.dart';
import 'package:selfprivacy/logic/models/user.dart';
class AppConfig extends Equatable {
const AppConfig({
this.hatzner,
this.cloudFlare,
this.domain,
this.rootUser,
});
final String hatzner;
final String cloudFlare;
final String domain;
final User rootUser;
factory AppConfig.empty() {
return AppConfig();
}
AppConfig copyWith({
hatzner,
cloudFlare,
domain,
rootUser,
}) =>
AppConfig(
hatzner: hatzner ?? this.hatzner,
cloudFlare: cloudFlare ?? this.cloudFlare,
domain: domain ?? this.domain,
rootUser: rootUser ?? this.rootUser,
);
@override
List<Object> get props => [hatzner, cloudFlare, domain, rootUser];
}

View File

@ -117,7 +117,7 @@ class _RisedButton extends StatelessWidget {
color: BrandColors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
height: 1.5,
height: 1,
),
),
),

View File

@ -1,15 +1,21 @@
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/utils/extensions/elevation_extension.dart';
class BrandCard extends StatelessWidget {
const BrandCard({Key key, this.child}) : super(key: key);
const BrandCard({
Key key,
this.child,
this.isBlocked = false,
}) : super(key: key);
final Widget child;
final bool isBlocked;
@override
Widget build(BuildContext context) {
return Container(
Widget res = Container(
margin: EdgeInsets.only(bottom: 30),
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
@ -23,5 +29,44 @@ class BrandCard extends StatelessWidget {
),
child: child,
);
if (!isBlocked) {
return res;
}
return IgnorePointer(
child: Stack(
children: [
ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.white,
BlendMode.saturation,
),
child: res,
),
Positioned(
top: 0,
left: 0,
right: 0,
bottom: 0,
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white.withOpacity(0.8),
),
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BrandText.h3('Blocked'),
BrandText.h4('finish initializing first')
],
),
),
)
],
),
);
}
}

View File

@ -37,6 +37,8 @@ class BrandIcons {
IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg);
static const IconData refresh_1 =
IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg);
static const IconData check =
IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg);
static const IconData refresh =
IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
static const IconData settings =

View File

@ -0,0 +1,105 @@
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/text_themes.dart';
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
class ProgressBar extends StatefulWidget {
ProgressBar({
Key key,
@required this.steps,
@required this.activeIndex,
}) : super(key: key);
final int activeIndex;
final List<String> steps;
@override
_ProgressBarState createState() => _ProgressBarState();
}
class _ProgressBarState extends State<ProgressBar> {
@override
Widget build(BuildContext context) {
double progress = 1 / widget.steps.length * (widget.activeIndex + 0.3);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BrandText.h4('Progress'),
SizedBox(height: 10),
Row(
children: widget.steps
.asMap()
.map(
(i, step) {
var isActive = i == widget.activeIndex;
var checked = i < widget.activeIndex;
var isDark =
context.watch<AppSettingsCubit>().state.isDarkModeOn;
var style =
isDark ? progressTextStyleDark : progressTextStyleLight;
style = isActive
? style.copyWith(fontWeight: FontWeight.w700)
: style;
return MapEntry(
i,
Expanded(
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: progressTextStyleLight,
children: [
checked
? WidgetSpan(
child: Padding(
padding: const EdgeInsets.only(
bottom: 1, right: 2),
child: Icon(BrandIcons.check, size: 14),
))
: TextSpan(text: '${i + 1}.', style: style),
TextSpan(text: step, style: style)
],
),
),
));
},
)
.values
.toList(),
),
SizedBox(height: 3),
Container(
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: BrandColors.gray4,
borderRadius: BorderRadius.circular(5),
),
child: LayoutBuilder(
builder: (_, constraints) {
return AnimatedContainer(
width: constraints.maxWidth * progress,
height: 5,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: BrandColors.stableGradientColors,
),
),
duration: Duration(
milliseconds: 300,
),
);
},
),
)
],
);
}
}

View File

@ -1,55 +1,153 @@
import 'package:cubit_form/cubit_form.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/config/text_themes.dart';
import 'package:selfprivacy/logic/cubit/forms/initializing/hetzner_form_cubit.dart';
import 'package:selfprivacy/logic/cubit/initializing/initializing_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
import 'package:selfprivacy/logic/models/provider.dart';
import 'package:selfprivacy/logic/models/user.dart';
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
import 'package:selfprivacy/ui/components/brand_card/brand_card.dart';
import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart';
import 'package:selfprivacy/ui/components/brand_span_button/brand_span_button.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/ui/components/progress_bar/progress_bar.dart';
import 'package:selfprivacy/ui/pages/rootRoute.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class InitializingPage extends StatelessWidget {
class InitializingPage extends StatefulWidget {
const InitializingPage({Key key}) : super(key: key);
@override
_InitializingPageState createState() => _InitializingPageState();
}
class _InitializingPageState extends State<InitializingPage> {
PageController pageController = PageController(viewportFraction: 1);
@override
void dispose() {
pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
var cubit = context.watch<ProvidersCubit>();
var connected = cubit.state.connected;
var uninitialized = cubit.state.uninitialized;
return Scaffold(
body: ListView(
padding: brandPagePadding1,
children: [
BrandText.h4('Начало'),
BrandText.h1('SelfPrivacy'),
SizedBox(
height: 10,
),
RichText(
text: TextSpan(
children: [
TextSpan(
text:
'Для устойчивости и приватности требует много учёток. Полная инструкция на ',
style: body2Style,
),
BrandSpanButton.link(
text: 'selfprivacy.org/start',
urlString: 'https://selfprivacy.org/start',
),
],
var cubit = context.watch<InitializingCubit>();
return SafeArea(
child: Scaffold(
body: ListView(
children: [
Padding(
padding: brandPagePadding1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BrandText.h4('Начало'),
BrandText.h1('SelfPrivacy'),
SizedBox(
height: 10,
),
RichText(
text: TextSpan(
children: [
TextSpan(
text:
'Для устойчивости и приватности требует много учёток. Полная инструкция на ',
style: body2Style,
),
BrandSpanButton.link(
text:
'https://selfprivacy.org/posts/getting_started/',
urlString:
'https://selfprivacy.org/posts/getting_started/',
),
],
),
),
SizedBox(height: 10),
ProgressBar(
steps: ['Server', 'DNS', 'Domain', 'User'],
// progress: cubit.state.progress,
activeIndex: cubit.state.progress,
),
SizedBox(height: 20),
],
),
),
),
SizedBox(height: 50),
...connected.map((p) => getCard(context, p)).toList(),
...uninitialized.map((p) => getCard(context, p)).toList(),
],
Container(
height: 500,
child: PageView(
// physics: NeverScrollableScrollPhysics(),
controller: pageController,
children: [
_addCard(_stepOne(cubit)),
_addCard(_stepTwo(cubit)),
_addCard(_stepThree(cubit)),
_addCard(_stepFour(cubit)),
],
),
),
BrandButton.text(title: 'Настрою потом', onPressed: _goToMainPage),
SizedBox(height: 30),
],
),
),
);
}
void _goToMainPage() {
Navigator.of(context).pushAndRemoveUntil(
materialRoute(RootPage()),
(predicate) => predicate == null,
);
}
Widget _stepOne(InitializingCubit initializingCubit) {
return BlocProvider(
create: (context) => HetznerFormCubit(initializingCubit),
child: Builder(builder: (context) {
var formCubit = context.watch<HetznerFormCubit>();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Spacer(),
Image.asset('assets/images/logos/hetzner.png'),
SizedBox(height: 10),
BrandText.h2('Подключите сервер Hetzner'),
SizedBox(height: 10),
BrandText.body2(
'Здесь будут жить наши данные и SelfPrivacy-сервисы'),
Spacer(),
CubitFormTextField(
formFieldCubit: formCubit.apiKey,
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
scrollPadding: EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
hintText: 'Hetzner API Token',
),
),
SizedBox(height: 20),
BrandButton.rised(
onPressed:
formCubit.state.isSubmitting ? null : formCubit.trySubmit,
title: 'Подключить',
),
Spacer(),
SizedBox(height: 10),
BrandButton.text(
onPressed: () => _showModal(context, _HowHetzner()),
title: 'Как получить API Token',
),
],
);
}),
);
}
void _showModal(BuildContext context, Widget widget) {
showModalBottomSheet<void>(
context: context,
@ -61,135 +159,115 @@ class InitializingPage extends StatelessWidget {
);
}
Widget getCard(BuildContext context, ProviderModel model) {
var cubit = context.watch<ProvidersCubit>();
if (model.state == StateType.stable) {
return _MockSuccess(type: model.type);
}
switch (model.type) {
case ProviderType.server:
return BrandCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/hetzner.png'),
SizedBox(height: 10),
BrandText.h2('1. Подключите сервер Hetzner'),
SizedBox(height: 10),
BrandText.body2(
'Здесь будут жить наши данные и SelfPrivacy-сервисы'),
_MockForm(
hintText: 'Hetzner API Token',
length: 2,
onPressed: () {
var provider = cubit.state.all
.firstWhere((p) => p.type == ProviderType.server);
cubit.connect(provider);
},
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () => _showModal(context, _HowHetzner()),
title: 'Как получить API Token',
),
],
Widget _stepTwo(InitializingCubit cubit) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/cloudflare.png'),
BrandText.h2('Подключите CloudFlare DNS'),
SizedBox(height: 10),
BrandText.body2('Для управления DNS вашего домена'),
Expanded(
child: _MockForm(
hintText: 'CloudFlare API Token',
length: 64,
onPressed: () {
cubit.setCloudFlare('key');
pageController.animateToPage(
2,
curve: Curves.easeIn,
duration: Duration(milliseconds: 200),
);
},
),
);
break;
case ProviderType.domain:
return BrandCard(
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () {},
title: 'Как получить API Token',
),
],
);
}
Widget _stepThree(InitializingCubit cubit) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
BrandText.h2('Введите домен:'),
Expanded(
child: _MockForm(
hintText: 'домен',
length: 10,
onPressed: () {
cubit.setDomain('domain');
pageController.animateToPage(
3,
curve: Curves.easeIn,
duration: Duration(milliseconds: 200),
);
},
),
),
SizedBox(height: 10),
BrandButton.text(
onPressed: () => _showModal(context, _HowHetzner()),
title: 'Как получить API Token',
),
],
);
}
Widget _stepFour(InitializingCubit cubit) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/namecheap.png'),
SizedBox(height: 10),
BrandText.h2('2. Настройте домен'),
SizedBox(height: 10),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Зарегистрируйте домен в ',
style: body2Style,
),
BrandSpanButton.link(
text: 'NameCheap',
urlString: 'https://www.namecheap.com',
),
TextSpan(
text:
' или у любого другого регистратора. После этого настройте его на DNS-сервер CloudFlare',
style: body2Style,
),
],
TextField(
decoration: InputDecoration(
hintText: 'нинейм',
),
),
_MockForm(
hintText: 'Домен, например, selfprivacy.org',
submitButtonText: 'Проверить DNS',
length: 2,
onPressed: () {},
SizedBox(height: 10),
TextField(
obscureText: true,
decoration: InputDecoration(
hintText: 'пароль',
),
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () {},
title: 'Как настроить DNS CloudFlare',
),
SizedBox(height: 10),
Image.asset('assets/images/logos/cloudflare.png'),
SizedBox(height: 10),
BrandText.h2('3. Подключите CloudFlare DNS'),
SizedBox(height: 10),
BrandText.body2('Для управления DNS вашего домена'),
_MockForm(
hintText: 'CloudFlare API Token',
length: 2,
Spacer(),
BrandButton.rised(
onPressed: () {
var provider = cubit.state.all
.firstWhere((p) => p.type == ProviderType.domain);
cubit.connect(provider);
cubit.setRootUser(
User(login: 'aa', password: 'bbb'),
);
_goToMainPage();
},
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () {},
title: 'Как получить API Token',
title: 'some text',
),
],
),
);
break;
case ProviderType.backup:
return BrandCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/aws.png'),
SizedBox(height: 10),
BrandText.h2('4. Подключите Amazon AWS для бекапа'),
SizedBox(height: 10),
BrandText.body2(
'IaaS-провайдер, для бесплатного хранения резервных копии ваших данных в зашифрованном виде'),
_MockForm(
hintText: 'Amazon AWS Access Key',
length: 2,
onPressed: () {
var provider = cubit.state.all
.firstWhere((p) => p.type == ProviderType.backup);
cubit.connect(provider);
},
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () {},
title: 'Как получить API Token',
),
],
),
);
}
),
SizedBox(height: 10),
BrandButton.text(
onPressed: () => _showModal(context, _HowHetzner()),
title: 'Как получить API Token',
),
],
);
}
return null;
Widget _addCard(Widget child) {
return Padding(
padding: brandPagePadding2,
child: BrandCard(
child: child,
),
);
}
}
@ -245,40 +323,40 @@ class _HowHetzner extends StatelessWidget {
}
}
class _MockSuccess extends StatelessWidget {
const _MockSuccess({Key key, this.type}) : super(key: key);
// class _MockSuccess extends StatelessWidget {
// const _MockSuccess({Key key, this.type}) : super(key: key);
final ProviderType type;
// final ProviderType type;
@override
Widget build(BuildContext context) {
String text;
// @override
// Widget build(BuildContext context) {
// String text;
switch (type) {
case ProviderType.server:
text = '1. Cервер подключен';
break;
case ProviderType.domain:
text = '2. Домен настроен';
break;
case ProviderType.backup:
text = '3. Резервное копирование настроенно';
break;
}
return BrandCard(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BrandText.h3(text),
Icon(
Icons.check,
color: BrandColors.green1,
),
],
),
);
}
}
// switch (type) {
// case ProviderType.server:
// text = '1. Cервер подключен';
// break;
// case ProviderType.domain:
// text = '2. Домен настроен';
// break;
// case ProviderType.backup:
// text = '3. Резервное копирование настроенно';
// break;
// }
// return BrandCard(
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// BrandText.h3(text),
// Icon(
// Icons.check,
// color: BrandColors.green1,
// ),
// ],
// ),
// );
// }
// }
class _MockForm extends StatefulWidget {
const _MockForm({
@ -322,6 +400,7 @@ class __MockFormState extends State<_MockForm> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 20),
TextField(
@ -350,7 +429,7 @@ class __MockFormState extends State<_MockForm> {
_valid ? null : 'Длинна должна быть ${widget.length} символа',
),
),
SizedBox(height: 20),
Spacer(),
BrandButton.rised(
onPressed: _valid ? onPressed : null,
title: widget.submitButtonText,
@ -359,3 +438,119 @@ class __MockFormState extends State<_MockForm> {
);
}
}
// Widget getCard(BuildContext context, ProviderModel model) {
// var cubit = context.watch<ProvidersCubit>();
// if (model.state == StateType.stable) {
// return _MockSuccess(type: model.type);
// }
// switch (model.type) {
// case ProviderType.server:
// return BrandCard(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Image.asset('assets/images/logos/hetzner.png'),
// SizedBox(height: 10),
// BrandText.h2('1. Подключите сервер Hetzner'),
// SizedBox(height: 10),
// BrandText.body2(
// 'Здесь будут жить наши данные и SelfPrivacy-сервисы'),
// _MockForm(
// hintText: 'Hetzner API Token',
// length: 48,
// onPressed: () {
// var provider = cubit.state.all
// .firstWhere((p) => p.type == ProviderType.server);
// cubit.connect(provider);
// },
// ),
// SizedBox(height: 20),
// BrandButton.text(
// onPressed: () => _showModal(context, _HowHetzner()),
// title: 'Как получить API Token',
// ),
// ],
// ),
// );
// break;
// case ProviderType.domain:
// return BrandCard(
// isBlocked: true,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Image.asset('assets/images/logos/namecheap.png'),
// SizedBox(height: 10),
// BrandText.h2('2. Настройте домен'),
// SizedBox(height: 10),
// RichText(
// text: TextSpan(
// children: [
// TextSpan(
// text: 'Зарегистрируйте домен в ',
// style: body2Style,
// ),
// BrandSpanButton.link(
// text: 'NameCheap',
// urlString: 'https://www.namecheap.com',
// ),
// TextSpan(
// text:
// ' или у любого другого регистратора. После этого настройте его на DNS-сервер CloudFlare',
// style: body2Style,
// ),
// ],
// ),
// ),
// _MockForm(
// hintText: 'Домен, например, selfprivacy.org',
// submitButtonText: 'Проверить DNS',
// length: 2,
// onPressed: () {},
// ),
// SizedBox(height: 20),
// BrandButton.text(
// onPressed: () {},
// title: 'Как настроить DNS CloudFlare',
// ),
// SizedBox(height: 10),
// Image.asset('assets/images/logos/cloudflare.png'),
// SizedBox(height: 10),
// ],
// ),
// );
// break;
// case ProviderType.backup:
// return BrandCard(
// isBlocked: true,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Image.asset('assets/images/logos/aws.png'),
// SizedBox(height: 10),
// BrandText.h2('4. Подключите Amazon AWS для бекапа'),
// SizedBox(height: 10),
// BrandText.body2(
// 'IaaS-провайдер, для бесплатного хранения резервных копии ваших данных в зашифрованном виде'),
// _MockForm(
// hintText: 'Amazon AWS Access Key',
// length: 2,
// onPressed: () {
// var provider = cubit.state.all
// .firstWhere((p) => p.type == ProviderType.backup);
// cubit.connect(provider);
// },
// ),
// SizedBox(height: 20),
// BrandButton.text(
// onPressed: () {},
// title: 'Как получить API Token',
// ),
// ],
// ),
// );
// }
// return null;
// }

View File

@ -5,6 +5,7 @@ import 'package:selfprivacy/ui/components/brand_divider/brand_divider.dart';
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/ui/pages/initializing/initializing.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'about/about.dart';
@ -28,6 +29,11 @@ class MorePage extends StatelessWidget {
child: Column(
children: [
BrandDivider(),
_NavItem(
title: 'Мастер Подключения',
iconData: BrandIcons.settings,
goTo: InitializingPage(),
),
_NavItem(
title: 'Настройки приложения',
iconData: BrandIcons.settings,

View File

@ -1,53 +1,120 @@
import 'package:flutter/material.dart';
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/ui/pages/rootRoute.dart';
import 'package:selfprivacy/ui/pages/initializing/initializing.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class OnboardingPage extends StatelessWidget {
class OnboardingPage extends StatefulWidget {
const OnboardingPage({Key key}) : super(key: key);
@override
_OnboardingPageState createState() => _OnboardingPageState();
}
class _OnboardingPageState extends State<OnboardingPage> {
PageController pageController = PageController();
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 45,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BrandText.h1(
'Онбординг',
),
SizedBox(height: 20),
BrandText.body2(
'Тут рассказ на 1-2 слайда о том, что делает это приложение, какие твои проблемы решает и как (в общем чего ожидать от сервиса).',
),
],
),
),
),
BrandButton.rised(
onPressed: () {
Navigator.of(context)
.pushReplacement(materialRoute(RootPage()));
},
title: 'Приступим!',
)
],
),
body: PageView(
controller: pageController,
children: [
_withPadding(firstPage()),
_withPadding(secondPage()),
],
),
),
);
}
Widget _withPadding(Widget child) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
child: child,
);
}
Widget firstPage() {
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 30),
BrandText.h2(
'Цифровая независимость и приватность, доступная каждому'),
SizedBox(height: 20),
BrandText.body2(
'Почта и мессенджер с открытым исходным кодом на вашем личном сервере под вашим полным контролем.'),
Flexible(
child: Center(
child: Image.asset(
'assets/images/onboarding/onboarding1.png',
),
),
),
BrandButton.rised(
onPressed: () {
pageController.animateToPage(
1,
duration: Duration(milliseconds: 300),
curve: Curves.easeIn,
);
},
title: 'Далее',
),
SizedBox(height: 30),
],
),
);
}
Widget secondPage() {
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height,
),
child: Column(
children: [
SizedBox(height: 30),
BrandText.h2('Для работы понадобятся ваши аккаунты'),
SizedBox(height: 20),
BrandText.body2(
'Для максимальноей приватности и независимости SelfPrivacy не использует свои серверы. \n \n Если у вас нет домена, аккаунтов на Hetzner, AWS и Clouflare, мы поможем их создать и подключить.'),
SizedBox(height: 20),
Center(
child: Image.asset(
'assets/images/onboarding/logos_line.png',
),
),
Flexible(
child: Center(
child: Image.asset(
'assets/images/onboarding/onboarding2.png',
),
),
),
BrandButton.rised(
onPressed: () {
Navigator.of(context)
.pushReplacement(materialRoute(InitializingPage()));
},
title: 'Понял',
),
SizedBox(height: 30),
],
),
);
}
}

View File

@ -1,231 +1,231 @@
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/config/text_themes.dart';
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
import 'package:selfprivacy/ui/components/brand_card/brand_card.dart';
import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart';
import 'package:selfprivacy/ui/components/brand_span_button/brand_span_button.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
// import 'package:flutter/material.dart';
// import 'package:selfprivacy/config/brand_theme.dart';
// import 'package:selfprivacy/config/text_themes.dart';
// import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
// import 'package:selfprivacy/ui/components/brand_card/brand_card.dart';
// import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart';
// import 'package:selfprivacy/ui/components/brand_span_button/brand_span_button.dart';
// import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
class OnboardingPage extends StatelessWidget {
const OnboardingPage({Key key}) : super(key: key);
// class OnboardingPage extends StatelessWidget {
// const OnboardingPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
padding: brandPagePadding1,
children: [
BrandText.h4('Начало'),
BrandText.h1('SelfPrivacy'),
SizedBox(
height: 10,
),
RichText(
text: TextSpan(
children: [
TextSpan(
text:
'Для устойчивости и приватности требует много учёток. Полная инструкция на ',
style: body2Style,
),
BrandSpanButton.link(
text: 'selfprivacy.org/start',
urlString: 'https://selfprivacy.org/start',
),
],
),
),
SizedBox(height: 50),
BrandCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/hetzner.png'),
SizedBox(height: 10),
BrandText.h2('1. Подключите сервер Hetzner'),
SizedBox(height: 10),
BrandText.body2(
'Здесь будут жить наши данные и SelfPrivacy-сервисы'),
_MockForm(
hintText: 'Hetzner API Token',
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () => _showModal(context, _HowHetzner()),
title: 'Как получить API Token',
),
],
),
),
BrandCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/namecheap.png'),
SizedBox(height: 10),
BrandText.h2('2. Настройте домен'),
SizedBox(height: 10),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Зарегистрируйте домен в ',
style: body2Style,
),
BrandSpanButton.link(
text: 'NameCheap',
urlString: 'https://www.namecheap.com',
),
TextSpan(
text:
' или у любого другого регистратора. После этого настройте его на DNS-сервер CloudFlare',
style: body2Style,
),
],
),
),
_MockForm(
hintText: 'Домен, например, selfprivacy.org',
submitButtonText: 'Проверить DNS',
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () {},
title: 'Как настроить DNS CloudFlare',
),
],
),
),
BrandCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/cloudflare.png'),
SizedBox(height: 10),
BrandText.h2('3. Подключите CloudFlare DNS'),
SizedBox(height: 10),
BrandText.body2('Для управления DNS вашего домена'),
_MockForm(
hintText: 'CloudFlare API Token',
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () {},
title: 'Как получить API Token',
),
],
),
),
BrandCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/logos/aws.png'),
SizedBox(height: 10),
BrandText.h2('4. Подключите Amazon AWS для бекапа'),
SizedBox(height: 10),
BrandText.body2(
'IaaS-провайдер, для бесплатного хранения резервных копии ваших данных в зашифрованном виде'),
_MockForm(
hintText: 'Amazon AWS Access Key',
),
SizedBox(height: 20),
BrandButton.text(
onPressed: () {},
title: 'Как получить API Token',
),
],
),
)
],
),
);
}
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// body: ListView(
// padding: brandPagePadding1,
// children: [
// BrandText.h4('Начало'),
// BrandText.h1('SelfPrivacy'),
// SizedBox(
// height: 10,
// ),
// RichText(
// text: TextSpan(
// children: [
// TextSpan(
// text:
// 'Для устойчивости и приватности требует много учёток. Полная инструкция на ',
// style: body2Style,
// ),
// BrandSpanButton.link(
// text: 'selfprivacy.org/start',
// urlString: 'https://selfprivacy.org/start',
// ),
// ],
// ),
// ),
// SizedBox(height: 50),
// BrandCard(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Image.asset('assets/images/logos/hetzner.png'),
// SizedBox(height: 10),
// BrandText.h2('1. Подключите сервер Hetzner'),
// SizedBox(height: 10),
// BrandText.body2(
// 'Здесь будут жить наши данные и SelfPrivacy-сервисы'),
// _MockForm(
// hintText: 'Hetzner API Token',
// ),
// SizedBox(height: 20),
// BrandButton.text(
// onPressed: () => _showModal(context, _HowHetzner()),
// title: 'Как получить API Token',
// ),
// ],
// ),
// ),
// BrandCard(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Image.asset('assets/images/logos/namecheap.png'),
// SizedBox(height: 10),
// BrandText.h2('2. Настройте домен'),
// SizedBox(height: 10),
// RichText(
// text: TextSpan(
// children: [
// TextSpan(
// text: 'Зарегистрируйте домен в ',
// style: body2Style,
// ),
// BrandSpanButton.link(
// text: 'NameCheap',
// urlString: 'https://www.namecheap.com',
// ),
// TextSpan(
// text:
// ' или у любого другого регистратора. После этого настройте его на DNS-сервер CloudFlare',
// style: body2Style,
// ),
// ],
// ),
// ),
// _MockForm(
// hintText: 'Домен, например, selfprivacy.org',
// submitButtonText: 'Проверить DNS',
// ),
// SizedBox(height: 20),
// BrandButton.text(
// onPressed: () {},
// title: 'Как настроить DNS CloudFlare',
// ),
// ],
// ),
// ),
// BrandCard(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Image.asset('assets/images/logos/cloudflare.png'),
// SizedBox(height: 10),
// BrandText.h2('3. Подключите CloudFlare DNS'),
// SizedBox(height: 10),
// BrandText.body2('Для управления DNS вашего домена'),
// _MockForm(
// hintText: 'CloudFlare API Token',
// ),
// SizedBox(height: 20),
// BrandButton.text(
// onPressed: () {},
// title: 'Как получить API Token',
// ),
// ],
// ),
// ),
// BrandCard(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Image.asset('assets/images/logos/aws.png'),
// SizedBox(height: 10),
// BrandText.h2('4. Подключите Amazon AWS для бекапа'),
// SizedBox(height: 10),
// BrandText.body2(
// 'IaaS-провайдер, для бесплатного хранения резервных копии ваших данных в зашифрованном виде'),
// _MockForm(
// hintText: 'Amazon AWS Access Key',
// ),
// SizedBox(height: 20),
// BrandButton.text(
// onPressed: () {},
// title: 'Как получить API Token',
// ),
// ],
// ),
// )
// ],
// ),
// );
// }
void _showModal(BuildContext context, Widget widget) {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (BuildContext context) {
return widget;
},
);
}
}
// void _showModal(BuildContext context, Widget widget) {
// showModalBottomSheet<void>(
// context: context,
// isScrollControlled: true,
// backgroundColor: Colors.transparent,
// builder: (BuildContext context) {
// return widget;
// },
// );
// }
// }
class _HowHetzner extends StatelessWidget {
const _HowHetzner({
Key key,
}) : super(key: key);
// class _HowHetzner extends StatelessWidget {
// const _HowHetzner({
// Key key,
// }) : super(key: key);
@override
Widget build(BuildContext context) {
return BrandModalSheet(
child: Padding(
padding: brandPagePadding2,
child: Column(
children: [
SizedBox(height: 40),
BrandText.h2('Как получить Hetzner API Token'),
SizedBox(height: 20),
RichText(
text: TextSpan(
children: [
TextSpan(
text: '1 Переходим по ссылке ',
style: body1Style,
),
BrandSpanButton.link(
text: 'hetzner.com/sdfsdfsdfsdf',
urlString: 'https://hetzner.com/sdfsdfsdfsdf',
),
TextSpan(
text: '''
// @override
// Widget build(BuildContext context) {
// return BrandModalSheet(
// child: Padding(
// padding: brandPagePadding2,
// child: Column(
// children: [
// SizedBox(height: 40),
// BrandText.h2('Как получить Hetzner API Token'),
// SizedBox(height: 20),
// RichText(
// text: TextSpan(
// children: [
// TextSpan(
// text: '1 Переходим по ссылке ',
// style: body1Style,
// ),
// BrandSpanButton.link(
// text: 'hetzner.com/sdfsdfsdfsdf',
// urlString: 'https://hetzner.com/sdfsdfsdfsdf',
// ),
// TextSpan(
// text: '''
2 Заходим в созданный нами проект. Если такового - нет, значит создаём.
// 2 Заходим в созданный нами проект. Если такового - нет, значит создаём.
3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний Security (с иконкой ключика).
// 3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний Security (с иконкой ключика).
4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.
// 4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.
5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку.
// 5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку.
6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет.
// 6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет.
''',
style: body1Style,
),
],
),
),
],
),
),
);
}
}
// ''',
// style: body1Style,
// ),
// ],
// ),
// ),
// ],
// ),
// ),
// );
// }
// }
class _MockForm extends StatelessWidget {
const _MockForm({
Key key,
@required this.hintText,
this.submitButtonText = 'Подключить',
}) : super(key: key);
// class _MockForm extends StatelessWidget {
// const _MockForm({
// Key key,
// @required this.hintText,
// this.submitButtonText = 'Подключить',
// }) : super(key: key);
final String hintText;
final String submitButtonText;
// final String hintText;
// final String submitButtonText;
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(height: 20),
TextField(decoration: InputDecoration(hintText: hintText)),
SizedBox(height: 20),
BrandButton.rised(onPressed: () {}, title: submitButtonText),
],
);
}
}
// @override
// Widget build(BuildContext context) {
// return Column(
// children: [
// SizedBox(height: 20),
// TextField(decoration: InputDecoration(hintText: hintText)),
// SizedBox(height: 20),
// BrandButton.rised(onPressed: () {}, title: submitButtonText),
// ],
// );
// }
// }

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/initializing/initializing_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
import 'package:selfprivacy/logic/models/provider.dart';
import 'package:selfprivacy/logic/models/state_types.dart';
@ -8,7 +9,7 @@ import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:selfprivacy/ui/components/brand_modal_sheet/brand_modal_sheet.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
import 'package:selfprivacy/ui/pages/providers/settings/setting.dart';
import 'package:selfprivacy/ui/pages/providers/settings/settings.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
class ProvidersPage extends StatefulWidget {
@ -47,6 +48,8 @@ class _Card extends StatelessWidget {
String title;
String message;
String stableText;
var isFullyInitilized =
context.watch<InitializingCubit>().state.isFullyInitilized;
switch (provider.type) {
case ProviderType.server:
@ -77,6 +80,7 @@ class _Card extends StatelessWidget {
},
),
child: BrandCard(
isBlocked: !isFullyInitilized,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

View File

@ -1,5 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/cubit/initializing/initializing_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
import 'package:selfprivacy/ui/components/brand_tab_bar/brand_tab_bar.dart';
import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
@ -8,9 +9,6 @@ import 'package:selfprivacy/ui/pages/providers/providers.dart';
import 'package:selfprivacy/ui/pages/services/services.dart';
import 'package:selfprivacy/ui/pages/users/users.dart';
import 'initializing/initializing.dart';
class RootPage extends StatefulWidget {
const RootPage({Key key}) : super(key: key);
@ -36,17 +34,17 @@ class _RootPageState extends State<RootPage>
@override
Widget build(BuildContext context) {
var isReady =
context.select((ProvidersCubit bloc) => bloc.state.isFullyInitialized);
var isUserFilled =
context.watch<InitializingCubit>().state.isFullyInitilized;
return SafeArea(
child: Scaffold(
body: TabBarView(
controller: tabController,
children: [
isReady ? ProvidersPage() : InitializingPage(),
isReady ? ServicesPage() : _NotReady(),
isReady ? UsersPage() : _NotReady(),
ProvidersPage(),
ServicesPage(),
isUserFilled ? UsersPage() : _NotReady(),
MorePage(),
],
),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_theme.dart';
import 'package:selfprivacy/logic/cubit/initializing/initializing_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
@ -52,6 +53,7 @@ class _Card extends StatelessWidget {
String title;
IconData iconData;
String description;
var isFullyInitilized = context.watch<InitializingCubit>().state.isFullyInitilized;
switch (service.type) {
case ServiceTypes.messanger:
@ -83,6 +85,7 @@ class _Card extends StatelessWidget {
break;
}
return BrandCard(
isBlocked: !isFullyInitilized,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -102,8 +105,7 @@ class _Card extends StatelessWidget {
context.read<ServicesCubit>().connect(service);
})
],
if (service.state == StateType.stable)
BrandText.body2('Подключен'),
if (service.state == StateType.stable) BrandText.body2('Подключен'),
],
),
);

View File

@ -28,7 +28,7 @@ packages:
name: bloc
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.0"
version: "6.1.1"
boolean_selector:
dependency: transitive
description:
@ -78,6 +78,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
cubit_form:
dependency: "direct main"
description:
name: cubit_form
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.14"
cupertino_icons:
dependency: "direct main"
description:
@ -92,6 +99,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.3"
email_validator:
dependency: transitive
description:
name: email_validator
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.6"
equatable:
dependency: "direct main"
description:
@ -189,6 +203,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.1"
mask_text_input_formatter:
dependency: transitive
description:
name: mask_text_input_formatter
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
matcher:
dependency: transitive
description:
@ -343,6 +364,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+3"
shortuuid:
dependency: transitive
description:
name: shortuuid
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
sky_engine:
dependency: transitive
description: flutter
@ -439,6 +467,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+3"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.2"
vector_math:
dependency: transitive
description:

View File

@ -9,6 +9,7 @@ environment:
dependencies:
flutter:
sdk: flutter
cubit_form: ^0.0.14
cupertino_icons: ^1.0.0
easy_localization: ^2.3.3
equatable: ^1.2.5
@ -31,6 +32,8 @@ flutter_icons:
flutter:
uses-material-design: true
assets:
- assets/images/
- assets/images/onboarding/
- assets/images/logos/
- assets/translations/
fonts: