Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Check GitHub for updates #712

Open
wants to merge 16 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@
"list-item-advanced-settings-licenses": "Open Source Licenses",
"list-item-advanced-settings-start-background": "Start Background Service",
"list-item-advanced-settings-stop-background": "Stop All Services",
"list-item-advanced-settings-check-for-updates": "Check GitHub for Syphon updates",
"list-item-advanced-settings-check-for-updates-body": "Periodically check GitHub for new releases",
"list-item-advanced-settings-test-notifications": "Test Notifications",
"list-item-advanced-settings-test-sync-loop": "Test Background Sync Loop",
"list-item-advanced-settings-force-function": "Force Function",
Expand Down
4 changes: 4 additions & 0 deletions lib/global/strings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ class Strings {
tr('list-item-advanced-settings-start-background');
static final listItemAdvancedSettingsStopBackground =
tr('list-item-advanced-settings-stop-background');
static final listItemAdvancedSettingsCheckForUpdates =
tr('list-item-advanced-settings-check-for-updates');
static final listItemAdvancedSettingsCheckForUpdatesBody =
tr('list-item-advanced-settings-check-for-updates-body');
static final listItemAdvancedSettingsTestNotifications =
tr('list-item-advanced-settings-test-notifications');
static final listItemAdvancedSettingsTestSyncLoop =
Expand Down
52 changes: 52 additions & 0 deletions lib/global/update-check.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'package:http/http.dart' as http;
import 'package:package_info_plus/package_info_plus.dart';
import 'package:syphon/global/https.dart';
import 'package:syphon/store/hooks.dart';
import 'package:syphon/store/index.dart';

class UpdateChecker {
static DateTime? lastChecked;
static DateTime nextCheckNotBefore = DateTime.utc(1970);
static bool updateAvailable = false;

static final latestBuildUri =
Uri.https('github.com', 'syphon-org/syphon/releases/latest');

static checkForUpdate() async {
final enabled = useSelector<AppState, bool>(
(state) => state.settingsStore.checkForUpdatesEnabled) ??
false;

if (!enabled ||
nextCheckNotBefore.isAfter(DateTime.now()) ||
updateAvailable) {
return;
}

final packageInfo = await PackageInfo.fromPlatform();
final currentVersion = int.parse(packageInfo.version.replaceAll('.', ''));

//Extract the build tag from the redirect
final request = http.Request('Get', latestBuildUri)
..followRedirects = false;

//Make sure to send over our client to respect the proxy
final response = await httpClient.send(request);

if (!response.headers.containsKey('location')) {
return;
}

final redirectUri = Uri.parse(response.headers['location']!);
final version = int.parse(redirectUri.pathSegments.last //extract the tag
.replaceAll('.', ''));

lastChecked = DateTime.now();

if (version > currentVersion) {
updateAvailable = true;
}

nextCheckNotBefore = lastChecked!.add(Duration(hours: 18));
}
}
8 changes: 8 additions & 0 deletions lib/store/settings/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class SetReadReceipts {
SetReadReceipts({this.readReceipts});
}

class ToggleCheckForUpdates {}

class ToggleEnterSend {}

class ToggleAutocorrect {}
Expand Down Expand Up @@ -356,3 +358,9 @@ ThunkAction<AppState> toggleNotifications() {
}
};
}

