Skip to content

Commit

Permalink
feat: In App Updates. closes #20
Browse files Browse the repository at this point in the history
  • Loading branch information
khaled-0 committed Dec 21, 2024
1 parent c8e8452 commit 90da5fe
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 21 deletions.
19 changes: 16 additions & 3 deletions lib/app/home/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import 'package:tubesync/app/app_theme.dart';
import 'package:tubesync/app/library/import_playlist_dialog.dart';
import 'package:tubesync/app/library/library_tab.dart';
import 'package:tubesync/app/more/more_tab.dart';
import 'package:tubesync/clients/in_app_update_client.dart';
import 'package:tubesync/model/preferences.dart';
import 'package:tubesync/provider/library_provider.dart';

import 'home_app_bar.dart';
Expand Down Expand Up @@ -77,19 +79,30 @@ class HomeTab extends StatefulWidget {
class _HomeTabState extends State<HomeTab> {
final homeNavigator = GlobalKey<NavigatorState>();
StreamSubscription? shareHandler;
late final prefs = context.read<Isar>().preferences;

@override
void initState() {
super.initState();
// TODO: Add IOS Support
if (Platform.isAndroid) {
shareHandler = ReceiveSharingIntent.instance.getMediaStream().listen(
handleSharedData,
);
shareHandler = ReceiveSharingIntent.instance
.getMediaStream()
.listen(handleSharedData);

ReceiveSharingIntent.instance
.getInitialMedia()
.then(handleSharedData)
.whenComplete(ReceiveSharingIntent.instance.reset);
}

// Check for update
if (prefs.getValue(Preference.inAppUpdate, true)!) {
InAppUpdateClient.checkFromGitHub().then((changes) {
if (!mounted || changes == null) return;
InAppUpdateClient.showUpdateDialog(context, changes);
}).catchError((_) {});
}
}

void handleSharedData(List<SharedMediaFile> value) {
Expand Down
42 changes: 31 additions & 11 deletions lib/app/more/about_screen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:package_info_plus/package_info_plus.dart";
import "package:tubesync/clients/in_app_update_client.dart";
import "package:url_launcher/url_launcher_string.dart";

class AboutScreen extends StatelessWidget {
Expand All @@ -23,34 +24,53 @@ class AboutScreen extends StatelessWidget {
return Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
spacing: 24,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
"assets/icons/tubesync_mono.webp",
color: Theme.of(context).colorScheme.primary,
height: 80,
),
const SizedBox(height: 20),
Text(
"TubeSync",
style: Theme.of(context).textTheme.headlineMedium,
),
Text(
"v${snapshot.requireData.version}",
style: Theme.of(context).textTheme.bodyLarge,
Column(
spacing: 12,
children: [
Text(
"TubeSync",
style: Theme.of(context).textTheme.headlineMedium,
),
Text(
"v${snapshot.requireData.version}",
style: Theme.of(context).textTheme.bodyLarge,
),
FilledButton(
onPressed: () {
InAppUpdateClient.checkFromGitHub().then((value) {
if (!context.mounted) return;
if (value == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("No new updates."),
),
);
return;
}
InAppUpdateClient.showUpdateDialog(context, value);
});
},
child: const Text("Check For Update"),
)
],
),
const SizedBox(height: 24),
const Text(
"Licenced under the GNU General Public Licence v3.0",
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
TextButton.icon(
onPressed: () => showLicensePage(context: context),
icon: const Icon(Icons.chrome_reader_mode_rounded),
label: const Text("Open Source Licences"),
),
const SizedBox(height: 24),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Expand Down
16 changes: 16 additions & 0 deletions lib/app/more/preferences/preference_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,22 @@ class PreferenceScreen extends StatelessWidget {
}),
),
),
_title(context, "Others"),
StreamBuilder(
stream: preferences(context).watch(
Preference.inAppUpdate,
),
builder: (c, value) => SwitchListTile(
value: value.data?.get<bool>() != false,
onChanged: (value) => preferences(c).setValue(
Preference.inAppUpdate,
value,
),
secondary: const Icon(Icons.shuffle_rounded),
title: const Text("Check app updates"),
subtitle: const Text("Notify when new version is available"),
),
),
],
),
);
Expand Down
59 changes: 59 additions & 0 deletions lib/clients/in_app_update_client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:http/http.dart' as http;
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher_string.dart';

