Compare commits
12 Commits
Author | SHA1 | Date |
---|---|---|
Inex Code | 4930fc2387 | |
Inex Code | 11d0e58334 | |
NaiJi ✨ | a6b846cc78 | |
NaiJi ✨ | 6819192219 | |
NaiJi ✨ | ffdb9d92fb | |
NaiJi ✨ | 1c42598787 | |
dettlaff | c179a109fd | |
def | add2366e6b | |
dettlaff | 0dc281a4f6 | |
dettlaff | a4737e9f05 | |
Inex Code | bf66717854 | |
Inex Code | d3b7f31c65 |
|
@ -40,3 +40,9 @@ app.*.symbols
|
||||||
|
|
||||||
# Obfuscation related
|
# Obfuscation related
|
||||||
app.*.map.json
|
app.*.map.json
|
||||||
|
|
||||||
|
# Flatpak
|
||||||
|
.flatpak-builder/
|
||||||
|
flatpak-build/
|
||||||
|
flatpak-repo/
|
||||||
|
*.flatpak
|
||||||
|
|
|
@ -52,8 +52,8 @@ android {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "org.selfprivacy.app"
|
applicationId "org.selfprivacy.app"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 33
|
targetSdkVersion 34
|
||||||
compileSdkVersion 33
|
compileSdkVersion 34
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
|
|
@ -606,5 +606,16 @@
|
||||||
"reset_onboarding": "Reset onboarding switch",
|
"reset_onboarding": "Reset onboarding switch",
|
||||||
"reset_onboarding_description": "Reset onboarding switch to show onboarding screen again",
|
"reset_onboarding_description": "Reset onboarding switch to show onboarding screen again",
|
||||||
"cubit_statuses": "Cubit loading statuses"
|
"cubit_statuses": "Cubit loading statuses"
|
||||||
|
},
|
||||||
|
"countries": {
|
||||||
|
"germany": "Germany",
|
||||||
|
"netherlands": "Netherlands",
|
||||||
|
"singapore": "Singapore",
|
||||||
|
"united_kingdom": "United Kingdom",
|
||||||
|
"canada": "Canada",
|
||||||
|
"india": "India",
|
||||||
|
"australia": "Australia",
|
||||||
|
"united_states": "United States",
|
||||||
|
"finland": "Finland"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
app-id: org.selfprivacy.app
|
app-id: org.selfprivacy.app
|
||||||
runtime: org.freedesktop.Platform
|
runtime: org.freedesktop.Platform
|
||||||
runtime-version: '22.08'
|
runtime-version: '23.08'
|
||||||
sdk: org.freedesktop.Sdk
|
sdk: org.freedesktop.Sdk
|
||||||
command: selfprivacy
|
command: selfprivacy
|
||||||
finish-args:
|
finish-args:
|
||||||
|
@ -11,6 +11,7 @@ finish-args:
|
||||||
- "--share=network"
|
- "--share=network"
|
||||||
- "--own-name=org.selfprivacy.app"
|
- "--own-name=org.selfprivacy.app"
|
||||||
- "--device=dri"
|
- "--device=dri"
|
||||||
|
- "--talk-name=org.freedesktop.secrets"
|
||||||
modules:
|
modules:
|
||||||
- name: selfprivacy
|
- name: selfprivacy
|
||||||
buildsystem: simple
|
buildsystem: simple
|
||||||
|
@ -35,7 +36,7 @@ modules:
|
||||||
sources:
|
sources:
|
||||||
- type: git
|
- type: git
|
||||||
url: https://gitlab.gnome.org/GNOME/libsecret.git
|
url: https://gitlab.gnome.org/GNOME/libsecret.git
|
||||||
tag: 0.20.5
|
tag: 0.21.4
|
||||||
- name: libjsoncpp
|
- name: libjsoncpp
|
||||||
buildsystem: meson
|
buildsystem: meson
|
||||||
config-opts:
|
config-opts:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart';
|
||||||
|
@ -28,33 +28,47 @@ class HiveConfig {
|
||||||
|
|
||||||
await Hive.openBox(BNames.appSettingsBox);
|
await Hive.openBox(BNames.appSettingsBox);
|
||||||
|
|
||||||
final HiveAesCipher cipher = HiveAesCipher(
|
try {
|
||||||
await getEncryptedKey(BNames.serverInstallationEncryptionKey),
|
final HiveAesCipher cipher = HiveAesCipher(
|
||||||
);
|
await getEncryptedKey(BNames.serverInstallationEncryptionKey),
|
||||||
|
);
|
||||||
|
|
||||||
await Hive.openBox<User>(BNames.usersDeprecated);
|
await Hive.openBox<User>(BNames.usersDeprecated);
|
||||||
await Hive.openBox<User>(BNames.usersBox, encryptionCipher: cipher);
|
await Hive.openBox<User>(BNames.usersBox, encryptionCipher: cipher);
|
||||||
|
|
||||||
final Box<User> deprecatedUsers = Hive.box<User>(BNames.usersDeprecated);
|
final Box<User> deprecatedUsers = Hive.box<User>(BNames.usersDeprecated);
|
||||||
if (deprecatedUsers.isNotEmpty) {
|
if (deprecatedUsers.isNotEmpty) {
|
||||||
final Box<User> users = Hive.box<User>(BNames.usersBox);
|
final Box<User> users = Hive.box<User>(BNames.usersBox);
|
||||||
await users.addAll(deprecatedUsers.values.toList());
|
await users.addAll(deprecatedUsers.values.toList());
|
||||||
await deprecatedUsers.clear();
|
await deprecatedUsers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Hive.openBox(
|
||||||
|
BNames.serverInstallationBox,
|
||||||
|
encryptionCipher: cipher,
|
||||||
|
);
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
print('HiveConfig: Error while opening boxes: $e');
|
||||||
|
rethrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Hive.openBox(BNames.serverInstallationBox, encryptionCipher: cipher);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Uint8List> getEncryptedKey(final String encKey) async {
|
static Future<Uint8List> getEncryptedKey(final String encKey) async {
|
||||||
const FlutterSecureStorage secureStorage = FlutterSecureStorage();
|
const FlutterSecureStorage secureStorage = FlutterSecureStorage();
|
||||||
final bool hasEncryptionKey = await secureStorage.containsKey(key: encKey);
|
try {
|
||||||
if (!hasEncryptionKey) {
|
final bool hasEncryptionKey =
|
||||||
final List<int> key = Hive.generateSecureKey();
|
await secureStorage.containsKey(key: encKey);
|
||||||
await secureStorage.write(key: encKey, value: base64UrlEncode(key));
|
if (!hasEncryptionKey) {
|
||||||
}
|
final List<int> key = Hive.generateSecureKey();
|
||||||
|
await secureStorage.write(key: encKey, value: base64UrlEncode(key));
|
||||||
|
}
|
||||||
|
|
||||||
final String? string = await secureStorage.read(key: encKey);
|
final String? string = await secureStorage.read(key: encKey);
|
||||||
return base64Url.decode(string!);
|
return base64Url.decode(string!);
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
print('HiveConfig: Error while getting encryption key: $e');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,14 +65,59 @@ class DigitalOceanLocation {
|
||||||
emoji = '🇮🇳';
|
emoji = '🇮🇳';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'syd':
|
||||||
|
emoji = '🇦🇺';
|
||||||
|
break;
|
||||||
|
|
||||||
case 'nyc':
|
case 'nyc':
|
||||||
case 'sfo':
|
case 'sfo':
|
||||||
emoji = '🇺🇸';
|
emoji = '🇺🇸';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return emoji;
|
return emoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get countryDisplayKey {
|
||||||
|
String displayKey = 'countries.';
|
||||||
|
switch (slug.substring(0, 3)) {
|
||||||
|
case 'fra':
|
||||||
|
displayKey += 'germany';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ams':
|
||||||
|
displayKey += 'netherlands';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'sgp':
|
||||||
|
displayKey += 'singapore';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'lon':
|
||||||
|
displayKey += 'united_kingdom';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'tor':
|
||||||
|
displayKey += 'canada';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'blr':
|
||||||
|
displayKey += 'india';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'syd':
|
||||||
|
displayKey += 'australia';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'nyc':
|
||||||
|
case 'sfo':
|
||||||
|
displayKey += 'united_states';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
displayKey = slug;
|
||||||
|
}
|
||||||
|
return displayKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
|
@ -155,6 +155,27 @@ class HetznerLocation {
|
||||||
}
|
}
|
||||||
return emoji;
|
return emoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get countryDisplayKey {
|
||||||
|
String displayKey = 'countries.';
|
||||||
|
switch (country.substring(0, 2)) {
|
||||||
|
case 'DE':
|
||||||
|
displayKey += 'germany';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'FI':
|
||||||
|
displayKey += 'finland';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'US':
|
||||||
|
displayKey += 'united_states';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
displayKey = country;
|
||||||
|
}
|
||||||
|
return displayKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Volume is a highly-available, scalable, and SSD-based block storage for Servers.
|
/// A Volume is a highly-available, scalable, and SSD-based block storage for Servers.
|
||||||
|
|
|
@ -2,12 +2,14 @@ class ServerProviderLocation {
|
||||||
ServerProviderLocation({
|
ServerProviderLocation({
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.identifier,
|
required this.identifier,
|
||||||
|
required this.countryDisplayKey,
|
||||||
this.description,
|
this.description,
|
||||||
this.flag = '',
|
this.flag = '',
|
||||||
});
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final String identifier;
|
final String identifier;
|
||||||
|
final String countryDisplayKey;
|
||||||
final String? description;
|
final String? description;
|
||||||
final String flag;
|
final String flag;
|
||||||
}
|
}
|
||||||
|
|
|
@ -438,6 +438,7 @@ class DigitalOceanServerProvider extends ServerProvider {
|
||||||
description: rawLocation.name,
|
description: rawLocation.name,
|
||||||
flag: rawLocation.flag,
|
flag: rawLocation.flag,
|
||||||
identifier: rawLocation.slug,
|
identifier: rawLocation.slug,
|
||||||
|
countryDisplayKey: rawLocation.countryDisplayKey,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -156,6 +156,7 @@ class HetznerServerProvider extends ServerProvider {
|
||||||
description: server.location.description,
|
description: server.location.description,
|
||||||
flag: server.location.flag,
|
flag: server.location.flag,
|
||||||
identifier: server.location.name,
|
identifier: server.location.name,
|
||||||
|
countryDisplayKey: server.location.countryDisplayKey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -456,6 +457,7 @@ class HetznerServerProvider extends ServerProvider {
|
||||||
description: rawLocation.description,
|
description: rawLocation.description,
|
||||||
flag: rawLocation.flag,
|
flag: rawLocation.flag,
|
||||||
identifier: rawLocation.name,
|
identifier: rawLocation.name,
|
||||||
|
countryDisplayKey: rawLocation.countryDisplayKey,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:selfprivacy/config/bloc_config.dart';
|
import 'package:selfprivacy/config/bloc_config.dart';
|
||||||
import 'package:selfprivacy/config/bloc_observer.dart';
|
import 'package:selfprivacy/config/bloc_observer.dart';
|
||||||
|
@ -9,13 +10,20 @@ import 'package:selfprivacy/config/hive_config.dart';
|
||||||
import 'package:selfprivacy/config/localization.dart';
|
import 'package:selfprivacy/config/localization.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart';
|
||||||
import 'package:selfprivacy/theming/factory/app_theme_factory.dart';
|
import 'package:selfprivacy/theming/factory/app_theme_factory.dart';
|
||||||
|
import 'package:selfprivacy/ui/pages/errors/failed_to_init_secure_storage.dart';
|
||||||
import 'package:selfprivacy/ui/router/router.dart';
|
import 'package:selfprivacy/ui/router/router.dart';
|
||||||
// import 'package:wakelock/wakelock.dart';
|
// import 'package:wakelock/wakelock.dart';
|
||||||
import 'package:timezone/data/latest.dart' as tz;
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await HiveConfig.init();
|
try {
|
||||||
|
await HiveConfig.init();
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
runApp(
|
||||||
|
FailedToInitSecureStorageScreen(e: e),
|
||||||
|
);
|
||||||
|
}
|
||||||
// await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
// await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
|
|
|
@ -24,8 +24,10 @@ abstract class AppThemeFactory {
|
||||||
final ColorScheme? dynamicColorsScheme =
|
final ColorScheme? dynamicColorsScheme =
|
||||||
await _getDynamicColors(brightness);
|
await _getDynamicColors(brightness);
|
||||||
|
|
||||||
|
final Color? accentColor = await _getAccentColor();
|
||||||
|
|
||||||
final ColorScheme fallbackColorScheme = ColorScheme.fromSeed(
|
final ColorScheme fallbackColorScheme = ColorScheme.fromSeed(
|
||||||
seedColor: fallbackColor,
|
seedColor: accentColor ?? fallbackColor,
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -55,6 +57,14 @@ abstract class AppThemeFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<Color?> _getAccentColor() {
|
||||||
|
try {
|
||||||
|
return DynamicColorPlugin.getAccentColor();
|
||||||
|
} on PlatformException {
|
||||||
|
return Future.value(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Future<CorePalette?> getCorePalette() async {
|
static Future<CorePalette?> getCorePalette() async {
|
||||||
try {
|
try {
|
||||||
return await DynamicColorPlugin.getCorePalette();
|
return await DynamicColorPlugin.getCorePalette();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:ionicons/ionicons.dart';
|
import 'package:ionicons/ionicons.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||||
|
@ -126,7 +127,9 @@ class _HeroSliverAppBarState extends State<HeroSliverAppBar> {
|
||||||
Widget build(final BuildContext context) {
|
Widget build(final BuildContext context) {
|
||||||
final isMobile =
|
final isMobile =
|
||||||
widget.ignoreBreakpoints ? true : Breakpoints.small.isActive(context);
|
widget.ignoreBreakpoints ? true : Breakpoints.small.isActive(context);
|
||||||
final isJobsListEmpty = context.watch<JobsCubit>().state is JobsStateEmpty;
|
final isJobsListEmpty = widget.hasFlashButton
|
||||||
|
? context.watch<JobsCubit>().state is JobsStateEmpty
|
||||||
|
: true;
|
||||||
return SliverAppBar(
|
return SliverAppBar(
|
||||||
expandedHeight:
|
expandedHeight:
|
||||||
widget.hasHeroIcon ? 148.0 + _size.height : 72.0 + _size.height,
|
widget.hasHeroIcon ? 148.0 + _size.height : 72.0 + _size.height,
|
||||||
|
@ -164,6 +167,7 @@ class _HeroSliverAppBarState extends State<HeroSliverAppBar> {
|
||||||
color: isJobsListEmpty
|
color: isJobsListEmpty
|
||||||
? Theme.of(context).colorScheme.onBackground
|
? Theme.of(context).colorScheme.onBackground
|
||||||
: Theme.of(context).colorScheme.primary,
|
: Theme.of(context).colorScheme.primary,
|
||||||
|
tooltip: 'jobs.title'.tr(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox.shrink(),
|
const SizedBox.shrink(),
|
||||||
|
|
|
@ -100,7 +100,7 @@ class _RootAppBar extends StatelessWidget {
|
||||||
leading: context.router.pageCount > 1
|
leading: context.router.pageCount > 1
|
||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.arrow_back),
|
icon: const Icon(Icons.arrow_back),
|
||||||
onPressed: () => context.router.pop(),
|
onPressed: () => context.router.maybePop(),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
actions: const [
|
actions: const [
|
||||||
|
|
|
@ -38,8 +38,14 @@ class BackupDetailsPage extends StatelessWidget {
|
||||||
: StateType.uninitialized;
|
: StateType.uninitialized;
|
||||||
final bool preventActions = backupsState.preventActions;
|
final bool preventActions = backupsState.preventActions;
|
||||||
final List<Backup> backups = backupsState.backups;
|
final List<Backup> backups = backupsState.backups;
|
||||||
final List<Service> services =
|
final List<Service> services = context
|
||||||
context.watch<ServicesBloc>().state.servicesThatCanBeBackedUp;
|
.watch<ServicesBloc>()
|
||||||
|
.state
|
||||||
|
.servicesThatCanBeBackedUp
|
||||||
|
.where(
|
||||||
|
(final service) => service.isEnabled,
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
final Duration? autobackupPeriod = backupsState.autobackupPeriod;
|
final Duration? autobackupPeriod = backupsState.autobackupPeriod;
|
||||||
final List<ServerJob> backupJobs = context
|
final List<ServerJob> backupJobs = context
|
||||||
.watch<ServerJobsBloc>()
|
.watch<ServerJobsBloc>()
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/backups/backups_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/server_jobs/server_jobs_bloc.dart';
|
||||||
|
import 'package:selfprivacy/logic/bloc/volumes/volumes_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
import 'package:selfprivacy/logic/models/json/server_job.dart';
|
||||||
import 'package:selfprivacy/logic/models/service.dart';
|
import 'package:selfprivacy/logic/models/service.dart';
|
||||||
|
|
||||||
|
@ -103,6 +104,29 @@ class _CreateBackupsModalState extends State<CreateBackupsModal> {
|
||||||
...widget.services.map(
|
...widget.services.map(
|
||||||
(final Service service) {
|
(final Service service) {
|
||||||
final bool busy = busyServices.contains(service.id);
|
final bool busy = busyServices.contains(service.id);
|
||||||
|
final List<Widget> descriptionWidgets = [];
|
||||||
|
if (busy) {
|
||||||
|
descriptionWidgets.add(Text('backup.service_busy'.tr()));
|
||||||
|
} else {
|
||||||
|
descriptionWidgets.add(
|
||||||
|
Text(
|
||||||
|
'service_page.uses'.tr(
|
||||||
|
namedArgs: {
|
||||||
|
'usage': service.storageUsage.used.toString(),
|
||||||
|
'volume': context
|
||||||
|
.read<VolumesBloc>()
|
||||||
|
.state
|
||||||
|
.getVolume(service.storageUsage.volume ?? '')
|
||||||
|
.displayName,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
style: Theme.of(context).textTheme.labelMedium,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
descriptionWidgets.add(
|
||||||
|
Text(service.backupDescription),
|
||||||
|
);
|
||||||
|
}
|
||||||
return CheckboxListTile.adaptive(
|
return CheckboxListTile.adaptive(
|
||||||
onChanged: !busy
|
onChanged: !busy
|
||||||
? (final bool? value) {
|
? (final bool? value) {
|
||||||
|
@ -122,8 +146,9 @@ class _CreateBackupsModalState extends State<CreateBackupsModal> {
|
||||||
title: Text(
|
title: Text(
|
||||||
service.displayName,
|
service.displayName,
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Column(
|
||||||
busy ? 'backup.service_busy'.tr() : service.backupDescription,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: descriptionWidgets,
|
||||||
),
|
),
|
||||||
secondary: SvgPicture.string(
|
secondary: SvgPicture.string(
|
||||||
service.svgIcon,
|
service.svgIcon,
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||||
|
import 'package:selfprivacy/ui/pages/more/about_application.dart';
|
||||||
|
|
||||||
|
class FailedToInitSecureStorageScreen extends StatelessWidget {
|
||||||
|
const FailedToInitSecureStorageScreen({
|
||||||
|
required this.e,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final PlatformException e;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(final BuildContext context) => MaterialApp(
|
||||||
|
home: BrandHeroScreen(
|
||||||
|
heroIcon: Icons.error_outline,
|
||||||
|
heroTitle: 'Failed to initialize secure storage',
|
||||||
|
hasBackButton: false,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'SelfPrivacy requires a secure storage provided by your operating system to encrypt sensitive data, but it failed to initialize.',
|
||||||
|
),
|
||||||
|
if (Platform.isLinux)
|
||||||
|
const Text(
|
||||||
|
'Please make sure that the libsecret library is installed.',
|
||||||
|
),
|
||||||
|
const Gap(16),
|
||||||
|
Text('Error: ${e.message}'),
|
||||||
|
const Gap(16),
|
||||||
|
const Divider(),
|
||||||
|
const Gap(16),
|
||||||
|
const LinkListTile(
|
||||||
|
title: 'Our website',
|
||||||
|
subtitle: 'selfprivacy.org',
|
||||||
|
uri: 'https://selfprivacy.org/',
|
||||||
|
icon: Icons.language_outlined,
|
||||||
|
),
|
||||||
|
const LinkListTile(
|
||||||
|
title: 'Documentation',
|
||||||
|
subtitle: 'selfprivacy.org/docs',
|
||||||
|
uri: 'https://selfprivacy.org/docs/',
|
||||||
|
icon: Icons.library_books_outlined,
|
||||||
|
),
|
||||||
|
const LinkListTile(
|
||||||
|
title: 'Privacy Policy',
|
||||||
|
subtitle: 'selfprivacy.org/privacy-policy',
|
||||||
|
uri: 'https://selfprivacy.org/privacy-policy/',
|
||||||
|
icon: Icons.policy_outlined,
|
||||||
|
),
|
||||||
|
const LinkListTile(
|
||||||
|
title: 'Matrix support chat',
|
||||||
|
subtitle: '#chat:selfprivacy.org',
|
||||||
|
uri: 'https://matrix.to/#/#chat:selfprivacy.org',
|
||||||
|
icon: Icons.question_answer_outlined,
|
||||||
|
longPressText: '#chat:selfprivacy.org',
|
||||||
|
),
|
||||||
|
const LinkListTile(
|
||||||
|
title: 'Telegram support chat',
|
||||||
|
subtitle: '@selfprivacy_chat',
|
||||||
|
uri: 'https://t.me/selfprivacy_chat',
|
||||||
|
icon: Icons.question_answer_outlined,
|
||||||
|
longPressText: '@selfprivacy_chat',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
|
@ -35,7 +35,8 @@ class CpuChart extends StatelessWidget {
|
||||||
lineTouchData: LineTouchData(
|
lineTouchData: LineTouchData(
|
||||||
enabled: true,
|
enabled: true,
|
||||||
touchTooltipData: LineTouchTooltipData(
|
touchTooltipData: LineTouchTooltipData(
|
||||||
tooltipBgColor: Theme.of(context).colorScheme.surface,
|
getTooltipColor: (final LineBarSpot _) =>
|
||||||
|
Theme.of(context).colorScheme.surface,
|
||||||
tooltipPadding: const EdgeInsets.all(8),
|
tooltipPadding: const EdgeInsets.all(8),
|
||||||
getTooltipItems: (final List<LineBarSpot> touchedBarSpots) {
|
getTooltipItems: (final List<LineBarSpot> touchedBarSpots) {
|
||||||
final List<LineTooltipItem> res = [];
|
final List<LineTooltipItem> res = [];
|
||||||
|
|
|
@ -38,7 +38,8 @@ class NetworkChart extends StatelessWidget {
|
||||||
lineTouchData: LineTouchData(
|
lineTouchData: LineTouchData(
|
||||||
enabled: true,
|
enabled: true,
|
||||||
touchTooltipData: LineTouchTooltipData(
|
touchTooltipData: LineTouchTooltipData(
|
||||||
tooltipBgColor: Theme.of(context).colorScheme.surface,
|
getTooltipColor: (final LineBarSpot _) =>
|
||||||
|
Theme.of(context).colorScheme.surface,
|
||||||
tooltipPadding: const EdgeInsets.all(8),
|
tooltipPadding: const EdgeInsets.all(8),
|
||||||
getTooltipItems: (final List<LineBarSpot> touchedBarSpots) {
|
getTooltipItems: (final List<LineBarSpot> touchedBarSpots) {
|
||||||
final List<LineTooltipItem> res = [];
|
final List<LineTooltipItem> res = [];
|
||||||
|
|
|
@ -43,8 +43,8 @@ class _ServerStoragePageState extends State<ServerStoragePage> {
|
||||||
return BrandHeroScreen(
|
return BrandHeroScreen(
|
||||||
hasBackButton: true,
|
hasBackButton: true,
|
||||||
heroTitle: 'storage.card_title'.tr(),
|
heroTitle: 'storage.card_title'.tr(),
|
||||||
|
bodyPadding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
children: [
|
children: [
|
||||||
// ...sections,
|
|
||||||
...widget.diskStatus.diskVolumes.map(
|
...widget.diskStatus.diskVolumes.map(
|
||||||
(final volume) => Column(
|
(final volume) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
@ -87,24 +87,35 @@ class ServerStorageSection extends StatelessWidget {
|
||||||
Widget build(final BuildContext context) => Column(
|
Widget build(final BuildContext context) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ServerStorageListItem(
|
Padding(
|
||||||
volume: volume,
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
|
child: ServerStorageListItem(
|
||||||
|
volume: volume,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
...services.map(
|
...services.map(
|
||||||
(final service) => ServerConsumptionListTile(
|
(final service) => ServerConsumptionListTile(
|
||||||
service: service,
|
service: service,
|
||||||
volume: volume,
|
volume: volume,
|
||||||
|
onTap: () {
|
||||||
|
context.pushRoute(
|
||||||
|
ServiceRoute(serviceId: service.id),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (volume.isResizable) ...[
|
if (volume.isResizable) ...[
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
BrandOutlinedButton(
|
Padding(
|
||||||
title: 'storage.extend_volume_button.title'.tr(),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
onPressed: () => context.pushRoute(
|
child: BrandOutlinedButton(
|
||||||
ExtendingVolumeRoute(
|
title: 'storage.extend_volume_button.title'.tr(),
|
||||||
diskVolumeToResize: volume,
|
onPressed: () => context.pushRoute(
|
||||||
diskStatus: diskStatus,
|
ExtendingVolumeRoute(
|
||||||
|
diskVolumeToResize: volume,
|
||||||
|
diskStatus: diskStatus,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -117,33 +128,38 @@ class ServerConsumptionListTile extends StatelessWidget {
|
||||||
const ServerConsumptionListTile({
|
const ServerConsumptionListTile({
|
||||||
required this.service,
|
required this.service,
|
||||||
required this.volume,
|
required this.volume,
|
||||||
|
required this.onTap,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Service service;
|
final Service service;
|
||||||
final DiskVolume volume;
|
final DiskVolume volume;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(final BuildContext context) => Padding(
|
Widget build(final BuildContext context) => InkWell(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
onTap: onTap,
|
||||||
child: ConsumptionListItem(
|
child: Padding(
|
||||||
title: service.displayName,
|
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
|
||||||
icon: SvgPicture.string(
|
child: ConsumptionListItem(
|
||||||
service.svgIcon,
|
title: service.displayName,
|
||||||
width: 24.0,
|
icon: SvgPicture.string(
|
||||||
height: 24.0,
|
service.svgIcon,
|
||||||
colorFilter: ColorFilter.mode(
|
width: 22.0,
|
||||||
Theme.of(context).colorScheme.onBackground,
|
height: 24.0,
|
||||||
BlendMode.srcIn,
|
colorFilter: ColorFilter.mode(
|
||||||
|
Theme.of(context).colorScheme.onBackground,
|
||||||
|
BlendMode.srcIn,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
rightSideText: service.storageUsage.used.toString(),
|
||||||
|
percentage: service.storageUsage.used.byte / volume.sizeTotal.byte,
|
||||||
|
color: volume.root
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Theme.of(context).colorScheme.secondary,
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
|
dense: true,
|
||||||
),
|
),
|
||||||
rightSideText: service.storageUsage.used.toString(),
|
|
||||||
percentage: service.storageUsage.used.byte / volume.sizeTotal.byte,
|
|
||||||
color: volume.root
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Theme.of(context).colorScheme.secondary,
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
|
|
||||||
dense: true,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
import 'package:selfprivacy/logic/bloc/services/services_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/services/services_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/bloc/volumes/volumes_bloc.dart';
|
import 'package:selfprivacy/logic/bloc/volumes/volumes_bloc.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
import 'package:selfprivacy/logic/cubit/client_jobs/client_jobs_cubit.dart';
|
||||||
|
@ -11,6 +12,7 @@ import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
||||||
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart';
|
||||||
import 'package:selfprivacy/ui/router/router.dart';
|
import 'package:selfprivacy/ui/router/router.dart';
|
||||||
import 'package:selfprivacy/utils/launch_url.dart';
|
import 'package:selfprivacy/utils/launch_url.dart';
|
||||||
|
import 'package:selfprivacy/utils/platform_adapter.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class ServicePage extends StatefulWidget {
|
class ServicePage extends StatefulWidget {
|
||||||
|
@ -65,6 +67,11 @@ class _ServicePageState extends State<ServicePage> {
|
||||||
ListTile(
|
ListTile(
|
||||||
iconColor: Theme.of(context).colorScheme.onBackground,
|
iconColor: Theme.of(context).colorScheme.onBackground,
|
||||||
onTap: () => launchURL(service.url),
|
onTap: () => launchURL(service.url),
|
||||||
|
onLongPress: () {
|
||||||
|
PlatformAdapter.setClipboard(service.url!);
|
||||||
|
getIt<NavigationService>()
|
||||||
|
.showSnackBar('basis.copied_to_clipboard'.tr());
|
||||||
|
},
|
||||||
leading: const Icon(Icons.open_in_browser),
|
leading: const Icon(Icons.open_in_browser),
|
||||||
title: Text(
|
title: Text(
|
||||||
'service_page.open_in_browser'.tr(),
|
'service_page.open_in_browser'.tr(),
|
||||||
|
|
|
@ -57,7 +57,7 @@ class _DnsProviderPickerState extends State<DnsProviderPicker> {
|
||||||
providerCubit: widget.formCubit,
|
providerCubit: widget.formCubit,
|
||||||
providerInfo: const ProviderPageInfo(
|
providerInfo: const ProviderPageInfo(
|
||||||
providerType: DnsProviderType.digitalOcean,
|
providerType: DnsProviderType.digitalOcean,
|
||||||
pathToHow: 'how_digital_ocean_dns',
|
pathToHow: 'how_digital_ocean',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,9 @@ class InitializingPage extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (cubit.state is ServerInstallationEmpty ||
|
if (cubit.state is ServerInstallationEmpty ||
|
||||||
cubit.state is ServerInstallationNotFinished)
|
cubit.state is ServerInstallationNotFinished &&
|
||||||
|
cubit.state.progress ==
|
||||||
|
ServerSetupProgress.nothingYet)
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: BrandButton.filled(
|
child: BrandButton.filled(
|
||||||
|
|
|
@ -120,6 +120,14 @@ class SelectLocationPage extends StatelessWidget {
|
||||||
.titleMedium,
|
.titleMedium,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
location.countryDisplayKey.tr(),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium,
|
||||||
|
),
|
||||||
|
if (location.description != null)
|
||||||
|
const SizedBox(height: 4),
|
||||||
if (location.description != null)
|
if (location.description != null)
|
||||||
Text(
|
Text(
|
||||||
location.description!,
|
location.description!,
|
||||||
|
|
|
@ -38,7 +38,7 @@ class NewUserPage extends StatelessWidget {
|
||||||
return BlocListener<UserFormCubit, FormCubitState>(
|
return BlocListener<UserFormCubit, FormCubitState>(
|
||||||
listener: (final BuildContext context, final FormCubitState state) {
|
listener: (final BuildContext context, final FormCubitState state) {
|
||||||
if (state.isSubmitted) {
|
if (state.isSubmitted) {
|
||||||
context.router.pop();
|
context.router.maybePop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: BrandHeroScreen(
|
child: BrandHeroScreen(
|
||||||
|
|
|
@ -103,7 +103,7 @@ class _DeleteUserTile extends StatelessWidget {
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text('basis.cancel'.tr()),
|
child: Text('basis.cancel'.tr()),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.router.pop();
|
context.router.maybePop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
|
@ -115,8 +115,8 @@ class _DeleteUserTile extends StatelessWidget {
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<JobsCubit>().addJob(DeleteUserJob(user: user));
|
context.read<JobsCubit>().addJob(DeleteUserJob(user: user));
|
||||||
context.router.childControllers.first.pop();
|
context.router.childControllers.first.maybePop();
|
||||||
context.router.pop();
|
context.router.maybePop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -244,7 +244,7 @@ class _SshKeysCard extends StatelessWidget {
|
||||||
publicKey: key,
|
publicKey: key,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
context.popRoute();
|
context.maybePop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
444
pubspec.lock
444
pubspec.lock
File diff suppressed because it is too large
Load Diff
38
pubspec.yaml
38
pubspec.yaml
|
@ -5,30 +5,29 @@ version: 0.11.0+22
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.2.1 <4.0.0'
|
sdk: '>=3.2.1 <4.0.0'
|
||||||
flutter: ">=3.16.1"
|
flutter: ">=3.19.5"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
animations: ^2.0.8
|
animations: ^2.0.11
|
||||||
auto_route: ^7.8.4
|
auto_route: ^8.0.3
|
||||||
auto_size_text: ^3.0.0
|
auto_size_text: ^3.0.0
|
||||||
bloc_concurrency: ^0.2.3
|
bloc_concurrency: ^0.2.5
|
||||||
crypt: ^4.3.1
|
crypt: ^4.3.1
|
||||||
collection: ^1.18.0
|
collection: ^1.18.0
|
||||||
cubit_form: ^2.0.1
|
cubit_form: ^2.0.1
|
||||||
device_info_plus: ^9.1.1
|
device_info_plus: ^10.0.1
|
||||||
dio: ^5.4.0
|
dio: ^5.4.2+1
|
||||||
duration: ^3.0.13
|
duration: ^3.0.13
|
||||||
dynamic_color: ^1.6.8
|
dynamic_color: ^1.7.0
|
||||||
easy_localization: ^3.0.3
|
easy_localization: ^3.0.5
|
||||||
either_option: ^2.0.1-dev.1
|
|
||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
fl_chart: ^0.65.0
|
fl_chart: ^0.67.0
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_bloc: ^8.1.3
|
flutter_bloc: ^8.1.5
|
||||||
flutter_markdown: ^0.6.18+2
|
flutter_markdown: ^0.6.22
|
||||||
flutter_secure_storage: ^9.0.0
|
flutter_secure_storage: ^9.0.0
|
||||||
flutter_svg: ^2.0.9
|
flutter_svg: ^2.0.10+1
|
||||||
gap: ^3.0.1
|
gap: ^3.0.1
|
||||||
get_it: ^7.6.4
|
get_it: ^7.6.4
|
||||||
gql: ^1.0.0
|
gql: ^1.0.0
|
||||||
|
@ -38,12 +37,11 @@ dependencies:
|
||||||
hive: ^2.2.3
|
hive: ^2.2.3
|
||||||
hive_flutter: ^1.1.0
|
hive_flutter: ^1.1.0
|
||||||
http: ^1.1.2
|
http: ^1.1.2
|
||||||
intl: ^0.18.0
|
intl: ^0.18.1
|
||||||
ionicons: ^0.2.2
|
ionicons: ^0.2.2
|
||||||
json_annotation: ^4.8.1
|
json_annotation: ^4.8.1
|
||||||
local_auth: ^2.1.7
|
material_color_utilities: ^0.8.0
|
||||||
material_color_utilities: ^0.5.0
|
modal_bottom_sheet: ^3.0.0
|
||||||
modal_bottom_sheet: ^3.0.0-pre
|
|
||||||
nanoid: ^1.0.0
|
nanoid: ^1.0.0
|
||||||
package_info: ^2.0.2
|
package_info: ^2.0.2
|
||||||
pretty_dio_logger: ^1.3.1
|
pretty_dio_logger: ^1.3.1
|
||||||
|
@ -55,14 +53,14 @@ dependencies:
|
||||||
# wakelock: ^0.6.2
|
# wakelock: ^0.6.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
auto_route_generator: ^7.3.2
|
auto_route_generator: ^8.0.0
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.9
|
||||||
flutter_launcher_icons: ^0.13.1
|
flutter_launcher_icons: ^0.13.1
|
||||||
hive_generator: ^2.0.1
|
hive_generator: ^2.0.1
|
||||||
json_serializable: ^6.7.1
|
json_serializable: ^6.7.1
|
||||||
flutter_lints: ^3.0.1
|
flutter_lints: ^3.0.2
|
||||||
|
|
||||||
flutter_icons:
|
flutter_icons:
|
||||||
android: "launcher_icon"
|
android: "launcher_icon"
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||||
#include <dynamic_color/dynamic_color_plugin_c_api.h>
|
#include <dynamic_color/dynamic_color_plugin_c_api.h>
|
||||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||||
#include <local_auth_windows/local_auth_plugin.h>
|
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
@ -19,8 +18,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
|
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
|
||||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||||
LocalAuthPluginRegisterWithRegistrar(
|
|
||||||
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
|
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
connectivity_plus
|
connectivity_plus
|
||||||
dynamic_color
|
dynamic_color
|
||||||
flutter_secure_storage_windows
|
flutter_secure_storage_windows
|
||||||
local_auth_windows
|
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue