mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-27 11:16:45 +00:00
add service page
This commit is contained in:
parent
cd02c75e2f
commit
90df52e895
Binary file not shown.
21
lib/config/bloc_config.dart
Normal file
21
lib/config/bloc_config.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
|
||||
|
||||
class BlocAndProviderConfig extends StatelessWidget {
|
||||
const BlocAndProviderConfig({Key key, this.child}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
BlocProvider<ServicesCubit>(
|
||||
create: (BuildContext context) => ServicesCubit(),
|
||||
),
|
||||
],
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -28,4 +28,17 @@ class BrandColors {
|
|||
static const textColor2 = gray1;
|
||||
|
||||
static get navBackground => white.withOpacity(0.8);
|
||||
|
||||
static const List<Color> uninitializedGradientColors = [
|
||||
Color(0xFF555555),
|
||||
Color(0xFFABABAB),
|
||||
];
|
||||
static const List<Color> stableGradientColors = [
|
||||
Color(0xFF093CEF),
|
||||
Color(0xFF14A1CB),
|
||||
];
|
||||
static const List<Color> warningGradientColors = [
|
||||
Color(0xFFEF4E09),
|
||||
Color(0xFFEFD135),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:selfprivacy/config/text_themes.dart';
|
|||
|
||||
import 'brand_colors.dart';
|
||||
|
||||
var theme = ThemeData(
|
||||
final theme = ThemeData(
|
||||
primaryColor: BrandColors.primary,
|
||||
brightness: Brightness.light,
|
||||
scaffoldBackgroundColor: BrandColors.scaffoldBackground,
|
||||
|
@ -13,7 +13,9 @@ var theme = ThemeData(
|
|||
headline1: headline1Style,
|
||||
headline2: headline2Style,
|
||||
caption: captionStyle,
|
||||
bodyText1: bodyText1Style,
|
||||
bodyText1: body1Style,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final brandPagePadding = EdgeInsets.symmetric(horizontal: 15, vertical: 30);
|
||||
|
|
|
@ -29,7 +29,7 @@ final captionStyle = GoogleFonts.inter(
|
|||
color: BrandColors.headlineColor,
|
||||
);
|
||||
|
||||
final bodyText1Style = defaultTextStyle;
|
||||
final body2TextStyle = defaultTextStyle.copyWith(
|
||||
final body1Style = defaultTextStyle;
|
||||
final body2Style = defaultTextStyle.copyWith(
|
||||
color: BrandColors.textColor2,
|
||||
);
|
||||
|
|
24
lib/logic/cubit/services/services_cubit.dart
Normal file
24
lib/logic/cubit/services/services_cubit.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
import 'package:bloc/bloc.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
export 'package:provider/provider.dart';
|
||||
|
||||
part 'services_state.dart';
|
||||
|
||||
class ServicesCubit extends Cubit<ServicesState> {
|
||||
ServicesCubit() : super(ServicesState(all));
|
||||
|
||||
void connect(Service service) {
|
||||
var newState = state.updateElement(service, ServiceStateType.stable);
|
||||
emit(newState);
|
||||
}
|
||||
}
|
||||
|
||||
final all = ServiceTypes.values
|
||||
.map(
|
||||
(type) => Service(
|
||||
state: ServiceStateType.uninitialized,
|
||||
type: type,
|
||||
),
|
||||
)
|
||||
.toList();
|
23
lib/logic/cubit/services/services_state.dart
Normal file
23
lib/logic/cubit/services/services_state.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
part of 'services_cubit.dart';
|
||||
|
||||
@immutable
|
||||
class ServicesState {
|
||||
ServicesState(this.all);
|
||||
|
||||
final List<Service> all;
|
||||
|
||||
ServicesState updateElement(Service service, ServiceStateType newState) {
|
||||
var newList = [...all];
|
||||
var index = newList.indexOf(service);
|
||||
newList[index] = service.updateState(newState);
|
||||
return ServicesState(newList);
|
||||
}
|
||||
|
||||
List<Service> get connected => all
|
||||
.where((service) => service.state != ServiceStateType.uninitialized)
|
||||
.toList();
|
||||
|
||||
List<Service> get uninitialized => all
|
||||
.where((service) => service.state == ServiceStateType.uninitialized)
|
||||
.toList();
|
||||
}
|
26
lib/logic/models/service.dart
Normal file
26
lib/logic/models/service.dart
Normal file
|
@ -0,0 +1,26 @@
|
|||
import 'package:equatable/equatable.dart';
|
||||
|
||||
enum ServiceStateType { uninitialized, stable, warning }
|
||||
enum ServiceTypes {
|
||||
messanger,
|
||||
mail,
|
||||
passwordManager,
|
||||
backup,
|
||||
github,
|
||||
cloud,
|
||||
}
|
||||
|
||||
class Service extends Equatable {
|
||||
const Service({this.state, this.type});
|
||||
|
||||
final ServiceStateType state;
|
||||
final ServiceTypes type;
|
||||
|
||||
Service updateState(ServiceStateType newState) => Service(
|
||||
state: newState,
|
||||
type: type,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object> get props => [state, type];
|
||||
}
|
|
@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
import 'config/bloc_config.dart';
|
||||
import 'config/brand_theme.dart';
|
||||
import 'config/localization.dart';
|
||||
|
||||
|
@ -11,7 +12,9 @@ void main() {
|
|||
|
||||
runApp(
|
||||
Localization(
|
||||
child: MyApp(),
|
||||
child: BlocAndProviderConfig(
|
||||
child: MyApp(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,32 +23,26 @@ class BrandIcons {
|
|||
|
||||
static const IconData connection =
|
||||
IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData envelope =
|
||||
IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData document =
|
||||
IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData envelope =
|
||||
static const IconData key =
|
||||
IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData github =
|
||||
static const IconData save =
|
||||
IconData(0xe804, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData globe =
|
||||
IconData(0xe805, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData help =
|
||||
IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData key =
|
||||
IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData messenger =
|
||||
IconData(0xe809, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData refresh =
|
||||
IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData save =
|
||||
IconData(0xe80b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData settings =
|
||||
IconData(0xe80d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData share =
|
||||
IconData(0xe80e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData triangle =
|
||||
IconData(0xe80f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData upload =
|
||||
IconData(0xe810, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData server =
|
||||
IconData(0xe811, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData box =
|
||||
|
@ -57,4 +51,10 @@ class BrandIcons {
|
|||
IconData(0xe813, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData users =
|
||||
IconData(0xe814, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData messanger =
|
||||
IconData(0xe815, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData upload =
|
||||
IconData(0xe816, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData github =
|
||||
IconData(0xe817, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
}
|
||||
|
|
35
lib/ui/components/icon_status_mask/icon_status_mask.dart
Normal file
35
lib/ui/components/icon_status_mask/icon_status_mask.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_colors.dart';
|
||||
import 'package:selfprivacy/logic/models/service.dart';
|
||||
|
||||
class IconStatusMaks extends StatelessWidget {
|
||||
IconStatusMaks({this.child, this.status});
|
||||
final Icon child;
|
||||
|
||||
final ServiceStateType status;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Color> colors;
|
||||
switch (status) {
|
||||
case ServiceStateType.uninitialized:
|
||||
colors = BrandColors.uninitializedGradientColors;
|
||||
break;
|
||||
case ServiceStateType.stable:
|
||||
colors = BrandColors.stableGradientColors;
|
||||
break;
|
||||
case ServiceStateType.warning:
|
||||
colors = BrandColors.warningGradientColors;
|
||||
break;
|
||||
}
|
||||
return ShaderMask(
|
||||
shaderCallback: (bounds) => LinearGradient(
|
||||
begin: Alignment(-1, -0.8),
|
||||
end: Alignment(0.9, 0.9),
|
||||
colors: colors,
|
||||
tileMode: TileMode.mirror,
|
||||
).createShader(bounds),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_tab_bar/brand_tab_bar.dart';
|
||||
import 'package:selfprivacy/ui/pages/servers/servers.dart';
|
||||
import 'package:selfprivacy/ui/pages/services/services.dart';
|
||||
|
||||
class RootPage extends StatefulWidget {
|
||||
const RootPage({Key key}) : super(key: key);
|
||||
|
@ -34,7 +35,7 @@ class _RootPageState extends State<RootPage>
|
|||
controller: tabController,
|
||||
children: [
|
||||
ServersPage(),
|
||||
Text('services'),
|
||||
ServicesPage(),
|
||||
Text('users'),
|
||||
Text('more'),
|
||||
],
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_colors.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/utils/extensions/text_extension.dart';
|
||||
export 'package:bloc/bloc.dart';
|
||||
|
||||
class ServersPage extends StatelessWidget {
|
||||
const ServersPage({Key key}) : super(key: key);
|
||||
|
@ -13,71 +15,70 @@ class ServersPage extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 30),
|
||||
children: [
|
||||
Text('Начало').caption,
|
||||
Text('SelfPrivacy').h1,
|
||||
SizedBox(
|
||||
height: 10,
|
||||
body: ListView(
|
||||
padding: brandPagePadding,
|
||||
children: [
|
||||
Text('Начало').caption,
|
||||
Text('SelfPrivacy').h1,
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text:
|
||||
'Для устойчивости и приватности требует много учёток. Полная инструкция на ',
|
||||
style: body2Style,
|
||||
),
|
||||
BrandSpanButton.link(
|
||||
text: 'selfprivacy.org/start',
|
||||
urlString: 'https://selfprivacy.org/start',
|
||||
),
|
||||
],
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text:
|
||||
'Для устойчивости и приватности требует много учёток. Полная инструкция на ',
|
||||
style: body2TextStyle,
|
||||
),
|
||||
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),
|
||||
Text('1. Подключите сервер Hetzner').h2,
|
||||
SizedBox(height: 10),
|
||||
Text('Здесь будут жить наши данные и SelfPrivacy-сервисы')
|
||||
.body2,
|
||||
_MockForm(
|
||||
hintText: 'Hetzner API Token',
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.text(
|
||||
onPressed: () => showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (BuildContext context) {
|
||||
return BrandModalSheet(
|
||||
child: Column(
|
||||
children: [
|
||||
Text('Как получить Hetzner API Token').h2,
|
||||
SizedBox(height: 20),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '1 Переходим по ссылке ',
|
||||
style: bodyText1Style,
|
||||
),
|
||||
BrandSpanButton.link(
|
||||
text: 'hetzner.com/sdfsdfsdfsdf',
|
||||
urlString:
|
||||
'https://hetzner.com/sdfsdfsdfsdf',
|
||||
),
|
||||
TextSpan(
|
||||
text: '''
|
||||
|
||||
),
|
||||
SizedBox(height: 50),
|
||||
BrandCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset('assets/images/logos/hetzner.png'),
|
||||
SizedBox(height: 10),
|
||||
Text('1. Подключите сервер Hetzner').h2,
|
||||
SizedBox(height: 10),
|
||||
Text('Здесь будут жить наши данные и SelfPrivacy-сервисы')
|
||||
.body2,
|
||||
_MockForm(
|
||||
hintText: 'Hetzner API Token',
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.text(
|
||||
onPressed: () => showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (BuildContext context) {
|
||||
return BrandModalSheet(
|
||||
child: Column(
|
||||
children: [
|
||||
Text('Как получить Hetzner API Token').h2,
|
||||
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 Заходим в созданный нами проект. Если такового - нет, значит создаём.
|
||||
|
||||
3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).
|
||||
|
@ -88,104 +89,103 @@ class ServersPage extends StatelessWidget {
|
|||
|
||||
6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет.
|
||||
|
||||
''',
|
||||
style: bodyText1Style,
|
||||
),
|
||||
],
|
||||
),
|
||||
''',
|
||||
style: body1Style,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
title: 'Как получить API Token',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
BrandCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset('assets/images/logos/namecheap.png'),
|
||||
SizedBox(height: 10),
|
||||
Text('2. Настройте домен ').h2,
|
||||
SizedBox(height: 10),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Зарегистрируйте домен в ',
|
||||
style: body2TextStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
BrandSpanButton.link(
|
||||
text: 'NameCheap',
|
||||
urlString: 'https://www.namecheap.com',
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' или у любого другого регистратора. После этого настройте его на DNS-сервер CloudFlare',
|
||||
style: body2TextStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
_MockForm(
|
||||
hintText: 'Домен, например, selfprivacy.org',
|
||||
submitButtonText: 'Проверить DNS',
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.text(
|
||||
onPressed: () {},
|
||||
title: 'Как настроить DNS CloudFlare',
|
||||
),
|
||||
],
|
||||
),
|
||||
title: 'Как получить API Token',
|
||||
),
|
||||
],
|
||||
),
|
||||
BrandCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset('assets/images/logos/cloudflare.png'),
|
||||
SizedBox(height: 10),
|
||||
Text('3. Подключите CloudFlare DNS').h2,
|
||||
SizedBox(height: 10),
|
||||
Text('Для управления DNS вашего домена').body2,
|
||||
_MockForm(
|
||||
hintText: 'CloudFlare API Token',
|
||||
),
|
||||
BrandCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset('assets/images/logos/namecheap.png'),
|
||||
SizedBox(height: 10),
|
||||
Text('2. Настройте домен ').h2,
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.text(
|
||||
onPressed: () {},
|
||||
title: 'Как получить API Token',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
_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/aws.png'),
|
||||
SizedBox(height: 10),
|
||||
Text('4. Подключите Amazon AWS для бекапа').h2,
|
||||
SizedBox(height: 10),
|
||||
Text('IaaS-провайдер, для бесплатного хранения резервных копии ваших данных в зашифрованном виде')
|
||||
.body2,
|
||||
_MockForm(
|
||||
hintText: 'Amazon AWS Access Key',
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.text(
|
||||
onPressed: () {},
|
||||
title: 'Как получить API Token',
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
BrandCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.asset('assets/images/logos/cloudflare.png'),
|
||||
SizedBox(height: 10),
|
||||
Text('3. Подключите CloudFlare DNS').h2,
|
||||
SizedBox(height: 10),
|
||||
Text('Для управления DNS вашего домена').body2,
|
||||
_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),
|
||||
Text('4. Подключите Amazon AWS для бекапа').h2,
|
||||
SizedBox(height: 10),
|
||||
Text('IaaS-провайдер, для бесплатного хранения резервных копии ваших данных в зашифрованном виде')
|
||||
.body2,
|
||||
_MockForm(
|
||||
hintText: 'Amazon AWS Access Key',
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
BrandButton.text(
|
||||
onPressed: () {},
|
||||
title: 'Как получить API Token',
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
110
lib/ui/pages/services/services.dart
Normal file
110
lib/ui/pages/services/services.dart
Normal file
|
@ -0,0 +1,110 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/config/brand_theme.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';
|
||||
import 'package:selfprivacy/ui/components/brand_card/brand_card.dart';
|
||||
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
|
||||
import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart';
|
||||
import 'package:selfprivacy/utils/extensions/text_extension.dart';
|
||||
|
||||
class ServicesPage extends StatefulWidget {
|
||||
ServicesPage({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ServicesPageState createState() => _ServicesPageState();
|
||||
}
|
||||
|
||||
class _ServicesPageState extends State<ServicesPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serviceCubit = context.watch<ServicesCubit>();
|
||||
final connected = serviceCubit.state.connected;
|
||||
final uninitialized = serviceCubit.state.uninitialized;
|
||||
return Scaffold(
|
||||
body: ListView(
|
||||
padding: brandPagePadding,
|
||||
children: [
|
||||
Text('Сервисы').caption,
|
||||
SizedBox(height: 24),
|
||||
...connected.map((service) => _Card(service: service)).toList(),
|
||||
if (uninitialized.isNotEmpty) ...[
|
||||
Text('не подключены').body1,
|
||||
SizedBox(height: 30),
|
||||
],
|
||||
...uninitialized.map((service) => _Card(service: service)).toList()
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Card extends StatelessWidget {
|
||||
const _Card({Key key, @required this.service}) : super(key: key);
|
||||
|
||||
final Service service;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String title;
|
||||
IconData iconData;
|
||||
String description;
|
||||
|
||||
switch (service.type) {
|
||||
case ServiceTypes.messanger:
|
||||
iconData = BrandIcons.messanger;
|
||||
title = 'Мессенджер';
|
||||
description =
|
||||
'Delta Chat срфеТекст-текст описание. Если бы мне надо было обсудить что-то от чего зависит жизнь. Я бы выбрал Delta.Chat + свой почтовый сервер.';
|
||||
break;
|
||||
case ServiceTypes.mail:
|
||||
iconData = BrandIcons.envelope;
|
||||
title = 'Почта';
|
||||
description = 'Электронная почта для семьи или компании ';
|
||||
break;
|
||||
case ServiceTypes.passwordManager:
|
||||
iconData = BrandIcons.key;
|
||||
title = 'Менеджер паролей';
|
||||
description = 'Надёжное хранилище для ваших паролей и ключей доступа';
|
||||
break;
|
||||
case ServiceTypes.github:
|
||||
iconData = BrandIcons.github;
|
||||
title = 'Git сервер';
|
||||
description = 'Сервис для приватного хранения своих разработок';
|
||||
break;
|
||||
case ServiceTypes.backup:
|
||||
iconData = BrandIcons.save;
|
||||
title = 'Резервное копирование';
|
||||
description = 'Обеспеченье целосности и сохранности ваших данных';
|
||||
break;
|
||||
case ServiceTypes.cloud:
|
||||
iconData = BrandIcons.upload;
|
||||
title = 'Файловое Облако';
|
||||
description = 'Сервис для доступа к вашим файлам в любой точке мира';
|
||||
break;
|
||||
}
|
||||
return BrandCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
IconStatusMaks(
|
||||
status: service.state,
|
||||
child: Icon(iconData, size: 30, color: Colors.white),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(title).h2,
|
||||
SizedBox(height: 10),
|
||||
if (service.state == ServiceStateType.uninitialized) ...[
|
||||
Text(description).body1,
|
||||
SizedBox(height: 10),
|
||||
BrandButton.text(
|
||||
title: 'Подключить',
|
||||
onPressed: () {
|
||||
context.read<ServicesCubit>().connect(service);
|
||||
})
|
||||
],
|
||||
if (service.state == ServiceStateType.stable) Text('Подключен').body1,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,8 @@ extension TextExtension on Text {
|
|||
Text get h2 => copyWith(style: headline2Style);
|
||||
Text get caption => copyWith(style: captionStyle);
|
||||
|
||||
Text get body2 => copyWith(style: body2TextStyle);
|
||||
Text get body1 => copyWith(style: body1Style);
|
||||
Text get body2 => copyWith(style: body2Style);
|
||||
|
||||
Text setKey(Key key) => copyWith(key: key);
|
||||
|
||||
|
|
35
pubspec.lock
35
pubspec.lock
|
@ -22,6 +22,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.5.0-nullsafety.1"
|
||||
bloc:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bloc
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -85,6 +92,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: equatable
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.5"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -111,6 +125,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_bloc:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_bloc
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.1"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -182,6 +203,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0-nullsafety.3"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -259,6 +287,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.13"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.3.2+2"
|
||||
shared_preferences:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -11,7 +11,10 @@ dependencies:
|
|||
sdk: flutter
|
||||
cupertino_icons: ^1.0.0
|
||||
easy_localization: ^2.3.3
|
||||
equatable: ^1.2.5
|
||||
flutter_bloc: ^6.1.1
|
||||
google_fonts: ^1.1.1
|
||||
provider: ^4.3.2+2
|
||||
url_launcher: ^5.7.10
|
||||
|
||||
dev_dependencies:
|
||||
|
|
Loading…
Reference in a new issue