update first page

fdroid
Kherel 2020-11-30 11:03:55 +01:00
parent cbd00e87d3
commit b626b05a1a
22 changed files with 588 additions and 64 deletions

13
.vscode/launch.json vendored Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -2,20 +2,26 @@ PODS:
- Flutter (1.0.0)
- path_provider (0.0.1):
- Flutter
- url_launcher (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
EXTERNAL SOURCES:
Flutter:
:path: Flutter
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

View File

@ -15,11 +15,17 @@ class BrandColors {
/// ![](https://www.colorhexa.com/fafafa.png)
static const Color gray3 = Color(0xFFFAFAFA);
/// ![](https://www.colorhexa.com/DDDDDD.png)
static const Color gray4 = Color(0xFFDDDDDD);
static const primary = blue;
static const headlineColor = black;
static const textColor = gray1;
static const inactive = gray2;
static const scaffoldBackground = gray3;
static const inputInactive = gray4;
static const textColor1 = black;
static const textColor2 = gray1;
static get navBackground => white.withOpacity(0.8);
}

View File

@ -0,0 +1,7 @@
import 'package:flutter/material.dart';
final shadow8 = BoxShadow(
offset: Offset(0, 4),
blurRadius: 8,
color: Colors.black.withOpacity(.08),
);

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.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';
@ -10,24 +10,10 @@ var theme = ThemeData(
scaffoldBackgroundColor: BrandColors.scaffoldBackground,
textTheme: GoogleFonts.interTextTheme(
TextTheme(
headline1: TextStyle(
fontSize: 40,
fontWeight: NamedFontWeight.extraBold,
color: BrandColors.headlineColor,
),
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,
),
headline1: headline1Style,
headline2: headline2Style,
caption: captionStyle,
bodyText1: bodyText1Style,
),
),
);

View 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,
);

View File

@ -11,6 +11,7 @@ void main() {
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light, // Manually changnig appbar color
child: MaterialApp(

View File

@ -3,7 +3,7 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_colors.dart';
enum BrandButtonTypes { rised }
enum BrandButtonTypes { rised, text }
class BrandButton extends StatelessWidget {
const BrandButton({
@ -19,8 +19,8 @@ class BrandButton extends StatelessWidget {
static rised({
Key key,
VoidCallback onPressed,
String title,
@required VoidCallback onPressed,
@required String title,
}) =>
BrandButton(
key: key,
@ -29,6 +29,18 @@ class BrandButton extends StatelessWidget {
type: BrandButtonTypes.rised,
);
static text({
Key key,
@required VoidCallback onPressed,
@required String title,
}) =>
BrandButton(
key: key,
onPressed: onPressed,
title: title,
type: BrandButtonTypes.text,
);
@override
Widget build(BuildContext context) {
switch (type) {
@ -37,6 +49,12 @@ class BrandButton extends StatelessWidget {
title: title,
onPressed: onPressed,
);
case BrandButtonTypes.text:
return _TextButton(
title: title,
onPressed: onPressed,
);
break;
}
return null;
@ -73,7 +91,7 @@ class _RisedButton extends StatelessWidget {
style: TextStyle(
color: BrandColors.white,
fontSize: 16,
fontWeight: FontWeight.w700,
fontWeight: FontWeight.bold,
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,
),
),
),
);
}
}

View 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,
);
}
}

View 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,
),
],
),
);
}
}

View 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';
}
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:selfprivacy/ui/components/brand_button/brand_button.dart';
import 'package:selfprivacy/ui/pages/rootRoute.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:selfprivacy/utils/extensions/text_extension.dart';
class OnboardingPage extends StatelessWidget {
const OnboardingPage({Key key}) : super(key: key);
@ -27,13 +28,11 @@ class OnboardingPage extends StatelessWidget {
children: [
Text(
'Онбординг',
style: Theme.of(context).textTheme.headline1,
),
).h1,
SizedBox(height: 20),
Text(
'Тут рассказ на 1-2 слайда о том, что делает это приложение, какие твои проблемы решает и как (в общем чего ожидать от сервиса).',
style: Theme.of(context).textTheme.bodyText1,
),
).body2,
],
),
),

View File

@ -1,6 +1,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';
class RootPage extends StatefulWidget {
const RootPage({Key key}) : super(key: key);
@ -32,10 +33,10 @@ class _RootPageState extends State<RootPage>
body: TabBarView(
controller: tabController,
children: [
Text('a'),
Text('b'),
Text('c'),
Text('d'),
ServersPage(),
Text('services'),
Text('users'),
Text('more'),
],
),
bottomNavigationBar: BottomTabBar(

View File

@ -1,4 +1,11 @@
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 {
const ServersPage({Key key}) : super(key: key);
@ -7,8 +14,217 @@ class ServersPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
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),
],
);
}
}

View 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,
);
}
}

View 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);
}
}

View File

@ -95,6 +95,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
google_fonts:
dependency: "direct main"
description:
@ -261,6 +266,48 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -284,4 +331,4 @@ packages:
version: "0.1.2"
sdks:
dart: ">=2.10.0-110 <2.11.0"
flutter: ">=1.17.0 <2.0.0"
flutter: ">=1.22.0 <2.0.0"

View File

@ -1,6 +1,6 @@
name: selfprivacy
description: selfprivacy.org
publish_to: 'none'
publish_to: 'none'
version: 1.0.0+1
environment:
@ -11,39 +11,16 @@ dependencies:
sdk: flutter
cupertino_icons: ^1.0.0
google_fonts: ^1.1.1
url_launcher: ^5.7.10
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
assets:
- assets/images/logos/
fonts:
- family: BrandIcons
fonts:
- asset: assets/fonts/BrandIcons.ttf
- family: BrandIcons
fonts:
- asset: assets/fonts/BrandIcons.ttf