refactor(platform): guard usages of dart:io and dart:html for future compatability

This commit is contained in:
Jagandeep Brar
2022-03-18 12:23:42 -04:00
parent 403edc16fb
commit c7bd62de2e
52 changed files with 159 additions and 220 deletions

View File

@@ -1,59 +1 @@
{
"motd": "Welcome to LunaSea v10.0.0!\n\nThis update does not have a lot of user-facing changes but introduces substantial reworkings of core integrations and processes that will help make new releases of LunaSea more stable and easier to deploy in the future.",
"new": [
{
"module": "Networking",
"changes": [
"(HTTP) Set user-agent to \"LunaSea/{version} {build}\""
]
},
{
"module": "Radarr",
"changes": [
"(Files) Show additional media metadata"
]
},
{
"module": "Settings",
"changes": [
"(Resources) Add test build information"
]
},
{
"module": "Sonarr",
"changes": [
"(Series) Support for searching entire series for monitored episodes"
]
},
{
"module": "UI/UX",
"changes": [
"(Block) Support skeleton-state loading"
]
}
],
"tweaks": [],
"fixes": [
{
"module": "Database",
"changes": [
"Database entries could be unloaded from memory in some cases"
]
},
{
"module": "Radarr",
"changes": [
"(Availability) Prevent using preDB availability for movies",
"(System Status) Hide irrelevant lines on about page for some installations"
]
},
{
"module": "UI/UX",
"changes": [
"(ListView) Correctly handle pull-to-refresh drag action on all platforms",
"(Input Bar) Saving inputs would not actually update the underlying value in some cases"
]
}
],
"platform": []
}
{}

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:lunasea/core.dart';

View File

@@ -1,4 +1,3 @@
import 'dart:typed_data';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:lunasea/core.dart';

View File

@@ -17,7 +17,7 @@ import 'package:lunasea/modules/tautulli.dart';
import '../modules/dashboard/core/database.dart';
import '../modules/dashboard/core/state.dart' as dashboard_state;
import '../modules/dashboard/routes/dashboard/route.dart' as dashboard_home;
import '../modules/wake_on_lan/api/api.dart';
import '../modules/wake_on_lan/api/wake_on_lan.dart';
part 'modules.g.dart';

View File

