@ -5,144 +5,225 @@ 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/pages/dots_indicator/dots_indicator.dart ' ;
import ' package:selfprivacy/ui/pages/rootRoute.dart ' ;
import ' package:selfprivacy/utils/extensions/text_extension.dart ' ;
import ' package:selfprivacy/utils/route_transitions/basic.dart ' ;
class OnboardingPage extends State less Widget {
class OnboardingPage extends State fu lWidget {
const OnboardingPage ( { Key key } ) : super ( key: key ) ;
@ override
_OnboardingPageState createState ( ) = > _OnboardingPageState ( ) ;
}
class _OnboardingPageState extends State < OnboardingPage > {
PageController controller ;
var currentPage = 0 ;
@ override
void initState ( ) {
controller = PageController (
initialPage: 0 ,
) . . addListener ( ( ) {
if ( currentPage ! = controller . page . toInt ( ) ) {
setState ( ( ) {
currentPage = controller . page . toInt ( ) ;
} ) ;
}
} ) ;
super . initState ( ) ;
WidgetsBinding . instance . addPostFrameCallback ( ( _ ) { } ) ;
}
@ override
void dispose ( ) {
controller . dispose ( ) ;
super . dispose ( ) ;
}
@ override
Widget build ( BuildContext context ) {
return Scaffold (
body: ListView (
padding: brandPagePadding1 ,
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 ' ,
) ,
] ,
) ,
) ,
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: ( ) = > _showModal ( context , _HowHetzner ( ) ) ,
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: body2Style ,
) ,
BrandSpanButton . link (
text: ' NameCheap ' ,
urlString: ' https://www.namecheap.com ' ,
) ,
TextSpan (
text:
' или у любого другого регистратора. После этого настройте е г о на DNS-сервер CloudFlare ' ,
style: body2Style ,
) ,
] ,
var steps = getSteps ( ) ;
return SafeArea (
child: Scaffold (
body: ListView (
shrinkWrap: true ,
children: [
Padding (
padding: brandPagePadding1 ,
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Text ( ' Начало ' ) . caption ,
Text ( ' SelfPrivacy ' ) . h1 ,
SizedBox (
height: 10 ,
) ,
) ,
_MockForm (
hintText: ' Домен, например, selfprivacy.org ' ,
submitButtonText: ' Проверить DNS ' ,
) ,
SizedBox ( height: 20 ) ,
BrandButton . text (
onPressed: ( ) { } ,
title: ' Как настроить DNS CloudFlare ' ,
) ,
] ,
RichText (
text: TextSpan (
children: [
TextSpan (
text:
' Для устойчивости и приватности требует много учёток. Полная инструкция на ' ,
style: body2Style ,
) ,
BrandSpanButton . link (
text: ' selfprivacy.org/start ' ,
urlString: ' https://selfprivacy.org/start ' ,
) ,
] ,
) ,
) ,
] ,
) ,
) ,
) ,
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 ' ,
) ,
] ,
Container (
height: 480 ,
child: PageView . builder (
physics: NeverScrollableScrollPhysics ( ) ,
allowImplicitScrolling: false ,
controller: controller ,
itemBuilder: ( _ , index ) {
return Padding (
padding: brandPagePadding2 ,
child: steps [ index ] ,
) ;
} ,
itemCount: 4 ,
) ,
) ,
) ,
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 ' ,
) ,
] ,
DotsIndicator (
activeIndex: currentPage ,
count: steps . length ,
) ,
)
] ,
SizedBox ( height: 50 ) ,
] ,
) ,
) ,
) ;
}
List < Widget > getSteps ( ) = > < Widget > [
BrandCard (
child: Column (
mainAxisSize: MainAxisSize . min ,
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 (
onPressed: _nextPage ,
hintText: ' Hetzner API Token ' ,
length: 2 ,
) ,
SizedBox ( height: 20 ) ,
Spacer ( ) ,
BrandButton . text (
onPressed: ( ) = > _showModal ( context , _HowHetzner ( ) ) ,
title: ' Как получить API Token ' ,
) ,
] ,
) ,
) ,
BrandCard (
child: Column (
mainAxisSize: MainAxisSize . min ,
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 ,
) ,
] ,
) ,
) ,
_MockForm (
onPressed: _nextPage ,
hintText: ' Домен, например, selfprivacy.org ' ,
submitButtonText: ' Проверить DNS ' ,
length: 2 ,
) ,
Spacer ( ) ,
BrandButton . text (
onPressed: ( ) { } ,
title: ' Как настроить DNS CloudFlare ' ,
) ,
] ,
) ,
) ,
BrandCard (
child: Column (
mainAxisSize: MainAxisSize . min ,
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 (
onPressed: _nextPage ,
hintText: ' CloudFlare API Token ' ,
length: 2 ,
) ,
Spacer ( ) ,
BrandButton . text (
onPressed: ( ) { } ,
title: ' Как получить API Token ' ,
) ,
] ,
) ,
) ,
BrandCard (
child: Column (
mainAxisSize: MainAxisSize . min ,
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 (
onPressed: ( ) {
Navigator . of ( context )
. pushReplacement ( materialRoute ( RootPage ( ) ) ) ;
} ,
hintText: ' Amazon AWS Access Key ' ,
length: 2 ,
) ,
Spacer ( ) ,
BrandButton . text (
onPressed: ( ) { } ,
title: ' Как получить API Token ' ,
) ,
] ,
) ,
) ,
] ;
void _showModal ( BuildContext context , Widget widget ) {
showModalBottomSheet < void > (
context: context ,
@ -153,6 +234,11 @@ class OnboardingPage extends StatelessWidget {
} ,
) ;
}
void _nextPage ( ) = > controller . nextPage (
duration: Duration ( milliseconds: 300 ) ,
curve: Curves . easeIn ,
) ;
}
class _HowHetzner extends StatelessWidget {
@ -163,25 +249,27 @@ class _HowHetzner extends StatelessWidget {
@ override
Widget build ( BuildContext context ) {
return BrandModalSheet (
child: Column (
children: [
SizedBox ( height: 40 ) ,
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: '''
child: Padding (
padding: brandPagePadding2 ,
child: Column (
children: [
SizedBox ( height: 40 ) ,
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 ( с и к о н к о й к л ю ч и к а ) .
@ -192,36 +280,60 @@ class _HowHetzner extends StatelessWidget {
6 В п о л е Description , д а ё м н а ш е м у т о к е н у н а з в а н и е ( э т о м о ж е т б ы т ь л ю б о е н а з в а н и е , к о т о р ы е в а м н р а в и т ь с я . С у т и о н о н е м е н я е т .
''' ,
style: body1Style ,
) ,
] ,
''' ,
style: body1Style ,
) ,
] ,
) ,
) ,
) ,
] ,
] ,
) ,
) ,
) ;
}
}
class _MockForm extends State less Widget {
class _MockForm extends State fu lWidget {
const _MockForm ( {
Key key ,
@ required this . hintText ,
this . submitButtonText = ' Подключить ' ,
@ required this . onPressed ,
@ required this . length ,
} ) : super ( key: key ) ;
final String hintText ;
final String submitButtonText ;
final int length ;
final VoidCallback onPressed ;
@ override
__MockFormState createState ( ) = > __MockFormState ( ) ;
}
class __MockFormState extends State < _MockForm > {
String text = ' ' ;
@ override
Widget build ( BuildContext context ) {
return Column (
children: [
SizedBox ( height: 20 ) ,
TextField ( decoration: InputDecoration ( hintText: hintText ) ) ,
TextField (
onChanged: ( value ) = > {
setState ( ( ) {
text = value ;
} )
} ,
decoration: InputDecoration ( hintText: widget . hintText ) ,
) ,
SizedBox ( height: 20 ) ,
BrandButton . rised ( onPressed: ( ) { } , title: submitButtonText ) ,
BrandButton . rised (
onPressed:
text . length = = widget . length ? widget . onPressed ? ? ( ) { } : null ,
title: widget . submitButtonText ,
) ,
] ,
) ;
}