mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-27 11:16:45 +00:00
update
This commit is contained in:
parent
3de01fe12b
commit
25a386d511
BIN
assets/images/logos/backblaze.png
Normal file
BIN
assets/images/logos/backblaze.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
|
@ -50,6 +50,6 @@ class BNames {
|
||||||
static String hetznerServer = 'hetznerServer';
|
static String hetznerServer = 'hetznerServer';
|
||||||
static String isDkimSetted = 'isDkimSetted';
|
static String isDkimSetted = 'isDkimSetted';
|
||||||
static String isDnsChecked = 'isDnsChecked';
|
static String isDnsChecked = 'isDnsChecked';
|
||||||
|
|
||||||
static String isServerStarted = 'isServerStarted';
|
static String isServerStarted = 'isServerStarted';
|
||||||
|
static String backblazeKey = 'backblazeKey';
|
||||||
}
|
}
|
||||||
|
|
38
lib/logic/api_maps/backblaze.dart
Normal file
38
lib/logic/api_maps/backblaze.dart
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:selfprivacy/logic/api_maps/api_map.dart';
|
||||||
|
|
||||||
|
class BackblazeApi extends ApiMap {
|
||||||
|
BackblazeApi([String token]) {
|
||||||
|
if (token != null) {
|
||||||
|
loggedClient.options = BaseOptions(
|
||||||
|
headers: {'Authorization': 'Basic $token'},
|
||||||
|
baseUrl: rootAddress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String rootAddress =
|
||||||
|
'https://api.backblazeb2.com/b2api/v2/b2_authorize_account';
|
||||||
|
|
||||||
|
Future<bool> isValid(String token) async {
|
||||||
|
var options = Options(
|
||||||
|
headers: {'Authorization': 'Basic $token'},
|
||||||
|
validateStatus: (status) {
|
||||||
|
return status == HttpStatus.ok || status == HttpStatus.unauthorized;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Response response = await loggedClient.get(rootAddress, options: options);
|
||||||
|
|
||||||
|
if (response.statusCode == HttpStatus.ok) {
|
||||||
|
print(response);
|
||||||
|
return true;
|
||||||
|
} else if (response.statusCode == HttpStatus.unauthorized) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
throw Exception('code: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,4 +69,14 @@ class HetznerApi extends ApiMap {
|
||||||
startTime: DateTime.now(),
|
startTime: DateTime.now(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<HetznerServerDetails> reset({
|
||||||
|
HetznerServerDetails server,
|
||||||
|
}) async {
|
||||||
|
await loggedClient.post('/${server.id}/actions/poweron');
|
||||||
|
|
||||||
|
return server.copyWith(
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import 'app_config_repository.dart';
|
||||||
|
|
||||||
part 'app_config_state.dart';
|
part 'app_config_state.dart';
|
||||||
|
|
||||||
/// initializeing steps:
|
/// initializeing steps:
|
||||||
/// 1. Hetzner key |setHetznerKey
|
/// 1. Hetzner key |setHetznerKey
|
||||||
/// 2. Cloudflare key |setCloudflareKey
|
/// 2. Cloudflare key |setCloudflareKey
|
||||||
/// 3. Set Domain address |setDomain
|
/// 3. Set Domain address |setDomain
|
||||||
|
@ -34,8 +34,8 @@ class AppConfigCubit extends Cubit<AppConfigState> {
|
||||||
emit(state);
|
emit(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void clearAppConfig() {
|
||||||
repository.reset();
|
repository.clearAppConfig();
|
||||||
emit(InitialAppConfigState());
|
emit(InitialAppConfigState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,16 @@ class AppConfigCubit extends Cubit<AppConfigState> {
|
||||||
state.cloudFlareKey,
|
state.cloudFlareKey,
|
||||||
state.cloudFlareDomain.zoneId,
|
state.cloudFlareDomain.zoneId,
|
||||||
);
|
);
|
||||||
emit(state.copyWith(isDkimSetted: true));
|
var hetznerServerDetails = await repository.reset(
|
||||||
|
state.hetznerKey,
|
||||||
|
state.hetznerServer,
|
||||||
|
);
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
isDkimSetted: true,
|
||||||
|
hetznerServer: hetznerServerDetails,
|
||||||
|
),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
_tryOrAddError(state, callBack);
|
_tryOrAddError(state, callBack);
|
||||||
|
@ -143,4 +152,9 @@ class AppConfigCubit extends Cubit<AppConfigState> {
|
||||||
emit(state);
|
emit(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBackblazeKey(String backblazeKey) {
|
||||||
|
repository.saveBackblazeKey(backblazeKey);
|
||||||
|
emit(state.copyWith(backblazeKey: backblazeKey));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ class AppConfigRepository {
|
||||||
hetznerKey: box.get(BNames.hetznerKey),
|
hetznerKey: box.get(BNames.hetznerKey),
|
||||||
cloudFlareKey: box.get(BNames.cloudFlareKey),
|
cloudFlareKey: box.get(BNames.cloudFlareKey),
|
||||||
cloudFlareDomain: box.get(BNames.cloudFlareDomain),
|
cloudFlareDomain: box.get(BNames.cloudFlareDomain),
|
||||||
|
backblazeKey: box.get(BNames.backblazeKey),
|
||||||
rootUser: box.get(BNames.rootUser),
|
rootUser: box.get(BNames.rootUser),
|
||||||
hetznerServer: box.get(BNames.hetznerServer),
|
hetznerServer: box.get(BNames.hetznerServer),
|
||||||
isServerStarted: box.get(BNames.isServerStarted, defaultValue: false),
|
isServerStarted: box.get(BNames.isServerStarted, defaultValue: false),
|
||||||
|
@ -28,7 +29,7 @@ class AppConfigRepository {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void clearAppConfig() {
|
||||||
box.clear();
|
box.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +37,10 @@ class AppConfigRepository {
|
||||||
box.put(BNames.hetznerKey, key);
|
box.put(BNames.hetznerKey, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void saveBackblazeKey(String key) {
|
||||||
|
box.put(BNames.backblazeKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
void saveCloudFlare(String key) {
|
void saveCloudFlare(String key) {
|
||||||
box.put(BNames.cloudFlareKey, key);
|
box.put(BNames.cloudFlareKey, key);
|
||||||
}
|
}
|
||||||
|
@ -104,12 +109,8 @@ class AppConfigRepository {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<HetznerServerDetails> createServer(
|
Future<HetznerServerDetails> createServer(String hetznerKey, User rootUser,
|
||||||
String hetznerKey,
|
String domainName, String cloudFlareKey) async {
|
||||||
User rootUser,
|
|
||||||
String domainName,
|
|
||||||
String cloudFlareKey
|
|
||||||
) async {
|
|
||||||
var hetznerApi = HetznerApi(hetznerKey);
|
var hetznerApi = HetznerApi(hetznerKey);
|
||||||
var serverDetails = await hetznerApi.createServer(
|
var serverDetails = await hetznerApi.createServer(
|
||||||
cloudFlareKey: cloudFlareKey,
|
cloudFlareKey: cloudFlareKey,
|
||||||
|
@ -164,4 +165,12 @@ class AppConfigRepository {
|
||||||
|
|
||||||
cloudflareApi.close();
|
cloudflareApi.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<HetznerServerDetails> reset(
|
||||||
|
String hetznerKey,
|
||||||
|
HetznerServerDetails server,
|
||||||
|
) async {
|
||||||
|
var hetznerApi = HetznerApi(hetznerKey);
|
||||||
|
return await hetznerApi.reset(server: server);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ class AppConfigState extends Equatable {
|
||||||
const AppConfigState({
|
const AppConfigState({
|
||||||
this.hetznerKey,
|
this.hetznerKey,
|
||||||
this.cloudFlareKey,
|
this.cloudFlareKey,
|
||||||
|
this.backblazeKey,
|
||||||
this.cloudFlareDomain,
|
this.cloudFlareDomain,
|
||||||
this.rootUser,
|
this.rootUser,
|
||||||
this.hetznerServer,
|
this.hetznerServer,
|
||||||
|
@ -20,6 +21,7 @@ class AppConfigState extends Equatable {
|
||||||
List<Object> get props => [
|
List<Object> get props => [
|
||||||
hetznerKey,
|
hetznerKey,
|
||||||
cloudFlareKey,
|
cloudFlareKey,
|
||||||
|
backblazeKey,
|
||||||
cloudFlareDomain,
|
cloudFlareDomain,
|
||||||
rootUser,
|
rootUser,
|
||||||
hetznerServer,
|
hetznerServer,
|
||||||
|
@ -33,6 +35,7 @@ class AppConfigState extends Equatable {
|
||||||
|
|
||||||
final String hetznerKey;
|
final String hetznerKey;
|
||||||
final String cloudFlareKey;
|
final String cloudFlareKey;
|
||||||
|
final String backblazeKey;
|
||||||
final CloudFlareDomain cloudFlareDomain;
|
final CloudFlareDomain cloudFlareDomain;
|
||||||
final User rootUser;
|
final User rootUser;
|
||||||
final HetznerServerDetails hetznerServer;
|
final HetznerServerDetails hetznerServer;
|
||||||
|
@ -47,6 +50,7 @@ class AppConfigState extends Equatable {
|
||||||
AppConfigState copyWith({
|
AppConfigState copyWith({
|
||||||
String hetznerKey,
|
String hetznerKey,
|
||||||
String cloudFlareKey,
|
String cloudFlareKey,
|
||||||
|
String backblazeKey,
|
||||||
CloudFlareDomain cloudFlareDomain,
|
CloudFlareDomain cloudFlareDomain,
|
||||||
User rootUser,
|
User rootUser,
|
||||||
HetznerServerDetails hetznerServer,
|
HetznerServerDetails hetznerServer,
|
||||||
|
@ -61,6 +65,7 @@ class AppConfigState extends Equatable {
|
||||||
AppConfigState(
|
AppConfigState(
|
||||||
hetznerKey: hetznerKey ?? this.hetznerKey,
|
hetznerKey: hetznerKey ?? this.hetznerKey,
|
||||||
cloudFlareKey: cloudFlareKey ?? this.cloudFlareKey,
|
cloudFlareKey: cloudFlareKey ?? this.cloudFlareKey,
|
||||||
|
backblazeKey: backblazeKey ?? this.backblazeKey,
|
||||||
cloudFlareDomain: cloudFlareDomain ?? this.cloudFlareDomain,
|
cloudFlareDomain: cloudFlareDomain ?? this.cloudFlareDomain,
|
||||||
rootUser: rootUser ?? this.rootUser,
|
rootUser: rootUser ?? this.rootUser,
|
||||||
hetznerServer: hetznerServer ?? this.hetznerServer,
|
hetznerServer: hetznerServer ?? this.hetznerServer,
|
||||||
|
@ -76,6 +81,7 @@ class AppConfigState extends Equatable {
|
||||||
|
|
||||||
bool get isHetznerFilled => hetznerKey != null;
|
bool get isHetznerFilled => hetznerKey != null;
|
||||||
bool get isCloudFlareFilled => cloudFlareKey != null;
|
bool get isCloudFlareFilled => cloudFlareKey != null;
|
||||||
|
bool get isBackblazeFilled => backblazeKey != null;
|
||||||
bool get isDomainFilled => cloudFlareDomain != null;
|
bool get isDomainFilled => cloudFlareDomain != null;
|
||||||
bool get isUserFilled => rootUser != null;
|
bool get isUserFilled => rootUser != null;
|
||||||
bool get isServerFilled => hetznerServer != null;
|
bool get isServerFilled => hetznerServer != null;
|
||||||
|
@ -90,6 +96,7 @@ class AppConfigState extends Equatable {
|
||||||
List<bool> get _fulfilementList => [
|
List<bool> get _fulfilementList => [
|
||||||
isHetznerFilled,
|
isHetznerFilled,
|
||||||
isCloudFlareFilled,
|
isCloudFlareFilled,
|
||||||
|
isBackblazeFilled,
|
||||||
isDomainFilled,
|
isDomainFilled,
|
||||||
isUserFilled,
|
isUserFilled,
|
||||||
isServerFilled,
|
isServerFilled,
|
||||||
|
|
81
lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart
Normal file
81
lib/logic/cubit/forms/initializing/backblaze_form_cubit.dart
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:cubit_form/cubit_form.dart';
|
||||||
|
import 'package:selfprivacy/logic/api_maps/backblaze.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart';
|
||||||
|
|
||||||
|
class BackblazeFormCubit extends FormCubit {
|
||||||
|
BackblazeApi apiClient = BackblazeApi();
|
||||||
|
|
||||||
|
BackblazeFormCubit(this.initializingCubit) {
|
||||||
|
//var regExp = RegExp(r"\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]");
|
||||||
|
keyId = FieldCubit(
|
||||||
|
initalValue: '',
|
||||||
|
validations: [
|
||||||
|
RequiredStringValidation('required'),
|
||||||
|
//ValidationModel<String>(
|
||||||
|
//(s) => regExp.hasMatch(s), 'invalid key format'),
|
||||||
|
//LegnthStringValidationWithLenghShowing(64, 'length is [] shoud be 64')
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
applicationKey = FieldCubit(
|
||||||
|
initalValue: '',
|
||||||
|
validations: [
|
||||||
|
RequiredStringValidation('required'),
|
||||||
|
//ValidationModel<String>(
|
||||||
|
//(s) => regExp.hasMatch(s), 'invalid key format'),
|
||||||
|
//LegnthStringValidationWithLenghShowing(64, 'length is [] shoud be 64')
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
super.setFields([keyId, applicationKey]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> onSubmit() async {
|
||||||
|
String encodedApiKey =
|
||||||
|
encodeToBase64(keyId.state.value, applicationKey.state.value);
|
||||||
|
|
||||||
|
initializingCubit.setBackblazeKey(encodedApiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
final AppConfigCubit initializingCubit;
|
||||||
|
|
||||||
|
FieldCubit<String> keyId;
|
||||||
|
|
||||||
|
FieldCubit<String> applicationKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<bool> asyncValidation() async {
|
||||||
|
bool isKeyValid;
|
||||||
|
try {
|
||||||
|
String encodedApiKey =
|
||||||
|
encodeToBase64(keyId.state.value, applicationKey.state.value);
|
||||||
|
isKeyValid = await apiClient.isValid(encodedApiKey);
|
||||||
|
} catch (e) {
|
||||||
|
addError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isKeyValid) {
|
||||||
|
keyId.setError('bad key');
|
||||||
|
applicationKey.setError('bad key');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
apiClient.close();
|
||||||
|
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
String encodeToBase64(String keyId, String applicationKey) {
|
||||||
|
String _apiKey = '$keyId:$applicationKey';
|
||||||
|
String encodedApiKey = base64.encode(utf8.encode(_apiKey));
|
||||||
|
return encodedApiKey;
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,10 +44,23 @@ class _ProgressBarState extends State<ProgressBar> {
|
||||||
} else {
|
} else {
|
||||||
odd.add(step);
|
odd.add(step);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
even.add(Spacer());
|
// even.add(SizedBox(
|
||||||
odd.insert(0, Spacer());
|
// width: 0,
|
||||||
|
// ));
|
||||||
|
odd
|
||||||
|
..insert(
|
||||||
|
0,
|
||||||
|
SizedBox(
|
||||||
|
width: 50,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
..add(
|
||||||
|
SizedBox(
|
||||||
|
width: 50,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:selfprivacy/config/brand_colors.dart';
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
import 'package:selfprivacy/config/brand_theme.dart';
|
import 'package:selfprivacy/config/brand_theme.dart';
|
||||||
import 'package:selfprivacy/config/text_themes.dart';
|
import 'package:selfprivacy/config/text_themes.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/forms/initializing/backblaze_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/cloudflare_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/initializing/cloudflare_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/domain_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/initializing/domain_form_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/forms/initializing/hetzner_form_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/forms/initializing/hetzner_form_cubit.dart';
|
||||||
|
@ -27,12 +28,13 @@ class InitializingPage extends StatelessWidget {
|
||||||
var actualPage = [
|
var actualPage = [
|
||||||
_stepHetzner(cubit),
|
_stepHetzner(cubit),
|
||||||
_stepCloudflare(cubit),
|
_stepCloudflare(cubit),
|
||||||
|
_stepBackblaze(cubit),
|
||||||
_stepDomain(cubit),
|
_stepDomain(cubit),
|
||||||
_stepUser(cubit),
|
_stepUser(cubit),
|
||||||
_stepServer(cubit),
|
_stepServer(cubit),
|
||||||
_stepCheck(cubit),
|
_stepCheck(cubit),
|
||||||
Container(child: Text('Everythigng is initialized'))
|
Container(child: Text('Everythigng is initialized'))
|
||||||
][cubit.state.progress];
|
][2];
|
||||||
return BlocListener<AppConfigCubit, AppConfigState>(
|
return BlocListener<AppConfigCubit, AppConfigState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (state.isFullyInitilized) {
|
if (state.isFullyInitilized) {
|
||||||
|
@ -46,12 +48,13 @@ class InitializingPage extends StatelessWidget {
|
||||||
Padding(
|
Padding(
|
||||||
padding: brandPagePadding1,
|
padding: brandPagePadding1,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ProgressBar(
|
ProgressBar(
|
||||||
steps: [
|
steps: [
|
||||||
'Hetzner',
|
'Hetzner',
|
||||||
'CloudFlare',
|
'CloudFlare',
|
||||||
|
'Backblaze',
|
||||||
'Domain',
|
'Domain',
|
||||||
'User',
|
'User',
|
||||||
'Server',
|
'Server',
|
||||||
|
@ -177,6 +180,55 @@ class InitializingPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _stepBackblaze(AppConfigCubit initializingCubit) {
|
||||||
|
return BlocProvider(
|
||||||
|
create: (context) => BackblazeFormCubit(initializingCubit),
|
||||||
|
child: Builder(builder: (context) {
|
||||||
|
var formCubit = context.watch<BackblazeFormCubit>();
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
Image.asset('assets/images/logos/backblaze.png'),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
BrandText.h2('Подключите облачное хранилище Backblaze'),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
BrandText.body2('Здесь будут храниться данные'),
|
||||||
|
Spacer(),
|
||||||
|
CubitFormTextField(
|
||||||
|
formFieldCubit: formCubit.keyId,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
scrollPadding: EdgeInsets.only(bottom: 70),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'KeyID',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
CubitFormTextField(
|
||||||
|
formFieldCubit: formCubit.applicationKey,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
scrollPadding: EdgeInsets.only(bottom: 70),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Master Application Key',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
BrandButton.rised(
|
||||||
|
onPressed:
|
||||||
|
formCubit.state.isSubmitting ? null : formCubit.trySubmit,
|
||||||
|
title: 'Подключить',
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
BrandButton.text(
|
||||||
|
onPressed: () => _showModal(context, _HowHetzner()),
|
||||||
|
title: 'Как получить API Token',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _stepDomain(AppConfigCubit initializingCubit) {
|
Widget _stepDomain(AppConfigCubit initializingCubit) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => DomainFormCubit(initializingCubit),
|
create: (context) => DomainFormCubit(initializingCubit),
|
||||||
|
@ -296,8 +348,8 @@ class InitializingPage extends StatelessWidget {
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
BrandText.body2(
|
BrandText.body2(
|
||||||
isDnsChecked
|
isDnsChecked
|
||||||
? 'Dns сервера вступили в силу, мы стартанули сервер, как только он поднимиться, мы закончим инициализацию.'
|
? 'Dns сервера вступили в силу, мы стартанули сервер, как только он поднимется, мы закончим инициализацию.'
|
||||||
: 'Мы начали процесс инциализации сервера, раз в минуты мы будем проверять наличие DNS записей, как только они вступят в силу мы продолжим инциализацию',
|
: 'Мы начали процесс инциализации сервера, раз в минуту мы будем проверять наличие DNS записей, как только они вступят в силу мы продолжим инциализацию',
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
Row(
|
Row(
|
||||||
|
|
|
@ -108,7 +108,7 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<AppConfigCubit>().reset();
|
context.read<AppConfigCubit>().clearAppConfig();
|
||||||
Navigator.of(context)..pop()..pop();
|
Navigator.of(context)..pop()..pop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,231 +0,0 @@
|
||||||
// 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);
|
|
||||||
|
|
||||||
// @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;
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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: '''
|
|
||||||
|
|
||||||
// 2 Заходим в созданный нами проект. Если такового - нет, значит создаём.
|
|
||||||
|
|
||||||
// 3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).
|
|
||||||
|
|
||||||
// 4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.
|
|
||||||
|
|
||||||
// 5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку.
|
|
||||||
|
|
||||||
// 6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет.
|
|
||||||
|
|
||||||
// ''',
|
|
||||||
// style: body1Style,
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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(decoration: InputDecoration(hintText: hintText)),
|
|
||||||
// SizedBox(height: 20),
|
|
||||||
// BrandButton.rised(onPressed: () {}, title: submitButtonText),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -1,341 +0,0 @@
|
||||||
// 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:selfprivacy/ui/components/dots_indicator/dots_indicator.dart';
|
|
||||||
// import 'package:selfprivacy/ui/pages/rootRoute.dart';
|
|
||||||
// import 'package:selfprivacy/utils/route_transitions/basic.dart';
|
|
||||||
|
|
||||||
// class InitializingPage extends StatefulWidget {
|
|
||||||
// const InitializingPage({Key key}) : super(key: key);
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// _InitializingPageState createState() => _InitializingPageState();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// class _InitializingPageState extends State<InitializingPage> {
|
|
||||||
// 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) {
|
|
||||||
// var steps = getSteps();
|
|
||||||
|
|
||||||
// return SafeArea(
|
|
||||||
// child: Scaffold(
|
|
||||||
// body: ListView(
|
|
||||||
// shrinkWrap: true,
|
|
||||||
// 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: 'selfprivacy.org/start',
|
|
||||||
// urlString: 'https://selfprivacy.org/start',
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Container(
|
|
||||||
// height: 480,
|
|
||||||
// child: PageView.builder(
|
|
||||||
// physics: NeverScrollableScrollPhysics(),
|
|
||||||
// allowImplicitScrolling: false,
|
|
||||||
// controller: controller,
|
|
||||||
// itemBuilder: (_, index) {
|
|
||||||
// return Padding(
|
|
||||||
// padding: brandPagePadding2,
|
|
||||||
// child: steps[index],
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// itemCount: 4,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// 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),
|
|
||||||
// BrandText.h2('1. Подключите сервер Hetzner'),
|
|
||||||
// SizedBox(height: 10),
|
|
||||||
// BrandText.body2(
|
|
||||||
// 'Здесь будут жить наши данные и SelfPrivacy-сервисы'),
|
|
||||||
// _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),
|
|
||||||
// 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(
|
|
||||||
// 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),
|
|
||||||
// BrandText.h2('3. Подключите CloudFlare DNS'),
|
|
||||||
// SizedBox(height: 10),
|
|
||||||
// BrandText.body2('Для управления DNS вашего домена'),
|
|
||||||
// _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),
|
|
||||||
// BrandText.h2('4. Подключите Amazon AWS для бекапа'),
|
|
||||||
// SizedBox(height: 10),
|
|
||||||
// BrandText.body2(
|
|
||||||
// 'IaaS-провайдер, для бесплатного хранения резервных копии ваших данных в зашифрованном виде'),
|
|
||||||
// _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,
|
|
||||||
// isScrollControlled: true,
|
|
||||||
// backgroundColor: Colors.transparent,
|
|
||||||
// builder: (BuildContext context) {
|
|
||||||
// return widget;
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// void _nextPage() => controller.nextPage(
|
|
||||||
// duration: Duration(milliseconds: 300),
|
|
||||||
// curve: Curves.easeIn,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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: '''
|
|
||||||
|
|
||||||
// 2 Заходим в созданный нами проект. Если такового - нет, значит создаём.
|
|
||||||
|
|
||||||
// 3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).
|
|
||||||
|
|
||||||
// 4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.
|
|
||||||
|
|
||||||
// 5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же вы используете мобильную версию сайта, в нижнем правом углу вы увидите красный плюсик. Нажимаем на эту кнопку.
|
|
||||||
|
|
||||||
// 6 В поле Description, даём нашему токену название (это может быть любое название, которые вам нравиться. Сути оно не меняет.
|
|
||||||
|
|
||||||
// ''',
|
|
||||||
// style: body1Style,
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// class _MockForm extends StatefulWidget {
|
|
||||||
// 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(
|
|
||||||
// onChanged: (value) => {
|
|
||||||
// setState(() {
|
|
||||||
// text = value;
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// decoration: InputDecoration(hintText: widget.hintText),
|
|
||||||
// ),
|
|
||||||
// SizedBox(height: 20),
|
|
||||||
// BrandButton.rised(
|
|
||||||
// onPressed:
|
|
||||||
// text.length == widget.length ? widget.onPressed ?? () {} : null,
|
|
||||||
// title: widget.submitButtonText,
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
Loading…
Reference in a new issue