Skip to content

Commit

Permalink
feat: settings: option to skip update checks
Browse files Browse the repository at this point in the history
  • Loading branch information
alexVinarskis committed Feb 23, 2024
1 parent b9739f7 commit d4411f8
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 68 deletions.
40 changes: 38 additions & 2 deletions lib/classes/ota_manager.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,54 @@
import 'dart:convert';
import 'dart:io';

import 'package:dell_powermanager/classes/dependencies_manager.dart';
import 'package:process_run/shell.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:version/version.dart';

import '../classes/dependencies_manager.dart';
import '../configs/constants.dart';
import '../configs/environment.dart';

class OtaManager {
static final _shell = Shell(verbose: Environment.runningDebug, throwOnError: false);
static SharedPreferences? _prefs;
static const _prefNameOtaCheckEnabled = "otaCheckEnabled";

static final List<Function(List<String> latestOta)> _callbacksOtaChanged = [];
static void addCallbacksOtaChanged(var callback) { _callbacksOtaChanged.add(callback); }
static void removeCallbacksOtaChanged(var callback) { _callbacksOtaChanged.remove(callback); }
static void _callOtaChanged(List<String> latestOta) {
var dubList = List.from(_callbacksOtaChanged);
for (var callback in dubList) {
callback(latestOta);
}
}

static Future<void> setOtaCheckEnabled(bool value) async {
_prefs ??= await SharedPreferences.getInstance();
bool previousValue = await isOtaCheckEnabled();
if (value != previousValue) {
await _prefs?.setBool(_prefNameOtaCheckEnabled, value);
checkLatestOta(otaCheckEnabled: value).then((latestOta) => _callOtaChanged(latestOta));
}
}
static Future<bool> isOtaCheckEnabled() async {
_prefs ??= await SharedPreferences.getInstance();
bool? isOtaCheckEnabled = _prefs?.getBool(_prefNameOtaCheckEnabled);
if (isOtaCheckEnabled == null) {
isOtaCheckEnabled = true;
await _prefs?.setBool(_prefNameOtaCheckEnabled, isOtaCheckEnabled);
checkLatestOta(otaCheckEnabled: isOtaCheckEnabled).then((latestOta) => _callOtaChanged(latestOta));
}
return isOtaCheckEnabled;
}

// [tagname, releaseUrl, downloadUrl]
static Future<List<String>> checkLatestOta() async {
static Future<List<String>> checkLatestOta({bool? otaCheckEnabled}) async {
otaCheckEnabled ??= await isOtaCheckEnabled();
if (!otaCheckEnabled) {
return [];
}
List<String> result = [];
ProcessResult pr = (await _shell.run('${Platform.isLinux ? "" : "cmd /c"} ${Constants.githubApiRequest} ${Constants.githubApiReleases}'))[0];
if (pr.exitCode != 0) {
Expand Down
19 changes: 17 additions & 2 deletions lib/components/notification_ota.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,29 @@ class NotificationOtaState extends State<NotificationOta> {
@override
void initState() {
super.initState();
OtaManager.addCallbacksOtaChanged(_handleOtaState);
OtaManager.checkLatestOta().then((latestOta) => _handleOtaState(latestOta));
}

@override
void dispose() {
OtaManager.removeCallbacksOtaChanged(_handleOtaState);
super.dispose();
}

void _handleOtaState(List<String> latestOta) {
if (latestOta.length < 2) {
/* Update in progress */
if (
_otaState == OtaState.installationSucceeded ||
_otaState == OtaState.installing ||
_otaState == OtaState.downloading
) {
return;
}
if (!OtaManager.compareUpdateRequired(latestOta[0])) {
if (latestOta.length < 2 || !OtaManager.compareUpdateRequired(latestOta[0])) {
setState(() {
_otaState = OtaState.hidden;
});
return;
}
if (_otaState == OtaState.hidden) {
Expand Down
247 changes: 183 additions & 64 deletions lib/components/settings_modal.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import 'dart:async';

import 'package:dell_powermanager/classes/bios_protection_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../classes/bios_protection_manager.dart';
import '../classes/ota_manager.dart';
import '../configs/constants.dart';


Expand Down Expand Up @@ -57,6 +58,106 @@ class SettingTileState extends State<SettingTile> {
}
}

class SettingTileToggle extends StatefulWidget {
const SettingTileToggle({
super.key,
required this.title,
this.subtitleEnabled,
this.subtitleDisabled,
this.subtitleEnabledAlt,
this.subtitleDisabledAlt,
required this.getPref,
required this.setPref,
});

final String title;
final String? subtitleEnabled;
final String? subtitleDisabled;
final String? subtitleEnabledAlt;
final String? subtitleDisabledAlt;
final Function getPref;
final Function setPref;

@override
State<SettingTileToggle> createState() => SettingTileToggleState();
}

class SettingTileToggleState extends State<SettingTileToggle> {
bool? _enabled;
bool _enablePressed = false;
bool _disablePressed = false;

_fetchPref() async {
bool enabled = await widget.getPref();
if (mounted) {
setState(() {
_enabled = enabled;
});
}
}

_setPref(bool value) async {
setState(() {
_enabled = value;
});
if (value) {
_disablePressed = false;
_enablePressed = true;
Timer(const Duration(seconds: 1), () {
if (!mounted) {
return;
}
setState(() {
_enablePressed = false;
});
});
} else {
_enablePressed = false;
_disablePressed = true;
Timer(const Duration(seconds: 1), () {
if (!mounted) {
return;
}
setState(() {
_disablePressed = false;
});
});
}
await widget.setPref(value);
}

String _getSubtitle() {
if (_enabled ?? false) {
return _enablePressed ? widget.subtitleEnabledAlt ?? widget.subtitleEnabled ?? '' : widget.subtitleEnabled ?? '';
}
return _disablePressed ? widget.subtitleDisabledAlt ?? widget.subtitleDisabled ?? '' : widget.subtitleDisabled ?? widget.subtitleEnabled ?? '';
}

@override
Widget build(BuildContext context) {
if (_enabled == null) {
_fetchPref();
}

return Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: ListTile(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))
),
title: Text(widget.title),
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4),
trailing: Switch(
value: _enabled ?? false,
onChanged: (bool value) => _setPref(value),
),
subtitle: Text(_getSubtitle()),
onTap: () => _setPref(!(_enabled ?? false)),
),
);
}
}

class SettingsModal {

static void _launchURL(String url) async {
Expand Down Expand Up @@ -111,81 +212,99 @@ class SettingsModal {
}

static Future<void> showModal(BuildContext context, {double width = 450, double height = 0, double paddingH = 0, double paddingV = 0}) {
Key settingIntanceKey = UniqueKey();

return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(S.of(context)!.settingsAlertTitle),
content: SizedBox(
width: 450,
child:
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(height: 15,),
Row(
children: [
Expanded(
child: _settingsBadge(
title: S.of(context)!.settingsAlertTileHomepage,
icon: const Icon(Icons.link),
onPressed: () {
_launchURL(Constants.urlHomepage);
Navigator.of(context).pop();
},
),
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
key: settingIntanceKey,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(height: 15,),
Row(
children: [
Expanded(
child: _settingsBadge(
title: S.of(context)!.settingsAlertTileHomepage,
icon: const Icon(Icons.link),
onPressed: () {
_launchURL(Constants.urlHomepage);
Navigator.of(context).pop();
},
),
),
const SizedBox(width: 15,),
Expanded(
child: _settingsBadge(
title: S.of(context)!.settingsAlertTileAbout,
onPressed: () {
_showAboutDialog(context: context);
Navigator.of(context).pop();
},
),
),
],
),
const SizedBox(width: 15,),
Expanded(
child: _settingsBadge(
title: S.of(context)!.settingsAlertTileAbout,
onPressed: () {
_showAboutDialog(context: context);
Navigator.of(context).pop();
},
),
const SizedBox(height: 15,),
Row(
children: [
Expanded(
child: _settingsBadge(
title: S.of(context)!.settingsAlertTileBug,
icon: const Icon(Icons.link),
onPressed: () {
_launchURL(Constants.urlBugReport);
Navigator.of(context).pop();
},
),
),
const SizedBox(width: 15,),
const Expanded(
child: SizedBox(),
),
],
),
],
),
const SizedBox(height: 15,),
Row(
children: [
Expanded(
child: _settingsBadge(
title: S.of(context)!.settingsAlertTileBug,
icon: const Icon(Icons.link),
onPressed: () {
_launchURL(Constants.urlBugReport);
Navigator.of(context).pop();
},
),
const SizedBox(height: 15,),
SettingTile(
title: S.of(context)!.settingsAlertResetBiosPwdTitle,
subtitle: S.of(context)!.settingsAlertResetBiosPwdSubTitleTodo,
subtitleAlt: S.of(context)!.settingsAlertResetBiosPwdSubTitleDone,
icon: Icons.delete_rounded,
onPressed: () => BiosProtectionManager.secureDeletePassword(),
),
SettingTile(
title: S.of(context)!.settingsAlertResetSettingsTitle,
subtitle: S.of(context)!.settingsAlertResetSettingsSubTitleTodo,
subtitleAlt: S.of(context)!.settingsAlertResetSettingsSubTitleDone,
icon: Icons.delete_rounded,
onPressed: () async {
/* Erase saved preferences and cached variables */
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.clear();
/* Re-initialize settings modal, to reflect changes */
setState(() {
settingIntanceKey = UniqueKey();
});
},
),
const SizedBox(width: 15,),
const Expanded(
child: SizedBox(),
SettingTileToggle(
title: S.of(context)!.settingsAlertOtaEnabledTitle,
subtitleEnabled: S.of(context)!.settingsAlertOtaEnabledSubTitleEnabled,
subtitleEnabledAlt: S.of(context)!.settingsAlertOtaEnabledSubTitleEnabledAlt,
subtitleDisabled: S.of(context)!.settingsAlertOtaEnabledSubTitleDisabled,
getPref: OtaManager.isOtaCheckEnabled,
setPref: OtaManager.setOtaCheckEnabled,
),
],
),
const SizedBox(height: 15,),
SettingTile(
title: S.of(context)!.settingsAlertResetBiosPwdTitle,
subtitle: S.of(context)!.settingsAlertResetBiosPwdSubTitleTodo,
subtitleAlt: S.of(context)!.settingsAlertResetBiosPwdSubTitleDone,
icon: Icons.delete_rounded,
onPressed: () => BiosProtectionManager.secureDeletePassword(),
),
SettingTile(
title: S.of(context)!.settingsAlertResetSettingsTitle,
subtitle: S.of(context)!.settingsAlertResetSettingsSubTitleTodo,
subtitleAlt: S.of(context)!.settingsAlertResetSettingsSubTitleDone,
icon: Icons.delete_rounded,
onPressed: () async {
/* Erase saved preferences and cached variables */
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.clear();
},
),
],
);
}
),
),
);
Expand Down
4 changes: 4 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
"settingsAlertResetSettingsTitle" : "Reset app's data and settings",
"settingsAlertResetSettingsSubTitleTodo" : "Tap to erase",
"settingsAlertResetSettingsSubTitleDone" : "Erased!",
"settingsAlertOtaEnabledTitle" : "Check for updates on startup",
"settingsAlertOtaEnabledSubTitleEnabled" : "Enabled",
"settingsAlertOtaEnabledSubTitleEnabledAlt" : "Enabled, checking...",
"settingsAlertOtaEnabledSubTitleDisabled" : "Disabled",

"compatibilityCardTitle" : "Incompatible Platform",
"compatibilityCardSubtitle" : "Non-Dell machine, or Unsupported Model",
Expand Down

0 comments on commit d4411f8

Please sign in to comment.