@@ -1,4 +1,3 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/main.dart';
@@ -19,11 +18,7 @@ import '../../modules/dashboard/routes/routes.dart' as dashboard;
class LunaRouter {
static FluroRouter router = FluroRouter();
static TransitionType get transitionType {
// Required otherwise no transition is executed
if (Platform.isMacOS) return TransitionType.cupertino;
return TransitionType.native;
}
static TransitionType get transitionType => TransitionType.native;
/// Calls `defineAllRoutes()` on all module routers that implement [LunaModuleRouter].
void initialize() {

View File

@@ -1,9 +1,7 @@
export 'system/configuration.dart';
export 'system/desktop_window.dart';
export 'system/filesystem.dart';
export 'system/flavor.dart';
export 'system/in_app_purchases.dart';
export 'system/localization.dart';
export 'system/networking.dart';
export 'system/profile.dart';
export 'system/quick_actions.dart';

View File

@@ -1,17 +1,17 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
import 'platform.dart';
class LunaDesktopWindow {
static const double _MINIMUM_WINDOW_SIZE = 400;
static const double _INITIAL_WINDOW_SIZE = 700;
static bool get isPlatformCompatible =>
Platform.isWindows || Platform.isMacOS || Platform.isLinux;
static bool get isSupported => LunaPlatform().isDesktop;
Future<void> initialize() async {
if (isPlatformCompatible) {
if (isSupported) {
await windowManager.ensureInitialized();
windowManager.waitUntilReadyToShow().then((_) async {
const Size minSize = Size(_MINIMUM_WINDOW_SIZE, _MINIMUM_WINDOW_SIZE);
@@ -27,7 +27,7 @@ class LunaDesktopWindow {
}
Future<void> setWindowTitle(String title) async {
if (isPlatformCompatible) {
if (isSupported) {
windowManager
.waitUntilReadyToShow()
.then((_) async => await windowManager.setTitle(title));

View File

@@ -1,2 +0,0 @@
export 'filesystem/file.dart';
export 'filesystem/filesystem.dart';

View File

@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
import 'file.dart';
import './platform/filesystem_stub.dart'
if (dart.library.io) './platform/filesystem_io.dart'
if (dart.library.html) './platform/filesystem_web.dart';
import 'platform/filesystem_stub.dart'
if (dart.library.io) 'platform/filesystem_io.dart'
if (dart.library.html) 'platform/filesystem_html.dart';
abstract class LunaFileSystem {
static bool get isSupported => isPlatformSupported();

View File

@@ -1,5 +1,5 @@
import '../filesystem.dart';
import './platform_web.dart';
import 'platform_web.dart';
bool isPlatformSupported() => false;
LunaFileSystem getFileSystem() => Web();

View File

@@ -1,8 +1,8 @@
import 'package:flutter/foundation.dart';
import '../filesystem.dart';
import './platform_desktop.dart';
import './platform_mobile.dart';
import 'platform_desktop.dart';
import 'platform_mobile.dart';
bool isPlatformSupported() {
switch (defaultTargetPlatform) {

View File

@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:lunasea/core.dart';
import 'platform.dart';
extension ProductDetailsExtension on ProductDetails {
IconData get icon {
@@ -54,7 +54,7 @@ class LunaInAppPurchases {
static List<ProductDetails> donationIAPs = [];
static bool isAvailable = false;
static bool get isPlatformCompatible => Platform.isAndroid || Platform.isIOS;
static bool get isSupported => LunaPlatform().isMobile;
/// Callback function for [purchaseStream].
static Future<void> _purchasedCallback(
@@ -74,7 +74,7 @@ class LunaInAppPurchases {
/// - Attach [InAppPurchaseConnection.instance.purchaseUpdateStream] listener for automatically completing IAP purchases
/// - Fetch and store donation IAPs
Future<void> initialize() async {
if (isPlatformCompatible) {
if (isSupported) {
isAvailable = await connection.isAvailable();
if (isAvailable) {
// Open listener

View File

@@ -1,42 +0,0 @@
import 'dart:io';
import 'package:lunasea/core.dart';
import 'package:package_info_plus/package_info_plus.dart';
class LunaNetworking extends HttpOverrides {
/// Initialize the default HTTP client by setting [HttpOverrides]'s global HTTP client to [LunaNetworking].
void initialize() {
HttpOverrides.global = LunaNetworking();
}
String generateUserAgent(PackageInfo info) {
return '${info.appName}/${info.version} ${info.buildNumber}';
}
/// Overrides the default [createHttpClient] function and ensures all HTTPS connections allow bad certificate connections.
///
/// Returns a new [HttpClient] using the given [context].
@override
HttpClient createHttpClient(SecurityContext? context) {
final HttpClient client = super.createHttpClient(context);
// Disable TLS validation
if (!LunaDatabaseValue.NETWORKING_TLS_VALIDATION.data)
client.badCertificateCallback = (cert, host, port) => true;
// Set User-Agent
PackageInfo.fromPlatform()
.then((info) => client.userAgent = generateUserAgent(info))
.catchError((_) => client.userAgent = 'LunaSea/Unknown');
return client;
}
/// Overrides the default [findProxyFromEnvironment] function.
///
/// Currently just calls the super function to use the default finding function.
@override
String findProxyFromEnvironment(Uri url, Map<String, String>? environment) {
return super.findProxyFromEnvironment(url, environment);
}
}

View File

@@ -0,0 +1,10 @@
import 'platform/networking_stub.dart'
if (dart.library.io) 'platform/networking_io.dart'
if (dart.library.html) 'platform/networking_html.dart';
abstract class LunaNetworking {
static bool get isSupported => isPlatformSupported();
factory LunaNetworking() => getNetworking();
void initialize();
}

View File

@@ -0,0 +1,5 @@
import '../networking.dart';
bool isPlatformSupported() => false;
LunaNetworking getNetworking() =>
throw UnsupportedError('LunaNetworking unsupported');

View File

@@ -0,0 +1,35 @@
import 'dart:io';
import '../../../../vendor.dart';
import '../../../database/luna_database.dart';
import '../networking.dart';
bool isPlatformSupported() => true;
LunaNetworking getNetworking() => IO();
class IO extends HttpOverrides implements LunaNetworking {
@override
void initialize() {
HttpOverrides.global = IO();
}
String generateUserAgent(PackageInfo info) {
return '${info.appName}/${info.version} ${info.buildNumber}';
}
@override
HttpClient createHttpClient(SecurityContext? context) {
final HttpClient client = super.createHttpClient(context);
// Disable TLS validation
if (!LunaDatabaseValue.NETWORKING_TLS_VALIDATION.data)
client.badCertificateCallback = (cert, host, port) => true;
// Set User-Agent
PackageInfo.fromPlatform()
.then((info) => client.userAgent = generateUserAgent(info))
.catchError((_) => client.userAgent = 'LunaSea/Unknown');
return client;
}
}

View File

@@ -0,0 +1,5 @@
import '../networking.dart';
bool isPlatformSupported() => false;
LunaNetworking getNetworking() =>
throw UnsupportedError('LunaNetworking unsupported');

View File

@@ -0,0 +1,15 @@
import 'package:flutter/foundation.dart';
class LunaPlatform {
bool get isAndroid => defaultTargetPlatform == TargetPlatform.android;
bool get isIOS => defaultTargetPlatform == TargetPlatform.iOS;
bool get isLinux => defaultTargetPlatform == TargetPlatform.linux;
bool get isMacOS => defaultTargetPlatform == TargetPlatform.macOS;
bool get isWindows => defaultTargetPlatform == TargetPlatform.windows;
bool get isWeb => kIsWeb;
bool get isMobile => isAndroid || isIOS;
bool get isDesktop => isLinux || isMacOS || isWindows;
}

View File

@@ -1,11 +1,12 @@
import 'dart:io';
import 'package:lunasea/core.dart';
import 'package:quick_actions/quick_actions.dart';
import 'platform.dart';
class LunaQuickActions {
static const QuickActions _quickActions = QuickActions();
static bool get isPlatformCompatible => Platform.isAndroid || Platform.isIOS;
static bool get isPlatformCompatible => LunaPlatform().isMobile;
/// Initialize the quick actions by setting the action handler.
///

View File

@@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';

View File

@@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import '../../../modules/wake_on_lan/api/api.dart';
import '../../../modules/wake_on_lan/api/wake_on_lan.dart';
class LunaDrawer extends StatelessWidget {
final String page;

View File

@@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';

View File

@@ -1,7 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:package_info_plus/package_info_plus.dart';
class LunaChangelogSheet extends LunaBottomModalSheet {
late _Changelog _changelog;
@@ -64,10 +62,6 @@ class LunaChangelogSheet extends LunaBottomModalSheet {
'lunasea.Fixes'.tr(),
_changelog.changesFixes,
),
..._buildChangeBlock(
'lunasea.PlatformSpecific'.tr(),
_changelog.changesPlatform,
),
const SizedBox(height: LunaUI.DEFAULT_MARGIN_SIZE / 2),
],
actionBar: LunaBottomActionBar(
@@ -110,50 +104,21 @@ class _Changelog {
List<_Change> changesNew = [];
List<_Change> changesTweaks = [];
List<_Change> changesFixes = [];
List<_Change> changesPlatform = [];
static _Changelog fromJson(Map<String, dynamic> json) {
_Changelog changelog = _Changelog();
int _index = -1;
List<dynamic>? data;
changelog.motd = json['motd'] ?? '';
changelog.motd = json['motd'] ?? 'Welcome to LunaSea!';
data = json['new'];
data?.forEach((change) {
_Change _change = _Change.fromJson(change);
changelog.changesNew.add(_change);
});
data?.forEach((c) => changelog.changesNew.add(_Change.fromJson(c)));
data = json['tweaks'];
data?.forEach((change) {
_Change _change = _Change.fromJson(change);
changelog.changesTweaks.add(_change);
});
data?.forEach((c) => changelog.changesTweaks.add(_Change.fromJson(c)));
data = json['fixes'];
data?.forEach((change) {
_Change _change = _Change.fromJson(change);
changelog.changesFixes.add(_change);
});
_index = data?.indexWhere((e) => e['module'] == 'macOS') ?? -1;
if (Platform.isMacOS && _index >= 0) {
_Change _change = _Change.fromJson(data![_index]);
changelog.changesFixes.add(_change);
}
_index = data?.indexWhere((e) => e['module'] == 'Android') ?? -1;
if (Platform.isAndroid && _index >= 0) {
_Change _change = _Change.fromJson(data![_index]);
changelog.changesFixes.add(_change);
}
_index = data?.indexWhere((e) => e['module'] == 'iOS') ?? -1;
if (Platform.isIOS && _index >= 0) {
_Change _change = _Change.fromJson(data![_index]);
changelog.changesFixes.add(_change);
}
data?.forEach((c) => changelog.changesFixes.add(_Change.fromJson(c)));
return changelog;
}
@@ -167,8 +132,8 @@ class _Change {
static _Change fromJson(Map<String, dynamic> json) {
_Change change = _Change._();
change.module = json['module']!;
change.changes = (json['changes'] as List?)?.cast<String>() ?? [];
change.module = json['module'] as String;
change.changes = (json['changes'] as List).cast<String>();
return change;
}
}

View File

@@ -1,5 +1,3 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';

View File

@@ -1,11 +1,11 @@
import 'dart:async';
import 'dart:io';
import 'package:device_preview/device_preview.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:lunasea/core.dart';
import 'core/system/networking/networking.dart';
import 'core/system/platform.dart';
import 'modules/dashboard/routes/dashboard/route.dart' show HomeRouter;
/// LunaSea Entry Point: Initialize & Run Application
@@ -21,7 +21,7 @@ Future<void> main() async {
LunaLogger().initialize();
LunaTheme().initialize();
await LunaDesktopWindow().initialize();
LunaNetworking().initialize();
if (LunaNetworking.isSupported) LunaNetworking().initialize();
LunaImageCache().initialize();
LunaRouter().initialize();
await LunaInAppPurchases().initialize();
@@ -45,7 +45,7 @@ class LunaBIOS extends StatelessWidget {
LunaRouter router = LunaRouter();
return DevicePreview(
enabled: kDebugMode && Platform.isMacOS,
enabled: kDebugMode && LunaPlatform().isDesktop,
builder: (context) => EasyLocalization(
supportedLocales: localization.supportedLocales as List<Locale>,
path: localization.fileDirectory,

View File

@@ -4,7 +4,7 @@ import '../../../../../../core/database/luna_database.dart';
import '../../../../../../core/modules.dart';
import '../../../../../../core/system/profile.dart';
import '../../../../../../core/ui.dart';
import '../../../../wake_on_lan/api/api.dart';
import '../../../../wake_on_lan/api/wake_on_lan.dart';
import '../widgets/navigation_bar.dart';
class ModulesPage extends StatefulWidget {

View File

@@ -2,6 +2,9 @@ import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/nzbget.dart';
import '../../../core/system/filesystem/file.dart';
import '../../../core/system/filesystem/filesystem.dart';
class NZBGet extends StatefulWidget {
static const ROUTE_NAME = '/nzbget';

View File

@@ -1,5 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/nzbget.dart';

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/radarr.dart';

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/sabnzbd.dart';

View File

@@ -2,6 +2,9 @@ import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/sabnzbd.dart';
import '../../../core/system/filesystem/file.dart';
import '../../../core/system/filesystem/filesystem.dart';
class SABnzbd extends StatefulWidget {
static const ROUTE_NAME = '/sabnzbd';

View File

@@ -4,6 +4,8 @@ import 'package:lunasea/modules/nzbget.dart';
import 'package:lunasea/modules/sabnzbd.dart';
import 'package:lunasea/modules/search.dart';
import '../../../../core/system/filesystem/filesystem.dart';
enum SearchDownloadType {
NZBGET,
SABNZBD,

View File

@@ -1,8 +1,10 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/settings.dart';
import '../../../../core/system/networking/networking.dart';
import '../../../../core/system/platform.dart';
class SettingsConfigurationRouter extends SettingsPageRouter {
SettingsConfigurationRouter() : super('/settings/configuration');
@@ -79,14 +81,15 @@ class _State extends State<_Widget> with LunaScrollControllerMixin {
onTap: () async =>
SettingsConfigurationLocalizationRouter().navigateTo(context),
),
LunaBlock(
title: 'settings.Network'.tr(),
body: [TextSpan(text: 'settings.NetworkDescription'.tr())],
trailing: const LunaIconButton(icon: Icons.network_check_rounded),
onTap: () async =>
SettingsConfigurationNetworkRouter().navigateTo(context),
),
if (Platform.isIOS)
if (LunaNetworking.isSupported)
LunaBlock(
title: 'settings.Network'.tr(),
body: [TextSpan(text: 'settings.NetworkDescription'.tr())],
trailing: const LunaIconButton(icon: Icons.network_check_rounded),
onTap: () async =>
SettingsConfigurationNetworkRouter().navigateTo(context),
),
if (LunaPlatform().isIOS)
LunaDatabaseValue.SELECTED_BROWSER.listen(
builder: (context, box, widget) {
LunaDatabaseValue _db = LunaDatabaseValue.SELECTED_BROWSER;

View File

@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/settings.dart';
import '../../../../core/system/networking/networking.dart';
class SettingsConfigurationNetworkRouter extends SettingsPageRouter {
SettingsConfigurationNetworkRouter()
: super('/settings/configuration/network');
@@ -58,7 +60,10 @@ class _State extends State<_Widget> with LunaScrollControllerMixin {
],
trailing: LunaSwitch(
value: _db.data,
onChanged: _db.put,
onChanged: (data) {
_db.put(data);
if (LunaNetworking.isSupported) LunaNetworking().initialize();
},
),
),
);

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:lunasea/core.dart';

View File

@@ -70,7 +70,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin {
onTap: () async => SettingsProfilesRouter().navigateTo(context),
),
LunaDivider(),
if (LunaInAppPurchases.isPlatformCompatible)
if (LunaInAppPurchases.isSupported)
LunaBlock(
title: 'settings.Donations'.tr(),
body: [TextSpan(text: 'settings.DonationsDescription'.tr())],

View File

@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/settings.dart';
import 'package:package_info_plus/package_info_plus.dart';
class SettingsSystemRouter extends SettingsPageRouter {
SettingsSystemRouter() : super('/settings/system');

View File

@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/settings.dart';
import '../../../../../core/system/filesystem/filesystem.dart';
class SettingsSystemBackupRestoreBackupTile extends StatelessWidget {
const SettingsSystemBackupRestoreBackupTile({
Key? key,

View File

@@ -2,6 +2,9 @@ import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/settings.dart';
import '../../../../../core/system/filesystem/file.dart';
import '../../../../../core/system/filesystem/filesystem.dart';
class SettingsSystemBackupRestoreRestoreTile extends StatelessWidget {
const SettingsSystemBackupRestoreRestoreTile({
Key? key,

View File

@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/settings.dart';
import '../../../../core/system/filesystem/filesystem.dart';
class SettingsSystemLogsRouter extends SettingsPageRouter {
SettingsSystemLogsRouter() : super('/settings/logs');

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/sonarr.dart';

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/sonarr.dart';

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/sonarr.dart';

View File

@@ -1,5 +1,3 @@
import 'dart:async';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:lunasea/core.dart';

View File

@@ -1,4 +1,3 @@
import 'dart:async';
import 'package:lunasea/core.dart';
import 'package:lunasea/modules/tautulli.dart';

View File

@@ -1,10 +0,0 @@
import './platform/wake_on_lan_stub.dart'
if (dart.library.io) './platform/wake_on_lan_io.dart'
if (dart.library.html) './platform/wake_on_lan_web.dart';
abstract class LunaWakeOnLAN {
static bool get isSupported => isPlatformSupported();
factory LunaWakeOnLAN() => getWakeOnLAN();
Future<void> wake();
}

View File

@@ -1,4 +1,4 @@
import '../api.dart';
import '../wake_on_lan.dart';
bool isPlatformSupported() => false;
LunaWakeOnLAN getWakeOnLAN() =>

View File

@@ -4,12 +4,12 @@ import '../../../../core/models/configuration/profile.dart';
import '../../../../core/system/profile.dart';
import '../../../../core/ui.dart';
import '../../../../core/utilities/logger.dart';
import '../api.dart';
import '../wake_on_lan.dart';
bool isPlatformSupported() => true;
LunaWakeOnLAN getWakeOnLAN() => API();
LunaWakeOnLAN getWakeOnLAN() => IO();
class API implements LunaWakeOnLAN {
class IO implements LunaWakeOnLAN {
@override
Future<void> wake() async {
ProfileHiveObject profile = LunaProfile.current;

View File

@@ -1,4 +1,4 @@
import '../api.dart';
import '../wake_on_lan.dart';
bool isPlatformSupported() => false;
LunaWakeOnLAN getWakeOnLAN() =>

View File

@@ -0,0 +1,10 @@
import 'platform/wake_on_lan_stub.dart'
if (dart.library.io) 'platform/wake_on_lan_io.dart'
if (dart.library.html) 'platform/wake_on_lan_html.dart';
abstract class LunaWakeOnLAN {
static bool get isSupported => isPlatformSupported();
factory LunaWakeOnLAN() => getWakeOnLAN();
Future<void> wake();
}

View File

@@ -1,8 +1,9 @@
// Dart
export 'dart:async';
export 'dart:convert';
export 'dart:math';
export 'dart:typed_data';
// Packages
export 'package:cached_network_image/cached_network_image.dart';
export 'package:dio/dio.dart';
export 'package:easy_localization/easy_localization.dart';
export 'package:expandable/expandable.dart';
@@ -15,6 +16,7 @@ export 'package:hive_flutter/hive_flutter.dart';
export 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
export 'package:json_annotation/json_annotation.dart';
export 'package:layout/layout.dart';
export 'package:package_info_plus/package_info_plus.dart';
export 'package:provider/provider.dart';
export 'package:simple_gesture_detector/simple_gesture_detector.dart';
export 'package:stash/stash_api.dart';