Merge branch 'master' into release-party

pull/158/head
NaiJi ✨ 2022-12-31 10:06:34 +04:00
commit e0c04468bc
10 changed files with 2243 additions and 1827 deletions

View File

@ -0,0 +1,33 @@
Server setup:
- Added support for Digital Ocean as server provider
- You can now choose server region
- You can now choose server tier
- Server installation UI has been refreshed
- Fields now have more specific error messages
Common UI:
- New app bar used in most of the screens
Services:
- Services are now sorted by their status
Server settings:
- Timezone search screen now has a search bar
- Fixed job creation when switching the setting multiple times
- Server destruction now works
Jobs:
- Jobs panel now should take slightly less space
Auth:
- Recovery key page can now be reloaded by dragging down
Logging:
- Log console now has a limit of 500 lines
- GraphQL API requests are now logged in the console
- Networks errors are better handled
For developers:
- App now only uses GraphQL API to communicate with the server. All REST API calls have been removed.
- Server can now be deployed with staging ACME certificates
- Language assets have been reorganized

File diff suppressed because it is too large Load Diff

View File

@ -4,5 +4,5 @@ class StagingOptions {
/// Whether we request for staging temprorary certificates. /// Whether we request for staging temprorary certificates.
/// Hardcode to 'true' in the middle of testing to not /// Hardcode to 'true' in the middle of testing to not
/// get your domain banned by constant certificate renewal /// get your domain banned by constant certificate renewal
static bool get stagingAcme => true; static bool get stagingAcme => false;
} }

View File

@ -9,5 +9,9 @@ class ConsoleModel extends ChangeNotifier {
void addMessage(final Message message) { void addMessage(final Message message) {
messages.add(message); messages.add(message);
notifyListeners(); notifyListeners();
// Make sure we don't have too many messages
if (messages.length > 500) {
messages.removeAt(0);
}
} }
} }

View File

@ -105,13 +105,13 @@ class ServiceStorageUsage {
} }
enum ServiceStatus { enum ServiceStatus {
failed,
reloading,
activating, activating,
active, active,
deactivating, deactivating,
failed,
inactive, inactive,
off, off;
reloading;
factory ServiceStatus.fromGraphQL(final Enum$ServiceStatusEnum graphQL) { factory ServiceStatus.fromGraphQL(final Enum$ServiceStatusEnum graphQL) {
switch (graphQL) { switch (graphQL) {

View File

@ -15,7 +15,7 @@ class BrandBottomSheet extends StatelessWidget {
Widget build(final BuildContext context) { Widget build(final BuildContext context) {
final double mainHeight = MediaQuery.of(context).size.height - final double mainHeight = MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top - MediaQuery.of(context).padding.top -
100; 300;
late Widget innerWidget; late Widget innerWidget;
if (isExpended) { if (isExpended) {
innerWidget = Scaffold( innerWidget = Scaffold(
@ -29,31 +29,28 @@ class BrandBottomSheet extends StatelessWidget {
child: IntrinsicHeight(child: child), child: IntrinsicHeight(child: child),
); );
} }
return ConstrainedBox( return Column(
constraints: BoxConstraints(maxHeight: mainHeight + 4 + 6), mainAxisSize: MainAxisSize.min,
child: Column( children: [
mainAxisSize: MainAxisSize.min, Center(
children: [ child: Container(
Center( height: 4,
child: Container( width: 30,
height: 4, decoration: BoxDecoration(
width: 30, borderRadius: BorderRadius.circular(2),
decoration: BoxDecoration( color: BrandColors.gray4,
borderRadius: BorderRadius.circular(2),
color: BrandColors.gray4,
),
), ),
), ),
const SizedBox(height: 6), ),
ClipRRect( const SizedBox(height: 6),
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)), ClipRRect(
child: ConstrainedBox( borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
constraints: BoxConstraints(maxHeight: mainHeight), child: ConstrainedBox(
child: innerWidget, constraints: BoxConstraints(maxHeight: mainHeight),
), child: innerWidget,
), ),
], ),
), ],
); );
} }
} }

View File

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart'; import 'package:selfprivacy/logic/common_enum/common_enum.dart';
@ -82,7 +84,10 @@ class CpuChart extends StatelessWidget {
), ),
], ],
minY: 0, minY: 0,
maxY: 100, // Maximal value of data by 100 step
maxY:
((data.map((final e) => e.value).reduce(max) - 1) / 100).ceil() *
100.0,
minX: 0, minX: 0,
titlesData: FlTitlesData( titlesData: FlTitlesData(
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),

View File

@ -41,6 +41,10 @@ class _ServicesPageState extends State<ServicesPage> {
final isReady = context.watch<ServerInstallationCubit>().state final isReady = context.watch<ServerInstallationCubit>().state
is ServerInstallationFinished; is ServerInstallationFinished;
final services = [...context.watch<ServicesCubit>().state.services];
services
.sort((final a, final b) => a.status.index.compareTo(b.status.index));
return Scaffold( return Scaffold(
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(52), preferredSize: const Size.fromHeight(52),
@ -58,10 +62,7 @@ class _ServicesPageState extends State<ServicesPage> {
BrandText.body1('basis.services_title'.tr()), BrandText.body1('basis.services_title'.tr()),
const SizedBox(height: 24), const SizedBox(height: 24),
if (!isReady) ...[const NotReadyCard(), const SizedBox(height: 24)], if (!isReady) ...[const NotReadyCard(), const SizedBox(height: 24)],
...context ...services
.read<ServicesCubit>()
.state
.services
.map( .map(
(final service) => Padding( (final service) => Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(

View File

@ -254,9 +254,9 @@ class SelectTypePage extends StatelessWidget {
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
'initializing.choose_server_type_storage' 'initializing.choose_server_type_storage'
.tr(args: [ .tr(
type.disk.gibibyte.toString() args: [type.disk.gibibyte.toString()],
]), ),
style: style:
Theme.of(context).textTheme.bodyMedium, Theme.of(context).textTheme.bodyMedium,
), ),
@ -275,9 +275,11 @@ class SelectTypePage extends StatelessWidget {
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
'initializing.choose_server_type_payment_per_month' 'initializing.choose_server_type_payment_per_month'
.tr(args: [ .tr(
'${type.price.value.toString()} ${type.price.currency}' args: [
]), '${type.price.value.toString()} ${type.price.currency}'
],
),
style: style:
Theme.of(context).textTheme.bodyLarge, Theme.of(context).textTheme.bodyLarge,
), ),

View File

@ -1,7 +1,7 @@
name: selfprivacy name: selfprivacy
description: selfprivacy.org description: selfprivacy.org
publish_to: 'none' publish_to: 'none'
version: 0.7.0+16 version: 0.8.0+17
environment: environment:
sdk: '>=2.17.0 <3.0.0' sdk: '>=2.17.0 <3.0.0'