mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-02-04 23:40:38 +00:00
update first page
This commit is contained in:
parent
cbd00e87d3
commit
b626b05a1a
13
.vscode/launch.json
vendored
Normal file
13
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "selfprivacy",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
assets/images/logos/aws.png
Normal file
BIN
assets/images/logos/aws.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/images/logos/cloudflare.png
Normal file
BIN
assets/images/logos/cloudflare.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/images/logos/hetzner.png
Normal file
BIN
assets/images/logos/hetzner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/images/logos/namecheap.png
Normal file
BIN
assets/images/logos/namecheap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
|
@ -2,20 +2,26 @@ PODS:
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- path_provider (0.0.1):
|
- path_provider (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- url_launcher (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||||
|
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
path_provider:
|
path_provider:
|
||||||
:path: ".symlinks/plugins/path_provider/ios"
|
:path: ".symlinks/plugins/path_provider/ios"
|
||||||
|
url_launcher:
|
||||||
|
:path: ".symlinks/plugins/url_launcher/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||||
|
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||||
|
|
||||||
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,17 @@ class BrandColors {
|
||||||
/// ![](https://www.colorhexa.com/fafafa.png)
|
/// ![](https://www.colorhexa.com/fafafa.png)
|
||||||
static const Color gray3 = Color(0xFFFAFAFA);
|
static const Color gray3 = Color(0xFFFAFAFA);
|
||||||
|
|
||||||
|
/// ![](https://www.colorhexa.com/DDDDDD.png)
|
||||||
|
static const Color gray4 = Color(0xFFDDDDDD);
|
||||||
|
|
||||||
static const primary = blue;
|
static const primary = blue;
|
||||||
static const headlineColor = black;
|
static const headlineColor = black;
|
||||||
static const textColor = gray1;
|
|
||||||
static const inactive = gray2;
|
static const inactive = gray2;
|
||||||
static const scaffoldBackground = gray3;
|
static const scaffoldBackground = gray3;
|
||||||
|
static const inputInactive = gray4;
|
||||||
|
|
||||||
|
static const textColor1 = black;
|
||||||
|
static const textColor2 = gray1;
|
||||||
|
|
||||||
static get navBackground => white.withOpacity(0.8);
|
static get navBackground => white.withOpacity(0.8);
|
||||||
}
|
}
|
||||||
|
|
7
lib/config/brand_shadow.dart
Normal file
7
lib/config/brand_shadow.dart
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
final shadow8 = BoxShadow(
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
blurRadius: 8,
|
||||||
|
color: Colors.black.withOpacity(.08),
|
||||||
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:selfprivacy/utils/named_font_weight.dart';
|
import 'package:selfprivacy/config/text_themes.dart';
|
||||||
|
|
||||||
import 'brand_colors.dart';
|
import 'brand_colors.dart';
|
||||||
|
|
||||||
|
@ -10,24 +10,10 @@ var theme = ThemeData(
|
||||||
scaffoldBackgroundColor: BrandColors.scaffoldBackground,
|
scaffoldBackgroundColor: BrandColors.scaffoldBackground,
|
||||||
textTheme: GoogleFonts.interTextTheme(
|
textTheme: GoogleFonts.interTextTheme(
|
||||||
TextTheme(
|
TextTheme(
|
||||||
headline1: TextStyle(
|
headline1: headline1Style,
|
||||||
fontSize: 40,
|
headline2: headline2Style,
|
||||||
fontWeight: NamedFontWeight.extraBold,
|
caption: captionStyle,
|
||||||
color: BrandColors.headlineColor,
|
bodyText1: bodyText1Style,
|
||||||
),
|
|
||||||
headline2: TextStyle(
|
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: NamedFontWeight.extraBold,
|
|
||||||
color: BrandColors.headlineColor,
|
|
||||||
),
|
|
||||||
caption: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: NamedFontWeight.medium,
|
|
||||||
color: BrandColors.headlineColor),
|
|
||||||
bodyText1: TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
color: BrandColors.textColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
35
lib/config/text_themes.dart
Normal file
35
lib/config/text_themes.dart
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:selfprivacy/utils/named_font_weight.dart';
|
||||||
|
|
||||||
|
import 'brand_colors.dart';
|
||||||
|
|
||||||
|
final defaultTextStyle = GoogleFonts.inter(
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: BrandColors.textColor1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final headline1Style = GoogleFonts.inter(
|
||||||
|
fontSize: 40,
|
||||||
|
fontWeight: NamedFontWeight.extraBold,
|
||||||
|
color: BrandColors.headlineColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
final headline2Style = GoogleFonts.inter(
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: NamedFontWeight.extraBold,
|
||||||
|
color: BrandColors.headlineColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
final captionStyle = GoogleFonts.inter(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: NamedFontWeight.medium,
|
||||||
|
color: BrandColors.headlineColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
final bodyText1Style = defaultTextStyle;
|
||||||
|
final body2TextStyle = defaultTextStyle.copyWith(
|
||||||
|
color: BrandColors.textColor2,
|
||||||
|
);
|
|
@ -11,6 +11,7 @@ void main() {
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
|
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:ui';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/config/brand_colors.dart';
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
|
|
||||||
enum BrandButtonTypes { rised }
|
enum BrandButtonTypes { rised, text }
|
||||||
|
|
||||||
class BrandButton extends StatelessWidget {
|
class BrandButton extends StatelessWidget {
|
||||||
const BrandButton({
|
const BrandButton({
|
||||||
|
@ -19,8 +19,8 @@ class BrandButton extends StatelessWidget {
|
||||||
|
|
||||||
static rised({
|
static rised({
|
||||||
Key key,
|
Key key,
|
||||||
VoidCallback onPressed,
|
@required VoidCallback onPressed,
|
||||||
String title,
|
@required String title,
|
||||||
}) =>
|
}) =>
|
||||||
BrandButton(
|
BrandButton(
|
||||||
key: key,
|
key: key,
|
||||||
|
@ -29,6 +29,18 @@ class BrandButton extends StatelessWidget {
|
||||||
type: BrandButtonTypes.rised,
|
type: BrandButtonTypes.rised,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static text({
|
||||||
|
Key key,
|
||||||
|
@required VoidCallback onPressed,
|
||||||
|
@required String title,
|
||||||
|
}) =>
|
||||||
|
BrandButton(
|
||||||
|
key: key,
|
||||||
|
onPressed: onPressed,
|
||||||
|
title: title,
|
||||||
|
type: BrandButtonTypes.text,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -37,6 +49,12 @@ class BrandButton extends StatelessWidget {
|
||||||
title: title,
|
title: title,
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
);
|
);
|
||||||
|
case BrandButtonTypes.text:
|
||||||
|
return _TextButton(
|
||||||
|
title: title,
|
||||||
|
onPressed: onPressed,
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -73,7 +91,7 @@ class _RisedButton extends StatelessWidget {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: BrandColors.white,
|
color: BrandColors.white,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.bold,
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -84,3 +102,36 @@ class _RisedButton extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _TextButton extends StatelessWidget {
|
||||||
|
const _TextButton({
|
||||||
|
Key key,
|
||||||
|
this.onPressed,
|
||||||
|
this.title,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onPressed,
|
||||||
|
child: Container(
|
||||||
|
height: 48,
|
||||||
|
width: double.infinity,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: EdgeInsets.all(12),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
color: BrandColors.blue,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
height: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
25
lib/ui/components/brand_card/brand_card.dart
Normal file
25
lib/ui/components/brand_card/brand_card.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
|
import 'package:selfprivacy/utils/extensions/elevation_extension.dart';
|
||||||
|
|
||||||
|
class BrandCard extends StatelessWidget {
|
||||||
|
const BrandCard({Key key, this.child}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 30),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: BrandColors.white,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
).ev8,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 15,
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
41
lib/ui/components/brand_modal_sheet/brand_modal_sheet.dart
Normal file
41
lib/ui/components/brand_modal_sheet/brand_modal_sheet.dart
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
|
|
||||||
|
class BrandModalSheet extends StatelessWidget {
|
||||||
|
const BrandModalSheet({
|
||||||
|
Key key,
|
||||||
|
this.child,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 32, bottom: 6),
|
||||||
|
child: Container(
|
||||||
|
height: 4,
|
||||||
|
width: 30,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(2),
|
||||||
|
color: Color(0xFFE3E3E3).withOpacity(0.65),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
constraints: BoxConstraints(minHeight: 400),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||||
|
color: BrandColors.white,
|
||||||
|
),
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 40, horizontal: 15),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
37
lib/ui/components/brand_span_button/brand_span_button.dart
Normal file
37
lib/ui/components/brand_span_button/brand_span_button.dart
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class BrandSpanButton extends TextSpan {
|
||||||
|
BrandSpanButton({
|
||||||
|
@required String text,
|
||||||
|
@required VoidCallback onTap,
|
||||||
|
TextStyle style,
|
||||||
|
}) : assert(text != null),
|
||||||
|
assert(onTap != null),
|
||||||
|
super(
|
||||||
|
recognizer: TapGestureRecognizer()..onTap = onTap,
|
||||||
|
text: text,
|
||||||
|
style: (style ?? TextStyle()).copyWith(color: BrandColors.blue),
|
||||||
|
);
|
||||||
|
|
||||||
|
static link({
|
||||||
|
@required String text,
|
||||||
|
String urlString,
|
||||||
|
TextStyle style,
|
||||||
|
}) =>
|
||||||
|
BrandSpanButton(
|
||||||
|
text: text,
|
||||||
|
style: style,
|
||||||
|
onTap: () => _launchURL(urlString ?? text),
|
||||||
|
);
|
||||||
|
|
||||||
|
static _launchURL(String link) async {
|
||||||
|
if (await canLaunch(link)) {
|
||||||
|
await launch(link);
|
||||||
|
} else {
|
||||||
|
throw 'Could not launch $link';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
|
||||||
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
||||||
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
||||||
|
import 'package:selfprivacy/utils/extensions/text_extension.dart';
|
||||||
|
|
||||||
class OnboardingPage extends StatelessWidget {
|
class OnboardingPage extends StatelessWidget {
|
||||||
const OnboardingPage({Key key}) : super(key: key);
|
const OnboardingPage({Key key}) : super(key: key);
|
||||||
|
@ -27,13 +28,11 @@ class OnboardingPage extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Онбординг',
|
'Онбординг',
|
||||||
style: Theme.of(context).textTheme.headline1,
|
).h1,
|
||||||
),
|
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
'Тут рассказ на 1-2 слайда о том, что делает это приложение, какие твои проблемы решает и как (в общем чего ожидать от сервиса).',
|
'Тут рассказ на 1-2 слайда о том, что делает это приложение, какие твои проблемы решает и как (в общем чего ожидать от сервиса).',
|
||||||
style: Theme.of(context).textTheme.bodyText1,
|
).body2,
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/ui/components/brand_tab_bar/brand_tab_bar.dart';
|
import 'package:selfprivacy/ui/components/brand_tab_bar/brand_tab_bar.dart';
|
||||||
|
import 'package:selfprivacy/ui/pages/servers/servers.dart';
|
||||||
|
|
||||||
class RootPage extends StatefulWidget {
|
class RootPage extends StatefulWidget {
|
||||||
const RootPage({Key key}) : super(key: key);
|
const RootPage({Key key}) : super(key: key);
|
||||||
|
@ -32,10 +33,10 @@ class _RootPageState extends State<RootPage>
|
||||||
body: TabBarView(
|
body: TabBarView(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
children: [
|
children: [
|
||||||
Text('a'),
|
ServersPage(),
|
||||||
Text('b'),
|
Text('services'),
|
||||||
Text('c'),
|
Text('users'),
|
||||||
Text('d'),
|
Text('more'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
bottomNavigationBar: BottomTabBar(
|
bottomNavigationBar: BottomTabBar(
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_colors.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';
|
||||||
|
|
||||||
class ServersPage extends StatelessWidget {
|
class ServersPage extends StatelessWidget {
|
||||||
const ServersPage({Key key}) : super(key: key);
|
const ServersPage({Key key}) : super(key: key);
|
||||||
|
@ -7,8 +14,217 @@ class ServersPage extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Container(
|
body: Container(
|
||||||
child: Text('aaa111'),
|
child: ListView(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 30),
|
||||||
|
children: [
|
||||||
|
Text('Начало').caption,
|
||||||
|
Text('SelfPrivacy').h1,
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
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: '''
|
||||||
|
|
||||||
|
2 Заходим в созданный нами проект. Если такового - нет, значит создаём.
|
||||||
|
|
||||||
|
3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).
|
||||||
|
|
||||||
|
4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.
|
||||||
|
|
||||||
|
5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку.
|
||||||
|
|
||||||
|
6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет.
|
||||||
|
|
||||||
|
''',
|
||||||
|
style: bodyText1Style,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
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',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _MockForm extends StatelessWidget {
|
||||||
|
const _MockForm({
|
||||||
|
Key key,
|
||||||
|
@required this.hintText,
|
||||||
|
this.submitButtonText = 'Подключить',
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String hintText;
|
||||||
|
final String submitButtonText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 20),
|
||||||
|
TextField(
|
||||||
|
style: TextStyle(fontSize: 15, height: 1.6),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: hintText,
|
||||||
|
contentPadding: EdgeInsets.all(16),
|
||||||
|
border: InputBorder.none,
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(4)),
|
||||||
|
borderSide: BorderSide(color: BrandColors.inputInactive),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(4)),
|
||||||
|
borderSide: BorderSide(color: BrandColors.blue),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
BrandButton.rised(onPressed: () {}, title: submitButtonText),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
33
lib/utils/extensions/elevation_extension.dart
Normal file
33
lib/utils/extensions/elevation_extension.dart
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
library elevation_extension;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:selfprivacy/config/brand_shadow.dart';
|
||||||
|
|
||||||
|
extension ElevationExtension on BoxDecoration {
|
||||||
|
BoxDecoration get ev8 => copyWith(boxShadow: [shadow8]);
|
||||||
|
|
||||||
|
BoxDecoration copyWith({
|
||||||
|
Color color,
|
||||||
|
DecorationImage image,
|
||||||
|
BoxBorder border,
|
||||||
|
BorderRadiusGeometry borderRadius,
|
||||||
|
List<BoxShadow> boxShadow,
|
||||||
|
Gradient gradient,
|
||||||
|
BlendMode backgroundBlendMode,
|
||||||
|
BoxShape shape,
|
||||||
|
}) {
|
||||||
|
return BoxDecoration(
|
||||||
|
color: color ?? this.color,
|
||||||
|
image: image ?? this.image,
|
||||||
|
border: border ?? this.border,
|
||||||
|
borderRadius: borderRadius ?? this.borderRadius,
|
||||||
|
boxShadow: this.boxShadow != null || boxShadow != null
|
||||||
|
? [...this.boxShadow ?? [], ...boxShadow ?? []]
|
||||||
|
: null,
|
||||||
|
gradient: gradient ?? this.gradient,
|
||||||
|
backgroundBlendMode: backgroundBlendMode ?? this.backgroundBlendMode,
|
||||||
|
shape: shape ?? this.shape,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
43
lib/utils/extensions/text_extension.dart
Normal file
43
lib/utils/extensions/text_extension.dart
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
library text_extension;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:selfprivacy/config/text_themes.dart';
|
||||||
|
|
||||||
|
extension TextExtension on Text {
|
||||||
|
Text get h1 => copyWith(style: headline1Style);
|
||||||
|
Text get h2 => copyWith(style: headline2Style);
|
||||||
|
Text get caption => copyWith(style: captionStyle);
|
||||||
|
|
||||||
|
Text get body2 => copyWith(style: body2TextStyle);
|
||||||
|
|
||||||
|
Text setKey(Key key) => copyWith(key: key);
|
||||||
|
|
||||||
|
Text copyWith(
|
||||||
|
{Key key,
|
||||||
|
StrutStyle strutStyle,
|
||||||
|
TextAlign textAlign,
|
||||||
|
TextDirection textDirection = TextDirection.ltr,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
49
pubspec.lock
49
pubspec.lock
|
@ -95,6 +95,11 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
google_fonts:
|
google_fonts:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -261,6 +266,48 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.3"
|
version: "1.3.0-nullsafety.3"
|
||||||
|
url_launcher:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: url_launcher
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.7.10"
|
||||||
|
url_launcher_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_linux
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.1+4"
|
||||||
|
url_launcher_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_macos
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.1+9"
|
||||||
|
url_launcher_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.9"
|
||||||
|
url_launcher_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.5+1"
|
||||||
|
url_launcher_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_windows
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.1+3"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -284,4 +331,4 @@ packages:
|
||||||
version: "0.1.2"
|
version: "0.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.10.0-110 <2.11.0"
|
dart: ">=2.10.0-110 <2.11.0"
|
||||||
flutter: ">=1.17.0 <2.0.0"
|
flutter: ">=1.22.0 <2.0.0"
|
||||||
|
|
37
pubspec.yaml
37
pubspec.yaml
|
@ -1,6 +1,6 @@
|
||||||
name: selfprivacy
|
name: selfprivacy
|
||||||
description: selfprivacy.org
|
description: selfprivacy.org
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
@ -11,39 +11,16 @@ dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
cupertino_icons: ^1.0.0
|
cupertino_icons: ^1.0.0
|
||||||
google_fonts: ^1.1.1
|
google_fonts: ^1.1.1
|
||||||
|
url_launcher: ^5.7.10
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
assets:
|
||||||
|
- assets/images/logos/
|
||||||
fonts:
|
fonts:
|
||||||
- family: BrandIcons
|
- family: BrandIcons
|
||||||
fonts:
|
fonts:
|
||||||
- asset: assets/fonts/BrandIcons.ttf
|
- asset: assets/fonts/BrandIcons.ttf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue