Compare commits

...

7 Commits

Author SHA1 Message Date
Imran Remtulla
21ca18ce75 Updated version 2022-08-25 15:33:33 -04:00
Imran Remtulla
7afcf6a37b Fixed notif icon + Updated plugins + build warning 2022-08-25 15:29:25 -04:00
Imran Remtulla
9dba372244 Updated version 2022-08-25 14:36:59 -04:00
Imran Remtulla
88b60fe362 Ignore 'www' in URL 2022-08-25 14:35:46 -04:00
Imran Remtulla
0362cdf8ac Added update all button + Obtainium added by default 2022-08-25 14:26:15 -04:00
Imran Remtulla
aeada9635d Made app ids unique 2022-08-25 13:22:21 -04:00
Imran Remtulla
ffe212ebf2 Fixed bg task issue + notification icon 2022-08-25 11:17:47 -04:00
9 changed files with 144 additions and 81 deletions

View File

@@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
} }
android { android {
compileSdkVersion flutter.compileSdkVersion compileSdkVersion 33
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
compileOptions { compileOptions {
@@ -54,7 +54,7 @@ android {
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 32 targetSdkVersion 33
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }

BIN
android/app/src/main/res/drawable/ic_notification.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/*" />

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:obtainium/pages/home.dart'; import 'package:obtainium/pages/home.dart';
import 'package:obtainium/services/apps_provider.dart'; import 'package:obtainium/services/apps_provider.dart';
import 'package:obtainium/services/settings_provider.dart'; import 'package:obtainium/services/settings_provider.dart';
@@ -8,11 +9,21 @@ import 'package:provider/provider.dart';
import 'package:workmanager/workmanager.dart'; import 'package:workmanager/workmanager.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
@pragma('vm:entry-point')
void backgroundUpdateCheck() { void backgroundUpdateCheck() {
Workmanager().executeTask((task, inputData) async { Workmanager().executeTask((task, inputData) async {
var appsProvider = AppsProvider(bg: true); var appsProvider = AppsProvider(bg: true);
await appsProvider.notify(
4,
'Checking for Updates',
'',
'BG_UPDATE_CHECK',
'Checking for Updates',
'Transient notification that appears when checking for updates',
important: false);
try {
await appsProvider.loadApps(); await appsProvider.loadApps();
List<App> updates = await appsProvider.getUpdates(); List<App> updates = await appsProvider.checkUpdates();
if (updates.isNotEmpty) { if (updates.isNotEmpty) {
String message = updates.length == 1 String message = updates.length == 1
? '${updates[0].name} has an update.' ? '${updates[0].name} has an update.'
@@ -27,6 +38,20 @@ void backgroundUpdateCheck() {
'Notifies the user that updates are available for one or more Apps tracked by Obtainium'); 'Notifies the user that updates are available for one or more Apps tracked by Obtainium');
} }
return Future.value(true); return Future.value(true);
} catch (e) {
await appsProvider.downloaderNotifications.cancel(5);
await appsProvider.notify(
5,
'Error Checking for Updates',
e.toString(),
'BG_UPDATE_CHECK_ERROR',
'Error Checking for Updates',
'A notification that shows when background update checking fails',
important: false);
return Future.value(false);
} finally {
await appsProvider.downloaderNotifications.cancel(4);
}
}); });
} }
@@ -63,25 +88,26 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DynamicColorBuilder( return DynamicColorBuilder(
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) { builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
AppsProvider appsProvider = context.read<AppsProvider>();
appsProvider.deleteSavedAPKs();
// Initialize the settings provider (if needed) and perform first-run actions if needed // Initialize the settings provider (if needed) and perform first-run actions if needed
SettingsProvider settingsProvider = context.watch<SettingsProvider>(); SettingsProvider settingsProvider = context.watch<SettingsProvider>();
if (settingsProvider.prefs == null) { if (settingsProvider.prefs == null) {
settingsProvider.initializeSettings().then((_) { settingsProvider.initializeSettings().then((_) {
bool isFirstRun = settingsProvider.checkAndFlipFirstRun(); bool isFirstRun = settingsProvider.checkAndFlipFirstRun();
if (isFirstRun) { if (isFirstRun) {
AppsProvider appsProvider = context.read<AppsProvider>(); appsProvider.downloaderNotifications
appsProvider .resolvePlatformSpecificImplementation<
.notify( AndroidFlutterLocalNotificationsPlugin>()!
3, .requestPermission();
'Permission Notification', appsProvider.saveApp(App(
'This is a transient notification used to trigger the Android 13 notification permission prompt', 'imranr98_obtainium_github',
'PERMISSION_NOTIFICATION', 'https://github.com/ImranR98/Obtainium',
'Permission Notifications', 'ImranR98',
'A transient notification used to trigger the Android 13 notification permission prompt', 'Obtainium',
important: false) 'v0.1.2-beta', // KEEP THIS IN SYNC WITH GITHUB RELEASES
.whenComplete(() { 'v0.1.2-beta',
appsProvider.downloaderNotifications.cancel(3); ''));
});
} }
}); });
} }

View File

@@ -14,9 +14,25 @@ class _AppsPageState extends State<AppsPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var appsProvider = context.watch<AppsProvider>(); var appsProvider = context.watch<AppsProvider>();
appsProvider.getUpdates(); appsProvider.checkUpdates();
var existingUpdateAppIds = appsProvider.getExistingUpdates();
return Center( return Scaffold(
floatingActionButton: existingUpdateAppIds.isEmpty
? null
: ElevatedButton.icon(
onPressed: appsProvider.apps.values
.where((element) => element.downloadProgress != null)
.isNotEmpty
? null
: () {
for (var e in existingUpdateAppIds) {
appsProvider.downloadAndInstallLatestApp(e);
}
},
icon: const Icon(Icons.update),
label: const Text('Update All')),
body: Center(
child: appsProvider.loadingApps child: appsProvider.loadingApps
? const CircularProgressIndicator() ? const CircularProgressIndicator()
: appsProvider.apps.isEmpty : appsProvider.apps.isEmpty
@@ -25,14 +41,14 @@ class _AppsPageState extends State<AppsPage> {
style: Theme.of(context).textTheme.headline4, style: Theme.of(context).textTheme.headline4,
) )
: RefreshIndicator( : RefreshIndicator(
onRefresh: appsProvider.getUpdates, onRefresh: appsProvider.checkUpdates,
child: ListView( child: ListView(
children: appsProvider.apps.values children: appsProvider.apps.values
.map( .map(
(e) => ListTile( (e) => ListTile(
title: Text('${e.app.author}/${e.app.name}'), title: Text('${e.app.author}/${e.app.name}'),
subtitle: subtitle: Text(
Text(e.app.installedVersion ?? 'Not Installed'), e.app.installedVersion ?? 'Not Installed'),
trailing: e.downloadProgress != null trailing: e.downloadProgress != null
? Text( ? Text(
'Downloading - ${e.downloadProgress!.toInt()}%') 'Downloading - ${e.downloadProgress!.toInt()}%')
@@ -54,6 +70,6 @@ class _AppsPageState extends State<AppsPage> {
.toList(), .toList(),
), ),
), ),
); ));
} }
} }

View File

@@ -132,6 +132,15 @@ class AppsProvider with ChangeNotifier {
return appsDir; return appsDir;
} }
Future<void> deleteSavedAPKs() async {
(await getExternalStorageDirectory())
?.listSync()
.where((element) => element.path.endsWith('.apk'))
.forEach((element) {
element.deleteSync();
});
}
Future<void> loadApps() async { Future<void> loadApps() async {
loadingApps = true; loadingApps = true;
notifyListeners(); notifyListeners();
@@ -186,7 +195,7 @@ class AppsProvider with ChangeNotifier {
return null; return null;
} }
Future<List<App>> getUpdates() async { Future<List<App>> checkUpdates() async {
List<App> updates = []; List<App> updates = [];
if (!gettingUpdates) { if (!gettingUpdates) {
gettingUpdates = true; gettingUpdates = true;
@@ -203,14 +212,16 @@ class AppsProvider with ChangeNotifier {
return updates; return updates;
} }
Future<void> installUpdates() async { List<String> getExistingUpdates() {
List<String> updateAppIds = [];
List<String> appIds = apps.keys.toList(); List<String> appIds = apps.keys.toList();
for (int i = 0; i < appIds.length; i++) { for (int i = 0; i < appIds.length; i++) {
App? app = apps[appIds[i]]!.app; App? app = apps[appIds[i]]!.app;
if (app.installedVersion != app.latestVersion) { if (app.installedVersion != app.latestVersion) {
await downloadAndInstallLatestApp(app.id); updateAppIds.add(app.id);
} }
} }
return updateAppIds;
} }
@override @override

View File

@@ -23,6 +23,7 @@ class APKDetails {
// App Source abstract class (diff. implementations for GitHub, GitLab, etc.) // App Source abstract class (diff. implementations for GitHub, GitLab, etc.)
abstract class AppSource { abstract class AppSource {
late String sourceId;
String standardizeURL(String url); String standardizeURL(String url);
Future<APKDetails> getLatestAPKDetails(String standardUrl); Future<APKDetails> getLatestAPKDetails(String standardUrl);
AppNames getAppNames(String standardUrl); AppNames getAppNames(String standardUrl);
@@ -77,6 +78,9 @@ class App {
// Specific App Source classes // Specific App Source classes
class GitHub implements AppSource { class GitHub implements AppSource {
@override
String sourceId = 'github';
@override @override
String standardizeURL(String url) { String standardizeURL(String url) {
RegExp standardUrlRegEx = RegExp(r'^https?://github.com/[^/]*/[^/]*'); RegExp standardUrlRegEx = RegExp(r'^https?://github.com/[^/]*/[^/]*');
@@ -143,12 +147,15 @@ class SourceService {
url.toLowerCase().indexOf('https://') != 0) { url.toLowerCase().indexOf('https://') != 0) {
url = 'https://$url'; url = 'https://$url';
} }
if (url.toLowerCase().indexOf('https://www.') == 0) {
url = 'https://${url.substring(12)}';
}
AppSource source = getSource(url); AppSource source = getSource(url);
String standardUrl = source.standardizeURL(url); String standardUrl = source.standardizeURL(url);
AppNames names = source.getAppNames(standardUrl); AppNames names = source.getAppNames(standardUrl);
APKDetails apk = await source.getLatestAPKDetails(standardUrl); APKDetails apk = await source.getLatestAPKDetails(standardUrl);
return App( return App(
'${names.author}_${names.name}', '${names.author}_${names.name}_${source.sourceId}',
standardUrl, standardUrl,
names.author[0].toUpperCase() + names.author.substring(1), names.author[0].toUpperCase() + names.author.substring(1),
names.name[0].toUpperCase() + names.name.substring(1), names.name[0].toUpperCase() + names.name.substring(1),

View File

@@ -91,7 +91,7 @@ packages:
name: dbus name: dbus
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.7" version: "0.7.8"
dynamic_color: dynamic_color:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -119,7 +119,7 @@ packages:
name: file name: file
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.1.2" version: "6.1.4"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@@ -152,7 +152,7 @@ packages:
name: flutter_local_notifications name: flutter_local_notifications
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "9.7.0" version: "9.8.0+1"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@@ -281,7 +281,7 @@ packages:
name: path_provider_android name: path_provider_android
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.17" version: "2.0.20"
path_provider_ios: path_provider_ios:
dependency: transitive dependency: transitive
description: description:
@@ -552,7 +552,7 @@ packages:
name: webview_flutter_platform_interface name: webview_flutter_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.1" version: "1.9.2"
webview_flutter_wkwebview: webview_flutter_wkwebview:
dependency: transitive dependency: transitive
description: description:
@@ -580,7 +580,7 @@ packages:
name: xdg_directories name: xdg_directories
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.0+1" version: "0.2.0+2"
xml: xml:
dependency: transitive dependency: transitive
description: description:

View File

@@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 0.1.0+1 version: 0.1.2+3 # When changing this, update the tag in main() accordingly
environment: environment:
sdk: '>=2.19.0-79.0.dev <3.0.0' sdk: '>=2.19.0-79.0.dev <3.0.0'
@@ -38,7 +38,7 @@ dependencies:
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
path_provider: ^2.0.11 path_provider: ^2.0.11
flutter_fgbg: ^0.2.0 # Try removing reliance on this flutter_fgbg: ^0.2.0 # Try removing reliance on this
flutter_local_notifications: ^9.7.0 flutter_local_notifications: ^9.8.0+1
provider: ^6.0.3 provider: ^6.0.3
http: ^0.13.5 http: ^0.13.5
webview_flutter: ^3.0.4 webview_flutter: ^3.0.4