diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 261a84bb..201a79ff 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -19,8 +19,6 @@ jobs: channel: 'stable' - name: Set up Flutter run: flutter pub get - - name: Generate files with Builder - run: flutter packages pub run build_runner build --delete-conflicting-outputs - name: Build with Flutter env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index a78395b8..ab6de429 100644 --- a/.gitignore +++ b/.gitignore @@ -42,8 +42,6 @@ version # Flutter/Dart/Pub related **/doc/api/ **/*.g.dart -**/*.locator.dart -**/*.router.dart .dart_tool/ .flutter-plugins .flutter-plugins-dependencies diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0fa4713f..490ed99c 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,7 +2,7 @@ "version": "2.0.0", "tasks": [ { - "label": "Generate (Builder)", + "label": "Build (Serializer)", "type": "shell", "command": "flutter packages pub run build_runner build --delete-conflicting-outputs", "problemMatcher": [] @@ -30,7 +30,7 @@ "problemMatcher": [] }, { - "label": "Clean (Builder)", + "label": "Clean (Serializer)", "type": "shell", "command": "flutter packages pub run build_runner clean", "problemMatcher": [] @@ -39,7 +39,7 @@ "label": "Build all (Android)", "dependsOrder": "sequence", "dependsOn": [ - "Generate (Builder)", + "Build (Serializer)", "Build (Android)" ], "problemMatcher": [] @@ -49,7 +49,7 @@ "dependsOrder": "sequence", "dependsOn": [ "Clean (Flutter)", - "Clean (Builder)" + "Clean (Serializer)" ], "problemMatcher": [] }, diff --git a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt index ba725783..971836df 100644 --- a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt +++ b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt @@ -179,41 +179,10 @@ class MainActivity : FlutterActivity() { return true } - fun createPatcher( - inputFilePath: String, - cacheDirPath: String, - resourcePatching: Boolean - ): Boolean { + fun createPatcher(inputFilePath: String, cacheDirPath: String, resourcePatching: Boolean): Boolean { val inputFile = File(inputFilePath) val aaptPath = Aapt.binary(applicationContext).absolutePath - patcher = - Patcher( - PatcherOptions( - inputFile, - cacheDirPath, - resourcePatching, - aaptPath, - cacheDirPath, - logger = - object : app.revanced.patcher.logging.Logger { - override fun error(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - - override fun warn(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - - override fun info(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - - override fun trace(msg: String) { - methodChannel.invokeMethod("updateInstallerLog", msg) - } - } - ) - ) + patcher = Patcher(PatcherOptions(inputFile, cacheDirPath, resourcePatching, aaptPath, cacheDirPath)) return true } diff --git a/assets/images/reddit.png b/assets/images/reddit.png new file mode 100644 index 00000000..941a12e6 Binary files /dev/null and b/assets/images/reddit.png differ diff --git a/assets/images/revanced.svg b/assets/images/revanced.svg new file mode 100644 index 00000000..7318abbd --- /dev/null +++ b/assets/images/revanced.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/app/app.dart b/lib/app/app.dart index 8765ae4f..6d7ab8ec 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -5,7 +5,6 @@ import 'package:revanced_manager/services/root_api.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_view.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/contributors/contributors_view.dart'; -import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; import 'package:revanced_manager/ui/views/installer/installer_view.dart'; import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; @@ -32,7 +31,6 @@ import 'package:stacked_themes/stacked_themes.dart'; LazySingleton(classType: PatcherAPI), LazySingleton(classType: ManagerAPI), LazySingleton(classType: RootAPI), - LazySingleton(classType: HomeViewModel), LazySingleton(classType: PatcherViewModel), LazySingleton(classType: AppSelectorViewModel), LazySingleton(classType: PatchesSelectorViewModel), diff --git a/lib/app/app.locator.dart b/lib/app/app.locator.dart new file mode 100644 index 00000000..6476d9a5 --- /dev/null +++ b/lib/app/app.locator.dart @@ -0,0 +1,39 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// StackedLocatorGenerator +// ************************************************************************** + +// ignore_for_file: public_member_api_docs, depend_on_referenced_packages + +import 'package:stacked_core/stacked_core.dart'; +import 'package:stacked_services/stacked_services.dart'; +import 'package:stacked_themes/stacked_themes.dart'; + +import '../services/manager_api.dart'; +import '../services/patcher_api.dart'; +import '../services/root_api.dart'; +import '../ui/views/app_selector/app_selector_viewmodel.dart'; +import '../ui/views/installer/installer_viewmodel.dart'; +import '../ui/views/patcher/patcher_viewmodel.dart'; +import '../ui/views/patches_selector/patches_selector_viewmodel.dart'; + +final locator = StackedLocator.instance; + +Future setupLocator( + {String? environment, EnvironmentFilter? environmentFilter}) async { +// Register environments + locator.registerEnvironment( + environment: environment, environmentFilter: environmentFilter); + +// Register dependencies + locator.registerLazySingleton(() => NavigationService()); + locator.registerLazySingleton(() => PatcherAPI()); + locator.registerLazySingleton(() => ManagerAPI()); + locator.registerLazySingleton(() => RootAPI()); + locator.registerLazySingleton(() => PatcherViewModel()); + locator.registerLazySingleton(() => AppSelectorViewModel()); + locator.registerLazySingleton(() => PatchesSelectorViewModel()); + locator.registerLazySingleton(() => InstallerViewModel()); + locator.registerLazySingleton(() => ThemeService.getInstance()); +} diff --git a/lib/app/app.router.dart b/lib/app/app.router.dart new file mode 100644 index 00000000..62e381df --- /dev/null +++ b/lib/app/app.router.dart @@ -0,0 +1,231 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// StackedRouterGenerator +// ************************************************************************** + +// ignore_for_file: public_member_api_docs, unused_import, non_constant_identifier_names + +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; +import 'package:stacked_services/stacked_services.dart'; + +import '../main.dart'; +import '../ui/views/app_selector/app_selector_view.dart'; +import '../ui/views/contributors/contributors_view.dart'; +import '../ui/views/installer/installer_view.dart'; +import '../ui/views/patches_selector/patches_selector_view.dart'; +import '../ui/views/root_checker/root_checker_view.dart'; +import '../ui/views/settings/settings_view.dart'; + +class Routes { + static const String navigation = '/Navigation'; + static const String appSelectorView = '/app-selector-view'; + static const String patchesSelectorView = '/patches-selector-view'; + static const String installerView = '/installer-view'; + static const String settingsView = '/settings-view'; + static const String contributorsView = '/contributors-view'; + static const String rootCheckerView = '/root-checker-view'; + static const all = { + navigation, + appSelectorView, + patchesSelectorView, + installerView, + settingsView, + contributorsView, + rootCheckerView, + }; +} + +class StackedRouter extends RouterBase { + @override + List get routes => _routes; + final _routes = [ + RouteDef(Routes.navigation, page: Navigation), + RouteDef(Routes.appSelectorView, page: AppSelectorView), + RouteDef(Routes.patchesSelectorView, page: PatchesSelectorView), + RouteDef(Routes.installerView, page: InstallerView), + RouteDef(Routes.settingsView, page: SettingsView), + RouteDef(Routes.contributorsView, page: ContributorsView), + RouteDef(Routes.rootCheckerView, page: RootCheckerView), + ]; + @override + Map get pagesMap => _pagesMap; + final _pagesMap = { + Navigation: (data) { + return MaterialPageRoute( + builder: (context) => const Navigation(), + settings: data, + ); + }, + AppSelectorView: (data) { + return MaterialPageRoute( + builder: (context) => const AppSelectorView(), + settings: data, + ); + }, + PatchesSelectorView: (data) { + return MaterialPageRoute( + builder: (context) => const PatchesSelectorView(), + settings: data, + ); + }, + InstallerView: (data) { + var args = data.getArgs( + orElse: () => InstallerViewArguments(), + ); + return MaterialPageRoute( + builder: (context) => InstallerView(key: args.key), + settings: data, + ); + }, + SettingsView: (data) { + return MaterialPageRoute( + builder: (context) => const SettingsView(), + settings: data, + ); + }, + ContributorsView: (data) { + return MaterialPageRoute( + builder: (context) => const ContributorsView(), + settings: data, + ); + }, + RootCheckerView: (data) { + return MaterialPageRoute( + builder: (context) => const RootCheckerView(), + settings: data, + ); + }, + }; +} + +/// ************************************************************************ +/// Arguments holder classes +/// ************************************************************************* + +/// InstallerView arguments holder class +class InstallerViewArguments { + final Key? key; + InstallerViewArguments({this.key}); +} + +/// ************************************************************************ +/// Extension for strongly typed navigation +/// ************************************************************************* + +extension NavigatorStateExtension on NavigationService { + Future navigateToNavigation({ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo( + Routes.navigation, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition, + ); + } + + Future navigateToAppSelectorView({ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo( + Routes.appSelectorView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition, + ); + } + + Future navigateToPatchesSelectorView({ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo( + Routes.patchesSelectorView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition, + ); + } + + Future navigateToInstallerView({ + Key? key, + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo( + Routes.installerView, + arguments: InstallerViewArguments(key: key), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition, + ); + } + + Future navigateToSettingsView({ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo( + Routes.settingsView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition, + ); + } + + Future navigateToContributorsView({ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo( + Routes.contributorsView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition, + ); + } + + Future navigateToRootCheckerView({ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo( + Routes.rootCheckerView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition, + ); + } +} diff --git a/lib/models/patched_application.dart b/lib/models/patched_application.dart index ea530fa6..ecb7a62c 100644 --- a/lib/models/patched_application.dart +++ b/lib/models/patched_application.dart @@ -1,43 +1,21 @@ -import 'dart:typed_data'; -import 'package:json_annotation/json_annotation.dart'; +import 'package:revanced_manager/models/patch.dart'; -part 'patched_application.g.dart'; - -@JsonSerializable() class PatchedApplication { final String name; final String packageName; final String version; final String apkFilePath; - @JsonKey( - fromJson: bytesFromString, - toJson: bytesToString, - ) - final Uint8List icon; - final DateTime patchDate; final bool isRooted; final bool isFromStorage; - final List appliedPatches; + final List appliedPatches; PatchedApplication({ required this.name, required this.packageName, required this.version, required this.apkFilePath, - required this.icon, - required this.patchDate, required this.isRooted, required this.isFromStorage, - this.appliedPatches = const [], + this.appliedPatches = const [], }); - - factory PatchedApplication.fromJson(Map json) => - _$PatchedApplicationFromJson(json); - - Map toJson() => _$PatchedApplicationToJson(this); - - static Uint8List bytesFromString(String pictureUrl) => - Uint8List.fromList(pictureUrl.codeUnits); - - static String bytesToString(Uint8List bytes) => String.fromCharCodes(bytes); } diff --git a/lib/ui/views/app_selector/app_selector_viewmodel.dart b/lib/ui/views/app_selector/app_selector_viewmodel.dart index 27cf1c4a..a3541144 100644 --- a/lib/ui/views/app_selector/app_selector_viewmodel.dart +++ b/lib/ui/views/app_selector/app_selector_viewmodel.dart @@ -4,6 +4,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:package_archive_info/package_archive_info.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/patcher_api.dart'; @@ -38,8 +39,6 @@ class AppSelectorViewModel extends BaseViewModel { packageName: application.packageName, version: application.versionName!, apkFilePath: application.apkFilePath, - icon: application.icon, - patchDate: DateTime.now(), isRooted: isRooted, isFromStorage: isFromStorage, ); @@ -58,25 +57,20 @@ class AppSelectorViewModel extends BaseViewModel { ); if (result != null && result.files.single.path != null) { File apkFile = File(result.files.single.path!); - ApplicationWithIcon? application = - await DeviceApps.getAppFromStorage(apkFile.path, true) - as ApplicationWithIcon?; - if (application != null) { - PatchedApplication app = PatchedApplication( - name: application.appName, - packageName: application.packageName, - version: application.versionName!, - apkFilePath: result.files.single.path!, - icon: application.icon, - patchDate: DateTime.now(), - isRooted: isRooted, - isFromStorage: isFromStorage, - ); - locator().selectedApp = app; - locator().selectedPatches.clear(); - locator().dimPatchCard = false; - locator().notifyListeners(); - } + PackageArchiveInfo? packageArchiveInfo = + await PackageArchiveInfo.fromPath(apkFile.path); + PatchedApplication app = PatchedApplication( + name: packageArchiveInfo.appName, + packageName: packageArchiveInfo.packageName, + version: packageArchiveInfo.version, + apkFilePath: result.files.single.path!, + isRooted: isRooted, + isFromStorage: isFromStorage, + ); + locator().selectedApp = app; + locator().selectedPatches.clear(); + locator().dimPatchCard = false; + locator().notifyListeners(); } } on Exception { Fluttertoast.showToast( diff --git a/lib/ui/views/home/home_view.dart b/lib/ui/views/home/home_view.dart index 295380ba..551f0c48 100644 --- a/lib/ui/views/home/home_view.dart +++ b/lib/ui/views/home/home_view.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/theme.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/available_updates_card.dart'; @@ -15,8 +14,7 @@ class HomeView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( - disposeViewModel: false, - viewModelBuilder: () => locator(), + viewModelBuilder: () => HomeViewModel(), builder: (context, model, child) => Scaffold( body: SafeArea( child: SingleChildScrollView( diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index c2e958e2..79882510 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -1,22 +1,8 @@ -import 'dart:convert'; - -import 'package:injectable/injectable.dart'; import 'package:revanced_manager/app/app.locator.dart'; -import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/manager_api.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:stacked/stacked.dart'; -@lazySingleton class HomeViewModel extends BaseViewModel { Future downloadPatches() => locator().downloadPatches(); Future downloadIntegrations() => locator().downloadIntegrations(); - - Future> getPatchedApps() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - List patchedApps = prefs.getStringList('patchedApps') ?? []; - return patchedApps - .map((app) => PatchedApplication.fromJson(json.decode(app))) - .toList(); - } } diff --git a/lib/ui/views/installer/installer_view.dart b/lib/ui/views/installer/installer_view.dart index ef359925..f915a568 100644 --- a/lib/ui/views/installer/installer_view.dart +++ b/lib/ui/views/installer/installer_view.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:stacked/stacked.dart'; @@ -82,8 +81,9 @@ class InstallerView extends StatelessWidget { ), child: SelectableText( model.logs, - style: GoogleFonts.jetBrainsMono( - fontSize: 12, + style: const TextStyle( + fontFamily: 'monospace', + fontSize: 15, height: 1.5, ), ), diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 7c30088a..708c3ff4 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -7,7 +7,6 @@ import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:stacked/stacked.dart'; class InstallerViewModel extends BaseViewModel { @@ -62,25 +61,29 @@ class InstallerViewModel extends BaseViewModel { List selectedPatches = locator().selectedPatches; if (selectedPatches.isNotEmpty) { - addLog('Initializing installer'); + addLog('Initializing installer...'); if (selectedApp.isRooted && !selectedApp.isFromStorage) { - addLog('Checking if an old patched version exists'); + addLog('Checking if an old patched version exists...'); bool oldExists = await locator().checkOldPatch(selectedApp); + addLog('Done'); if (oldExists) { - addLog('Deleting old patched version'); + addLog('Deleting old patched version...'); await locator().deleteOldPatch(selectedApp); + addLog('Done'); } } - addLog('Creating working directory'); + addLog('Creating working directory...'); bool? isSuccess = await locator().initPatcher(); if (isSuccess != null && isSuccess) { + addLog('Done'); updateProgress(0.1); - addLog('Copying original apk'); + addLog('Copying original apk...'); isSuccess = await locator().copyInputFile(apkFilePath); if (isSuccess != null && isSuccess) { + addLog('Done'); updateProgress(0.2); - addLog('Creating patcher'); + addLog('Creating patcher...'); bool resourcePatching = false; if (selectedApp.packageName == 'com.google.android.youtube' || selectedApp.packageName == @@ -92,23 +95,29 @@ class InstallerViewModel extends BaseViewModel { ); if (isSuccess != null && isSuccess) { if (selectedApp.packageName == 'com.google.android.youtube') { + addLog('Done'); updateProgress(0.3); - addLog('Merging integrations'); + addLog('Merging integrations...'); isSuccess = await locator().mergeIntegrations(); } if (isSuccess != null && isSuccess) { + addLog('Done'); updateProgress(0.5); + addLog('Applying patches...'); isSuccess = await locator().applyPatches(selectedPatches); if (isSuccess != null && isSuccess) { + addLog('Done'); updateProgress(0.7); - addLog('Repacking patched apk'); + addLog('Repacking patched apk...'); isSuccess = await locator().repackPatchedFile(); if (isSuccess != null && isSuccess) { + addLog('Done'); updateProgress(0.9); - addLog('Signing patched apk'); + addLog('Signing patched apk...'); isSuccess = await locator().signPatchedFile(); if (isSuccess != null && isSuccess) { + addLog('Done'); showButtons = true; updateProgress(1.0); } @@ -119,13 +128,13 @@ class InstallerViewModel extends BaseViewModel { } } if (isSuccess == null || !isSuccess) { - addLog('An error occurred! Aborting'); + addLog('An error occurred! Aborting...'); } } else { - addLog('No patches selected! Aborting'); + addLog('No patches selected! Aborting...'); } } else { - addLog('No app selected! Aborting'); + addLog('No app selected! Aborting...'); } await FlutterBackground.disableBackgroundExecution(); isPatching = false; @@ -136,14 +145,13 @@ class InstallerViewModel extends BaseViewModel { locator().selectedApp; if (selectedApp != null) { addLog(selectedApp.isRooted - ? 'Installing patched file using root method' - : 'Installing patched file using nonroot method'); + ? 'Installing patched file using root method...' + : 'Installing patched file using nonroot method...'); isInstalled = await locator().installPatchedFile(selectedApp); if (isInstalled) { addLog('Done'); - await saveApp(selectedApp); } else { - addLog('An error occurred! Aborting'); + addLog('An error occurred! Aborting...'); } } } @@ -173,14 +181,4 @@ class InstallerViewModel extends BaseViewModel { DeviceApps.openApp(selectedApp.packageName); } } - - Future saveApp(PatchedApplication selectedApp) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - List patchedApps = prefs.getStringList('patchedApps') ?? []; - String app = selectedApp.toJson().toString(); - if (!patchedApps.contains(app)) { - patchedApps.add(app); - prefs.setStringList('patchedApps', patchedApps); - } - } } diff --git a/lib/ui/widgets/application_item.dart b/lib/ui/widgets/application_item.dart index 4c5c49db..805e8a24 100644 --- a/lib/ui/widgets/application_item.dart +++ b/lib/ui/widgets/application_item.dart @@ -1,30 +1,40 @@ -import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/ui/widgets/patch_text_button.dart'; -import 'package:timeago/timeago.dart'; class ApplicationItem extends StatelessWidget { - final Uint8List icon; + final String asset; final String name; - final DateTime patchDate; + final String releaseDate; final Function()? onPressed; const ApplicationItem({ Key? key, - required this.icon, + required this.asset, required this.name, - required this.patchDate, + required this.releaseDate, required this.onPressed, }) : super(key: key); @override Widget build(BuildContext context) { + final isSVG = asset.endsWith('.svg'); return ListTile( horizontalTitleGap: 12.0, - leading: Image.memory(icon), + leading: isSVG + ? SvgPicture.asset( + asset, + height: 26, + width: 26, + ) + : Image.asset( + asset, + height: 39, + width: 39, + ), title: Text( name, style: GoogleFonts.roboto( @@ -33,7 +43,7 @@ class ApplicationItem extends StatelessWidget { ), ), subtitle: Text( - format(patchDate), + releaseDate, style: robotoTextStyle, ), trailing: PatchTextButton( diff --git a/lib/ui/widgets/available_updates_card.dart b/lib/ui/widgets/available_updates_card.dart index 075e578d..d2e05b7f 100644 --- a/lib/ui/widgets/available_updates_card.dart +++ b/lib/ui/widgets/available_updates_card.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:revanced_manager/app/app.locator.dart'; -import 'package:revanced_manager/models/patched_application.dart'; -import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/application_item.dart'; import 'package:revanced_manager/ui/widgets/patch_text_button.dart'; @@ -53,19 +50,17 @@ class AvailableUpdatesCard extends StatelessWidget { ], ), ), - FutureBuilder>( - future: locator().getPatchedApps(), - builder: (context, snapshot) => - snapshot.hasData && snapshot.data!.length > 1 - ? ListView.builder( - itemBuilder: (context, index) => ApplicationItem( - icon: snapshot.data![index].icon, - name: snapshot.data![index].name, - patchDate: snapshot.data![index].patchDate, - onPressed: () => {}, - ), - ) - : Container(), + ApplicationItem( + asset: 'assets/images/revanced.svg', + name: 'ReVanced', + releaseDate: '2 days ago', + onPressed: () => {}, + ), + ApplicationItem( + asset: 'assets/images/reddit.png', + name: 'ReReddit', + releaseDate: 'Released 1 month ago', + onPressed: () => {}, ), const SizedBox(height: 4), I18nText( diff --git a/lib/ui/widgets/installed_apps_card.dart b/lib/ui/widgets/installed_apps_card.dart index a69971b8..b77deba3 100644 --- a/lib/ui/widgets/installed_apps_card.dart +++ b/lib/ui/widgets/installed_apps_card.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:revanced_manager/app/app.locator.dart'; -import 'package:revanced_manager/models/patched_application.dart'; -import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/application_item.dart'; class InstalledAppsCard extends StatelessWidget { @@ -36,19 +33,11 @@ class InstalledAppsCard extends StatelessWidget { ), ), ), - FutureBuilder>( - future: locator().getPatchedApps(), - builder: (context, snapshot) => - snapshot.hasData && snapshot.data!.length > 1 - ? ListView.builder( - itemBuilder: (context, index) => ApplicationItem( - icon: snapshot.data![index].icon, - name: snapshot.data![index].name, - patchDate: snapshot.data![index].patchDate, - onPressed: () => {}, - ), - ) - : Container(), + ApplicationItem( + asset: 'assets/images/revanced.svg', + name: 'ReVanced', + releaseDate: '2 days ago', + onPressed: () => {}, ), I18nText( 'installedAppsCard.changelogLabel', diff --git a/pubspec.yaml b/pubspec.yaml index 09ee05e3..bb504833 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,10 +12,7 @@ environment: dependencies: app_installer: ^1.1.0 cupertino_icons: ^1.0.2 - device_apps: - git: - url: https://github.com/ponces/flutter_plugin_device_apps - ref: appinfo-from-storage + device_apps: ^2.2.0 dio: ^4.0.6 file_picker: ^5.0.1 flutter: @@ -31,6 +28,7 @@ dependencies: http: ^0.13.4 injectable: ^1.5.3 json_annotation: ^4.6.0 + package_archive_info: ^0.1.0 path_provider: ^2.0.11 root: ^2.0.2 share_extend: ^2.0.0