class InAppUpdateClient {
static const repo = "khaled-0/TubeSync";

/// Returns changelog if update available. else null
static Future<String?> checkFromGitHub() async {
final url = Uri.parse('https://api.github.com/repos/$repo/releases/latest');
final response = await http.get(url);
// We're treating errors as no update.
if (response.statusCode != 200) return null;

final Map<String, dynamic> releaseInfo = json.decode(response.body);
final String latestVersion = releaseInfo['tag_name'];

final currentVersion = (await PackageInfo.fromPlatform()).version;
if (currentVersion.compareTo(latestVersion) >= 0) return null;

final String changelog = releaseInfo["body"];
return changelog;
}

static void showUpdateDialog(BuildContext context, String changelog) {
showDialog(
useRootNavigator: true,
useSafeArea: true,
context: context,
builder: (context) => AlertDialog(
title: const Text("A new update!"),
content: SizedBox(
height: MediaQuery.of(context).size.height * 0.7,
width: MediaQuery.of(context).size.width * 0.8,
child: Markdown(
data: changelog,
shrinkWrap: true,
padding: EdgeInsets.zero,
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("Cancel"),
),
TextButton(
onPressed: () => launchUrlString(
"https://github.com/$repo/releases/latest",
),
child: const Text("Update"),
),
],
),
);
}
}
1 change: 1 addition & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ void main() async {
),
),
);

// Ensure permissions
Future.wait([
Permission.notification.isDenied,
Expand Down
4 changes: 3 additions & 1 deletion lib/model/preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ enum Preference {
// Player Customization
miniPlayerSecondaryAction,
// Downloader
maxParallelDownload
maxParallelDownload,
// Others
inAppUpdate,
}

@Collection()
Expand Down
20 changes: 18 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.4+6"
flutter_markdown:
dependency: "direct main"
description:
name: flutter_markdown
sha256: "255b00afa1a7bad19727da6a7780cf3db6c3c12e68d302d85e0ff1fdf173db9e"
url: "https://pub.dev"
source: hosted
version: "0.7.4+3"
flutter_test:
dependency: "direct dev"
description: flutter
Expand Down Expand Up @@ -406,7 +414,7 @@ packages:
source: hosted
version: "0.15.5"
http:
dependency: transitive
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
Expand Down Expand Up @@ -581,6 +589,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.1.3-main.0"
markdown:
dependency: transitive
description:
name: markdown
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
url: "https://pub.dev"
source: hosted
version: "7.2.2"
matcher:
dependency: transitive
description:
Expand Down Expand Up @@ -881,7 +897,7 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "2cea396843cd3ab1b5ec4334be4233864637874e"
ref: HEAD
resolved-ref: "2cea396843cd3ab1b5ec4334be4233864637874e"
url: "https://github.com/KasemJaffer/receive_sharing_intent.git"
source: git
Expand Down
9 changes: 5 additions & 4 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies:
git: https://github.com/Hexer10/youtube_explode_dart.git
background_downloader: ^8.8.1
internet_connection_checker_plus: ^2.6.0
http: ^1.2.2

# Data Management (Isar is too big in fs <3mb> Use ObjectBox/SqLite+Drift?)
provider: ^6.1.2
Expand Down Expand Up @@ -67,12 +68,12 @@ dependencies:
path_provider: ^2.1.5
url_launcher: ^6.3.1
permission_handler: ^11.3.1

# Extras
flutter_markdown: ^0.7.4+3
package_info_plus: ^8.1.2
# https://github.com/KasemJaffer/receive_sharing_intent/pull/333
receive_sharing_intent:
git:
url: https://github.com/KasemJaffer/receive_sharing_intent.git
ref: 2cea396843cd3ab1b5ec4334be4233864637874e
git: https://github.com/KasemJaffer/receive_sharing_intent.git

dev_dependencies:
flutter_test:
Expand Down
7 changes: 7 additions & 0 deletions tests/basic.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
TestWidgetsFlutterBinding.ensureInitialized();
WidgetsFlutterBinding.ensureInitialized();
}

0 comments on commit 90da5fe

Please sign in to comment.