ThunkAction<AppState> toggleCheckForUpdates() {
return (Store<AppState> store) async {
store.dispatch(ToggleCheckForUpdates());
};
}
4 changes: 4 additions & 0 deletions lib/store/settings/reducer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ SettingsStore settingsReducer([
return state.copyWith(
suggestionsEnabled: !state.suggestionsEnabled,
);
case ToggleCheckForUpdates:
return state.copyWith(
checkForUpdatesEnabled: !state.checkForUpdatesEnabled,
);
case SetSyncInterval:
return state.copyWith(
syncInterval: action.syncInterval,
Expand Down
6 changes: 6 additions & 0 deletions lib/store/settings/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class SettingsStore extends Equatable {
final bool timeFormat24Enabled;
final bool dismissKeyboardEnabled;
final bool autoDownloadEnabled;
final bool checkForUpdatesEnabled;

final int syncInterval;
final int syncPollTimeout;
Expand Down Expand Up @@ -66,6 +67,7 @@ class SettingsStore extends Equatable {
this.timeFormat24Enabled = false,
this.dismissKeyboardEnabled = false,
this.autoDownloadEnabled = false,
this.checkForUpdatesEnabled = false,
this.chatSettings = const <String, ChatSetting>{},
this.devices = const [],
this.loading = false,
Expand All @@ -91,6 +93,7 @@ class SettingsStore extends Equatable {
timeFormat24Enabled,
dismissKeyboardEnabled,
autoDownloadEnabled,
checkForUpdatesEnabled,
chatSettings,
chatLists,
devices,
Expand All @@ -115,6 +118,7 @@ class SettingsStore extends Equatable {
bool? timeFormat24Enabled,
bool? dismissKeyboardEnabled,
bool? autoDownloadEnabled,
bool? checkForUpdatesEnabled,
int? syncInterval,
int? syncPollTimeout,
bool? loading,
Expand Down Expand Up @@ -146,6 +150,8 @@ class SettingsStore extends Equatable {
roomTypeBadgesEnabled:
roomTypeBadgesEnabled ?? this.roomTypeBadgesEnabled,
autoDownloadEnabled: autoDownloadEnabled ?? this.autoDownloadEnabled,
checkForUpdatesEnabled:
checkForUpdatesEnabled ?? this.checkForUpdatesEnabled,
syncInterval: syncInterval ?? this.syncInterval,
syncPollTimeout: syncPollTimeout ?? this.syncPollTimeout,
chatLists: chatLists ?? this.chatLists,
Expand Down
10 changes: 10 additions & 0 deletions lib/views/home/home-screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:fab_circular_menu/fab_circular_menu.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:syphon/global/strings.dart';
import 'package:syphon/global/update-check.dart';
import 'package:syphon/store/hooks.dart';
import 'package:syphon/store/index.dart';
import 'package:syphon/store/rooms/room/model.dart';
Expand All @@ -30,6 +31,10 @@ class HomeScreen extends HookWidget {
(state) => state.syncStore.lastSince,
);

final checkForUpdatesEnabled = useSelector<AppState, bool>(
(state) => state.settingsStore.checkForUpdatesEnabled) ??
false;

final searchLoading = useSelector<AppState, bool>(
(state) => state.searchStore.loading,
) ??
Expand Down Expand Up @@ -202,6 +207,11 @@ class HomeScreen extends HookWidget {
);
}

if (checkForUpdatesEnabled) {
UpdateChecker.checkForUpdate();
if (UpdateChecker.updateAvailable) {}
EdGeraghty marked this conversation as resolved.
Show resolved Hide resolved
}

return Scaffold(
appBar: currentAppBar as PreferredSizeWidget?,
floatingActionButton: buildActionFab(),
Expand Down
26 changes: 25 additions & 1 deletion lib/views/home/settings/advanced-settings-screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:package_info/package_info.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:redux/redux.dart';
import 'package:syphon/global/colors.dart';
import 'package:syphon/global/dimensions.dart';
Expand All @@ -24,12 +24,14 @@ import 'package:syphon/views/widgets/dialogs/dialog-text-input.dart';
class _Props extends Equatable {
final bool syncing;
final bool syncObserverActive;
final bool checkForUpdates;
final String? language;
final String? lastSince;
final User currentUser;
final int syncInterval;

final Function onToggleSyncing;
final Function onToggleCheckUpdates;
final Function onManualSync;
final Function onForceFullSync;
final Function onForceFunction;
Expand All @@ -38,6 +40,7 @@ class _Props extends Equatable {

const _Props({
required this.syncing,
required this.checkForUpdates,
required this.language,
required this.syncObserverActive,
required this.currentUser,
Expand All @@ -46,6 +49,7 @@ class _Props extends Equatable {
required this.onManualSync,
required this.onForceFullSync,
required this.onToggleSyncing,
required this.onToggleCheckUpdates,
required this.onForceFunction,
required this.onStartBackgroundSync,
required this.onEditSyncInterval,
Expand All @@ -55,13 +59,15 @@ class _Props extends Equatable {
List<Object?> get props => [
syncing,
syncInterval,
checkForUpdates,
lastSince,
currentUser,
syncObserverActive,
];

static _Props mapStateToProps(Store<AppState> store) => _Props(
syncing: store.state.syncStore.syncing,
checkForUpdates: store.state.settingsStore.checkForUpdatesEnabled,
language: store.state.settingsStore.language,
currentUser: store.state.authStore.user,
lastSince: store.state.syncStore.lastSince,
Expand Down Expand Up @@ -110,6 +116,9 @@ class _Props extends Equatable {
store.dispatch(startSyncObserver());
}
},
onToggleCheckUpdates: () {
store.dispatch(toggleCheckForUpdates());
},
onStartBackgroundSync: () async {
store.dispatch(startSyncService());
},
Expand Down Expand Up @@ -354,6 +363,21 @@ class AdvancedSettingsScreenState extends State<AdvancedSettingsScreen> {
),
),
),
ListTile(
onTap: () => props.onToggleCheckUpdates(),
contentPadding: Dimensions.listPadding,
title: Text(
Strings.listItemAdvancedSettingsCheckForUpdates,
),
subtitle: Text(
Strings.listItemAdvancedSettingsCheckForUpdatesBody,
style: Theme.of(context).textTheme.caption,
),
trailing: Switch(
value: props.checkForUpdates,
onChanged: (check) => props.onToggleCheckUpdates(),
),
),
ListTile(
dense: true,
contentPadding: Dimensions.listPadding,
Expand Down
Loading