diff --git a/lib/main.dart b/lib/main.dart index 72e7af4..b7b95f3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:obtainium/services/apk_service.dart'; +import 'package:obtainium/services/app_service.dart'; import 'package:obtainium/services/source_service.dart'; import 'package:provider/provider.dart'; void main() async { - ; WidgetsFlutterBinding.ensureInitialized(); runApp(MultiProvider( providers: [ @@ -12,7 +12,9 @@ void main() async { create: (context) => APKService(), dispose: (context, apkInstallService) => apkInstallService.dispose(), ), - Provider(create: (context) => SourceService()) + Provider(create: (context) => SourceService()), + Provider( + create: (context) => AppService(Provider.of(context))) ], child: const MyApp(), )); @@ -59,9 +61,9 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { int ind = 0; var urls = [ - "https://github.com/Ashinch/ReadYou/releases/download/0.8.0/ReadYou-0.8.0-eec397e.apk", - "https://github.com/Ashinch/ReadYou/releases/download/0.8.1/ReadYou-0.8.1-c741f19.apk", - "https://github.com/Ashinch/ReadYou/releases/download/0.8.3/ReadYou-0.8.3-7a47329.apk" + "https://github.com/Ashinch/ReadYou/releases/download", // Should work + "http://github.com/syncthing/syncthing-android/releases/tag/1.20.4", // Should work + "https://github.com/videolan/vlc" // Should not ]; @override @@ -83,16 +85,14 @@ class _MyHomePageState extends State { ), floatingActionButton: FloatingActionButton( onPressed: () { - var source = Provider.of(context).getSource(urls[ind]); - - var standardURL = Provider.of(context) - .standardizeURL(urls[ind], source.standardURLRegEx); - var names = - Provider.of(context).getAppNames(standardURL); - Provider.of(context, listen: false).downloadAndInstallAPK( - urls[ind], "${names.author}_${names.name}"); - setState(() { - ind = ind == (urls.length - 1) ? 0 : ind + 1; + Provider.of(context).getApp(urls[ind]).then((app) { + Provider.of(context, listen: false) + .downloadAndInstallAPK(app.apkUrl, app.id); + setState(() { + ind = ind == (urls.length - 1) ? 0 : ind + 1; + }); + }).catchError((err) { + print(err); }); }, tooltip: 'Increment', diff --git a/lib/models.dart b/lib/models.dart deleted file mode 100644 index d56aa2f..0000000 --- a/lib/models.dart +++ /dev/null @@ -1,10 +0,0 @@ -class App { - late String id; - late String url; - String? installedVersion; - late String latestVersion; - String? readmeHTML; - String? base64Icon; - App(this.id, this.url, this.installedVersion, this.latestVersion, - this.readmeHTML, this.base64Icon); -} diff --git a/lib/services/app_service.dart b/lib/services/app_service.dart new file mode 100644 index 0000000..7a01004 --- /dev/null +++ b/lib/services/app_service.dart @@ -0,0 +1,27 @@ +import 'package:obtainium/services/source_service.dart'; + +class App { + late String id; + late String url; + String? installedVersion; + late String latestVersion; + late String apkUrl; + App(this.id, this.url, this.installedVersion, this.latestVersion, + this.apkUrl); +} + +class AppService { + late SourceService sourceService; + AppService(this.sourceService); + + Future getApp(String url) async { + AppSource source = sourceService.getSource(url); + String standardUrl = source.standardizeURL(url); + AppNames names = source.getAppNames(standardUrl); + APKDetails apk = await source.getLatestAPKUrl(standardUrl); + return App("${names.author}_${names.name}", standardUrl, null, apk.version, + apk.downloadUrl); + } + + // Load Apps, Save App +} diff --git a/lib/services/source_service.dart b/lib/services/source_service.dart index 5fd2171..5f3281f 100644 --- a/lib/services/source_service.dart +++ b/lib/services/source_service.dart @@ -1,9 +1,7 @@ import 'dart:convert'; import 'package:http/http.dart'; -import 'package:markdown/markdown.dart'; -import 'package:html/parser.dart'; -// Sub-classes of App Source +// Sub-classes used in App Source class AppNames { late String author; @@ -19,33 +17,38 @@ class APKDetails { APKDetails(this.version, this.downloadUrl); } -// App Source abstract class (GitHub, GitLab, etc.) +// App Source abstract class (diff. implementations for GitHub, GitLab, etc.) abstract class AppSource { - late RegExp standardURLRegEx; - Future getLatestAPKUrl(String url); - Future getReadMeHTML(String url); - Future getBase64IconURLFromHTML(String url, String html); - - AppSource(this.standardURLRegEx); + String standardizeURL(String url); + Future getLatestAPKUrl(String standardUrl); + AppNames getAppNames(String standardUrl); } -// Specific App Source definitions +// Specific App Source classes -class GitHub extends AppSource { - GitHub() : super(RegExp(r"^https?://github.com/[^/]*/[^/]*")); +class GitHub implements AppSource { + @override + String standardizeURL(String url) { + RegExp standardUrlRegEx = RegExp(r"^https?://github.com/[^/]*/[^/]*"); + var match = standardUrlRegEx.firstMatch(url.toLowerCase()); + if (match == null) { + throw "Not a valid URL"; + } + return url.substring(0, match.end); + } - String getRawContentURL(String url) { + String convertURLToRawContentURL(String url) { int tempInd1 = url.indexOf('://') + 3; - int tempInd2 = url.indexOf('://') + 13; + int tempInd2 = url.substring(tempInd1).indexOf('/') + tempInd1; return "${url.substring(0, tempInd1)}raw.githubusercontent.com${url.substring(tempInd2)}"; } @override - Future getLatestAPKUrl(String url) async { - int tempInd = url.indexOf('://') + 3; + Future getLatestAPKUrl(String standardUrl) async { + int tempInd = standardUrl.indexOf('://') + 3; Response res = await get(Uri.parse( - "${url.substring(0, tempInd)}api.${url.substring(tempInd)}/releases/latest")); + "${standardUrl.substring(0, tempInd)}api.${standardUrl.substring(tempInd)}/releases/latest")); if (res.statusCode == 200) { var release = jsonDecode(res.body); for (var i = 0; i < release['assets'].length; i++) { @@ -65,51 +68,14 @@ class GitHub extends AppSource { } @override - Future getReadMeHTML(String url) async { - String uri = getRawContentURL(url); - List possibleSuffixes = ["main/README.md", "master/README.md"]; - for (var i = 0; i < possibleSuffixes.length; i++) { - Response res = await get(Uri.parse("$uri/${possibleSuffixes[i]}")); - if (res.statusCode == 200) { - return markdownToHtml(res.body); - } - } - return null; - } - - @override - Future getBase64IconURLFromHTML(String url, String html) async { - var icon = parse(html).getElementsByClassName("img")?[0]; - if (icon != null) { - String uri = getRawContentURL(url); - List possibleBranches = ["main", "master"]; - for (var i = 0; i < possibleBranches.length; i++) { - var imgUrl = "$uri/${possibleBranches[i]}/${icon.attributes['src']}"; - Response res = await get(Uri.parse(imgUrl)); - if (res.statusCode == 200) { - return imgUrl; - } - } - } - return null; + AppNames getAppNames(String standardUrl) { + String temp = standardUrl.substring(standardUrl.indexOf('://') + 3); + List names = temp.substring(temp.indexOf('/')).split('/'); + return AppNames(names[0], names[1]); } } class SourceService { - String standardizeURL(String url, RegExp standardURLRegEx) { - var match = standardURLRegEx.firstMatch(url.toLowerCase()); - if (match == null) { - throw "Not a valid URL"; - } - return url.substring(0, match.end); - } - - AppNames getAppNames(String standardURL) { - String temp = standardURL.substring(standardURL.indexOf('://') + 3); - List names = temp.substring(temp.indexOf('/')).split('/'); - return AppNames(names[0], names[1]); - } - // Add more source classes here so they are available via the service var github = GitHub(); AppSource getSource(String url) { @@ -119,19 +85,3 @@ class SourceService { throw "URL does not match a known source"; } } - -/* -- Make a function that validates and standardizes github URLs, do the same for gitlab (fail = error) -- Make a function that gets the App title and Author name from a github URL, do the same for gitlab (can't fail) -- Make a function that takes a github URL and finds the latest APK release if any (with version), do the same for gitlab (fail = error) -- Make a function that takes a github URL and returns a README HTML if any, do the same for gitlab (fail = "no description") -- Make a function that looks for the first image in a README HTML and returns its url (fail = no icon) - -- Make a function that integrates all above and returns an App object for a given github URL, do the same for gitlab - -- Make a function that detects the URL (Github or Gitlab) and runs the right function above - -- Make a function that can save/load an App object to/from persistent storage (JSON file with unique App ID as file name) - -- Make a function (using the above fn) that loads an array of all Apps -*/ \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 0f70400..0996514 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -43,13 +43,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" - csslib: - dependency: transitive - description: - name: csslib - url: "https://pub.dartlang.org" - source: hosted - version: "0.17.2" cupertino_icons: dependency: "direct main" description: @@ -137,13 +130,6 @@ packages: description: flutter source: sdk version: "0.0.0" - html: - dependency: "direct main" - description: - name: html - url: "https://pub.dartlang.org" - source: hosted - version: "0.15.0" http: dependency: "direct main" description: @@ -165,13 +151,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" - markdown: - dependency: "direct main" - description: - name: markdown - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.0" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index eb660fc..c7e775d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,8 +42,6 @@ dependencies: flutter_local_notifications: ^9.7.0 provider: ^6.0.3 http: ^0.13.5 - markdown: ^6.0.0 - html: ^0.15.0 dev_dependencies: flutter_test: