Compare commits

..

23 Commits

Author SHA1 Message Date
6bd218277d build: Bump version to v0.0.9 2022-09-17 19:40:44 +01:00
83ad7605c4 fix: Minor improvements on App Info view 2022-09-17 19:30:04 +01:00
5fbc8ff7a0 feat: Retrieve unsaved apps from manager's root folder and known packages from user's apps list 2022-09-17 19:29:46 +01:00
bb4b59eee6 Disable permission_handler package for now 2022-09-17 17:42:29 +01:00
4cfb620d63 build: Bump version to v0.0.8. 2022-09-17 20:58:19 +05:30
55739a9c78 fix: background should be more opaque. 2022-09-17 20:56:44 +05:30
482599bb4e fix: Do not import dart:html 2022-09-17 14:59:23 +01:00
3aaf49fee0 fix: Only init foreground service if user allowed IGNORE_BATTERY_OPTIMIZATIONS permission 2022-09-17 14:55:00 +01:00
0424ee235c build: Bump patcher dependency version 2022-09-17 14:51:09 +01:00
a178afce99 fix: Fix typo on menu options visibility 2022-09-17 14:47:03 +01:00
ef3685c817 fix: Add Unpatch option on App Info view 2022-09-17 14:45:43 +01:00
e74fce8574 Merge branch 'flutter' of github.com:revanced/revanced-manager into flutter 2022-09-17 14:42:58 +01:00
73e4ae1416 build: restrict manager to android 8. 2022-09-17 16:14:24 +03:00
bcf3b36b13 feat: tweak UI 2022-09-17 16:13:41 +03:00
9c3626c8ed fix: Request permissions a single time at boot 2022-09-16 17:29:32 +01:00
a3dca8c142 fix: Add build mode to about widget 2022-09-16 16:39:57 +01:00
ef0c59f693 fix: Surround isRooted with a try/catch just to be safe 2022-09-16 16:39:37 +01:00
31756884b6 build: Bump version to v0.0.7. 2022-09-16 03:48:23 +05:30
0a2a495ab0 feat: custom animated progressbar. 2022-09-16 03:46:46 +05:30
8300cc4071 feat: dropdown for changelogs. 2022-09-16 00:49:11 +05:30
9f58757caf feat: Apply dark/light mode to system navigation bar too 2022-09-15 13:27:48 +01:00
5d296038b7 fix: Increase API's maxAge to 1 day 2022-09-15 12:33:19 +01:00
9f85450c6c build: Bump version to v0.0.6 2022-09-15 09:14:43 +01:00
23 changed files with 381 additions and 129 deletions

View File

@ -44,7 +44,7 @@ android {
defaultConfig {
applicationId "app.revanced.manager.flutter"
minSdkVersion 21
minSdkVersion 26
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
@ -71,7 +71,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// ReVanced
implementation "app.revanced:revanced-patcher:4.4.0"
implementation "app.revanced:revanced-patcher:4.4.1"
// Signing & aligning
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")

View File

@ -69,7 +69,8 @@
},
"patchesSelectorView": {
"searchBarHint": "Search patches",
"doneButton": "Done"
"doneButton": "Done",
"noPatchesFound": "No patches found for the selected app."
},
"patchItem": {
"unsupportedWarningButton": "Unsupported version",
@ -120,8 +121,11 @@
"openButton": "Open",
"uninstallButton": "Uninstall",
"patchButton": "Patch",
"unpatchButton": "Unpatch",
"uninstallDialogTitle": "Uninstall",
"uninstallDialogText": "Are you sure you want to uninstall this app?",
"unpatchDialogTitle": "Unpatch",
"unpatchDialogText": "Are you sure you want to unpatch this app?",
"rootDialogTitle": "Error",
"rootDialogText": "App was installed with root mode enabled but currently root mode is disabled.\nPlease enable root mode first.",
"packageNameLabel": "Package Name",

View File

@ -13,7 +13,7 @@ class GithubAPI {
final Dio _dio = Dio();
final DioCacheManager _dioCacheManager = DioCacheManager(CacheConfig());
final Options _cacheOptions = buildCacheOptions(
const Duration(hours: 1),
const Duration(days: 1),
maxStale: const Duration(days: 7),
);
final Map<String, String> repoAppPath = {

View File

@ -165,33 +165,96 @@ class ManagerAPI {
return packageInfo.version;
}
Future<void> reAssessSavedApps() async {
List<PatchedApplication> patchedApps = getPatchedApps();
Future<List<PatchedApplication>> getAppsToRemove(
List<PatchedApplication> patchedApps,
) async {
List<PatchedApplication> toRemove = [];
for (PatchedApplication app in patchedApps) {
bool isRemove = await isAppUninstalled(app);
if (isRemove) {
toRemove.add(app);
} else {
app.hasUpdates = await hasAppUpdates(app.packageName, app.patchDate);
app.changelog = await getAppChangelog(app.packageName, app.patchDate);
if (!app.hasUpdates) {
String? currentInstalledVersion =
(await DeviceApps.getApp(app.packageName))?.versionName;
if (currentInstalledVersion != null) {
String currentSavedVersion = app.version;
int currentInstalledVersionInt = int.parse(
currentInstalledVersion.replaceAll(RegExp('[^0-9]'), ''));
int currentSavedVersionInt =
int.parse(currentSavedVersion.replaceAll(RegExp('[^0-9]'), ''));
if (currentInstalledVersionInt > currentSavedVersionInt) {
app.hasUpdates = true;
}
}
}
return toRemove;
}
Future<List<PatchedApplication>> getUnsavedApps(
List<PatchedApplication> patchedApps,
) async {
List<PatchedApplication> unsavedApps = [];
List<String> installedApps = await _rootAPI.getInstalledApps();
for (String packageName in installedApps) {
if (!patchedApps.any((app) => app.packageName == packageName)) {
ApplicationWithIcon? application =
await DeviceApps.getApp(packageName, true) as ApplicationWithIcon?;
if (application != null) {
unsavedApps.add(
PatchedApplication(
name: application.appName,
packageName: application.packageName,
version: application.versionName!,
apkFilePath: application.apkFilePath,
icon: application.icon,
patchDate: DateTime.now(),
isRooted: true,
),
);
}
}
}
List<Application> userApps = await DeviceApps.getInstalledApplications(
includeSystemApps: false,
includeAppIcons: false,
);
for (Application app in userApps) {
if (app.packageName.startsWith('app.revanced') &&
!app.packageName.startsWith('app.revanced.manager.')) {
ApplicationWithIcon? application =
await DeviceApps.getApp(app.packageName, true)
as ApplicationWithIcon?;
if (application != null) {
unsavedApps.add(
PatchedApplication(
name: application.appName,
packageName: application.packageName,
version: application.versionName!,
apkFilePath: application.apkFilePath,
icon: application.icon,
patchDate: DateTime.now(),
isRooted: false,
),
);
}
}
}
return unsavedApps;
}
Future<void> reAssessSavedApps() async {
List<PatchedApplication> patchedApps = getPatchedApps();
List<PatchedApplication> unsavedApps = await getUnsavedApps(patchedApps);
patchedApps.addAll(unsavedApps);
List<PatchedApplication> toRemove = await getAppsToRemove(patchedApps);
patchedApps.removeWhere((a) => toRemove.contains(a));
for (PatchedApplication app in patchedApps) {
app.hasUpdates = await hasAppUpdates(app.packageName, app.patchDate);
app.changelog = await getAppChangelog(app.packageName, app.patchDate);
if (!app.hasUpdates) {
String? currentInstalledVersion =
(await DeviceApps.getApp(app.packageName))?.versionName;
if (currentInstalledVersion != null) {
String currentSavedVersion = app.version;
int currentInstalledVersionInt = int.parse(
currentInstalledVersion.replaceAll(RegExp('[^0-9]'), ''));
int currentSavedVersionInt =
int.parse(currentSavedVersion.replaceAll(RegExp('[^0-9]'), ''));
if (currentInstalledVersionInt > currentSavedVersionInt) {
app.hasUpdates = true;
}
}
}
}
patchedApps.removeWhere((a) => toRemove.contains(a));
await setPatchedApps(patchedApps);
}

View File

@ -13,7 +13,7 @@ class RevancedAPI {
final Dio _dio = Dio();
final DioCacheManager _dioCacheManager = DioCacheManager(CacheConfig());
final Options _cacheOptions = buildCacheOptions(
const Duration(hours: 1),
const Duration(days: 1),
maxStale: const Duration(days: 7),
);

View File

@ -6,8 +6,12 @@ class RootAPI {
final String _serviceDDirPath = '/data/adb/service.d';
Future<bool> hasRootPermissions() async {
bool? isRooted = await Root.isRooted();
return isRooted != null && isRooted;
try {
bool? isRooted = await Root.isRooted();
return isRooted != null && isRooted;
} on Exception {
return false;
}
}
Future<void> setPermissions(

View File

@ -4,6 +4,7 @@ import 'package:google_fonts/google_fonts.dart';
var lightCustomColorScheme = ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
primary: const Color(0xff1B73E8),
);
var lightCustomTheme = ThemeData(
@ -23,8 +24,8 @@ var lightCustomTheme = ThemeData(
var darkCustomColorScheme = ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
primary: const Color(0xff7792BA),
surface: const Color(0xff0A0D11),
primary: const Color(0xffA5CAFF),
surface: const Color(0xff1B1A1D),
);
var darkCustomTheme = ThemeData(
@ -38,8 +39,8 @@ var darkCustomTheme = ThemeData(
),
),
),
canvasColor: const Color(0xff0A0D11),
scaffoldBackgroundColor: const Color(0xff0A0D11),
toggleableActiveColor: const Color(0xff7792BA),
canvasColor: const Color(0xff1B1A1D),
scaffoldBackgroundColor: const Color(0xff1B1A1D),
toggleableActiveColor: const Color(0xffA5CAFF),
textTheme: GoogleFonts.robotoTextTheme(ThemeData.dark().textTheme),
);

View File

@ -3,6 +3,7 @@ import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/installerView/custom_material_button.dart';
import 'package:revanced_manager/ui/widgets/installerView/gradient_progress_indicator.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_popup_menu.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_sliver_app_bar.dart';
@ -30,7 +31,7 @@ class InstallerView extends StatelessWidget {
),
actions: <Widget>[
Visibility(
visible: !model.isPatching && model.hasErrors,
visible: !model.isPatching && !model.hasErrors,
child: CustomPopupMenu(
onSelected: (value) => model.onMenuSelection(value),
children: {
@ -57,14 +58,9 @@ class InstallerView extends StatelessWidget {
),
],
bottom: PreferredSize(
preferredSize: const Size(double.infinity, 1.0),
child: LinearProgressIndicator(
color: Theme.of(context).colorScheme.primary,
backgroundColor:
Theme.of(context).colorScheme.primaryContainer,
value: model.progress,
),
),
preferredSize: const Size(double.infinity, 1.0),
child:
GradientProgressIndicator(progress: model.progress!)),
),
SliverPadding(
padding: const EdgeInsets.all(20.0),

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_background/flutter_background.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
//import 'package:permission_handler/permission_handler.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/patch.dart';
import 'package:revanced_manager/models/patched_application.dart';
@ -29,29 +30,31 @@ class InstallerViewModel extends BaseViewModel {
bool hasErrors = false;
Future<void> initialize(BuildContext context) async {
try {
await FlutterBackground.initialize(
androidConfig: FlutterBackgroundAndroidConfig(
notificationTitle: FlutterI18n.translate(
context,
'installerView.notificationTitle',
if (true /*await Permission.ignoreBatteryOptimizations.isGranted*/) {
try {
await FlutterBackground.initialize(
androidConfig: FlutterBackgroundAndroidConfig(
notificationTitle: FlutterI18n.translate(
context,
'installerView.notificationTitle',
),
notificationText: FlutterI18n.translate(
context,
'installerView.notificationText',
),
notificationImportance: AndroidNotificationImportance.Default,
notificationIcon: const AndroidResource(
name: 'ic_notification',
defType: 'drawable',
),
),
notificationText: FlutterI18n.translate(
context,
'installerView.notificationText',
),
notificationImportance: AndroidNotificationImportance.Default,
notificationIcon: const AndroidResource(
name: 'ic_notification',
defType: 'drawable',
),
),
);
await FlutterBackground.enableBackgroundExecution();
await Wakelock.enable();
} on Exception {
// ignore
);
await FlutterBackground.enableBackgroundExecution();
} on Exception {
// ignore
}
}
await Wakelock.enable();
await handlePlatformChannelMethods();
await runPatcher();
}
@ -119,12 +122,14 @@ class InstallerViewModel extends BaseViewModel {
hasErrors = true;
update(-1.0, 'Aborting...', 'No app or patches selected! Aborting');
}
try {
await FlutterBackground.disableBackgroundExecution();
await Wakelock.disable();
} on Exception {
// ignore
if (true /*await Permission.ignoreBatteryOptimizations.isGranted*/) {
try {
await FlutterBackground.disableBackgroundExecution();
} on Exception {
// ignore
}
}
await Wakelock.disable();
isPatching = false;
}

View File

@ -42,6 +42,7 @@ class NavigationView extends StatelessWidget {
context,
'navigationView.dashboardTab',
),
tooltip: '',
),
NavigationDestination(
icon: model.isIndexSelected(1)
@ -51,6 +52,7 @@ class NavigationView extends StatelessWidget {
context,
'navigationView.patcherTab',
),
tooltip: '',
),
NavigationDestination(
icon: model.isIndexSelected(2)
@ -60,6 +62,7 @@ class NavigationView extends StatelessWidget {
context,
'navigationView.settingsTab',
),
tooltip: '',
),
],
),

View File

@ -1,8 +1,9 @@
// ignore_for_file: use_build_context_synchronously
import 'package:dynamic_themes/dynamic_themes.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:injectable/injectable.dart';
import 'package:permission_handler/permission_handler.dart';
//import 'package:permission_handler/permission_handler.dart';
import 'package:revanced_manager/services/root_api.dart';
import 'package:revanced_manager/ui/views/home/home_view.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_view.dart';
@ -15,17 +16,27 @@ class NavigationViewModel extends IndexTrackingViewModel {
void initialize(BuildContext context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.getBool('useDarkTheme') == null) {
if (MediaQuery.of(context).platformBrightness == Brightness.light) {
await prefs.setBool('useDarkTheme', false);
DynamicTheme.of(context)!.setTheme(0);
} else {
await prefs.setBool('useDarkTheme', true);
DynamicTheme.of(context)!.setTheme(1);
}
bool isDark =
MediaQuery.of(context).platformBrightness != Brightness.light;
await prefs.setBool('useDarkTheme', isDark);
await DynamicTheme.of(context)!.setTheme(isDark ? 1 : 0);
}
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
systemNavigationBarColor:
DynamicTheme.of(context)!.theme.colorScheme.surface,
systemNavigationBarIconBrightness:
DynamicTheme.of(context)!.theme.brightness == Brightness.light
? Brightness.dark
: Brightness.light,
),
);
//if (prefs.getBool('permissionsRequested') == null) {
//await prefs.setBool('permissionsRequested', true);
RootAPI().hasRootPermissions();
Permission.requestInstallPackages.request();
Permission.ignoreBatteryOptimizations.request();
//Permission.requestInstallPackages.request();
//Permission.ignoreBatteryOptimizations.request();
//}
}
Widget getViewForIndex(int index) {

View File

@ -55,9 +55,16 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
const SizedBox(height: 12),
Expanded(
child: model.patches.isEmpty
? Center(
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.primary,
? Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: I18nText(
'patchesSelectorView.noPatchesFound',
child: Text(
'',
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
)
: ListView(

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dynamic_themes/dynamic_themes.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:logcat/logcat.dart';
import 'package:path_provider/path_provider.dart';
@ -50,10 +51,16 @@ class SettingsViewModel extends BaseViewModel {
await _managerAPI.setUseDynamicTheme(value);
int currentTheme = DynamicTheme.of(context)!.themeId;
if (currentTheme.isEven) {
DynamicTheme.of(context)!.setTheme(value ? 2 : 0);
await DynamicTheme.of(context)!.setTheme(value ? 2 : 0);
} else {
DynamicTheme.of(context)!.setTheme(value ? 3 : 1);
await DynamicTheme.of(context)!.setTheme(value ? 3 : 1);
}
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
systemNavigationBarColor:
DynamicTheme.of(context)!.theme.colorScheme.surface,
),
);
notifyListeners();
}
@ -65,10 +72,18 @@ class SettingsViewModel extends BaseViewModel {
await _managerAPI.setUseDarkTheme(value);
int currentTheme = DynamicTheme.of(context)!.themeId;
if (currentTheme < 2) {
DynamicTheme.of(context)!.setTheme(value ? 1 : 0);
await DynamicTheme.of(context)!.setTheme(value ? 1 : 0);
} else {
DynamicTheme.of(context)!.setTheme(value ? 3 : 2);
await DynamicTheme.of(context)!.setTheme(value ? 3 : 2);
}
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
systemNavigationBarColor:
DynamicTheme.of(context)!.theme.colorScheme.surface,
systemNavigationBarIconBrightness:
value ? Brightness.light : Brightness.dark,
),
);
notifyListeners();
}

View File

@ -96,8 +96,11 @@ class AppInfoView extends StatelessWidget {
color: Theme.of(context).canvasColor,
),
InkWell(
onTap: () =>
model.showUninstallAlertDialog(context, app),
onTap: () => model.showUninstallAlertDialog(
context,
app,
false,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
@ -154,6 +157,45 @@ class AppInfoView extends StatelessWidget {
],
),
),
Visibility(
visible: app.isRooted,
child: VerticalDivider(
color: Theme.of(context).canvasColor,
),
),
Visibility(
visible: app.isRooted,
child: InkWell(
onTap: () => model.showUninstallAlertDialog(
context,
app,
true,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.settings_backup_restore_outlined,
color:
Theme.of(context).colorScheme.primary,
),
const SizedBox(height: 10),
I18nText(
'appInfoView.unpatchButton',
child: Text(
'',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
],
),
),

View File

@ -19,12 +19,15 @@ class AppInfoViewModel extends BaseViewModel {
final PatcherAPI _patcherAPI = locator<PatcherAPI>();
final RootAPI _rootAPI = RootAPI();
Future<void> uninstallApp(PatchedApplication app) async {
Future<void> uninstallApp(PatchedApplication app, bool onlyUnpatch) async {
if (app.isRooted) {
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
if (hasRootPermissions) {
_rootAPI.deleteApp(app.packageName, app.apkFilePath);
_managerAPI.deletePatchedApp(app);
if (!onlyUnpatch) {
DeviceApps.uninstallApp(app.packageName);
}
}
} else {
DeviceApps.uninstallApp(app.packageName);
@ -43,32 +46,39 @@ class AppInfoViewModel extends BaseViewModel {
Future<void> showUninstallAlertDialog(
BuildContext context,
PatchedApplication app,
bool onlyUnpatch,
) async {
if (app.isRooted) {
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
if (!hasRootPermissions) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('appInfoView.rootDialogTitle'),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
content: I18nText('appInfoView.rootDialogText'),
actions: <Widget>[
CustomMaterialButton(
label: I18nText('okButton'),
onPressed: () => Navigator.of(context).pop(),
)
],
),
);
}
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
if (app.isRooted && !hasRootPermissions) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('appInfoView.rootDialogTitle'),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
content: I18nText('appInfoView.rootDialogText'),
actions: <Widget>[
CustomMaterialButton(
label: I18nText('okButton'),
onPressed: () => Navigator.of(context).pop(),
)
],
),
);
} else {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('appInfoView.uninstallDialogTitle'),
title: I18nText(
onlyUnpatch
? 'appInfoView.unpatchDialogTitle'
: 'appInfoView.uninstallDialogTitle',
),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
content: I18nText('appInfoView.uninstallDialogText'),
content: I18nText(
onlyUnpatch
? 'appInfoView.unpatchDialogText'
: 'appInfoView.uninstallDialogText',
),
actions: <Widget>[
CustomMaterialButton(
isFilled: false,
@ -78,7 +88,7 @@ class AppInfoViewModel extends BaseViewModel {
CustomMaterialButton(
label: I18nText('okButton'),
onPressed: () {
uninstallApp(app);
uninstallApp(app, onlyUnpatch);
locator<HomeViewModel>().initialize(context);
Navigator.of(context).pop();
Navigator.of(context).pop();

View File

@ -71,7 +71,7 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
future: locator<HomeViewModel>().hasManagerUpdates(),
initialData: false,
builder: (context, snapshot) => Opacity(
opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.5,
opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.25,
child: CustomMaterialButton(
isExpanded: false,
label: I18nText('latestCommitCard.updateButton'),

View File

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
class GradientProgressIndicator extends StatefulWidget {
final double? progress;
const GradientProgressIndicator({required this.progress, super.key});
@override
State<GradientProgressIndicator> createState() =>
_GradientProgressIndicatorState();
}
class _GradientProgressIndicatorState extends State<GradientProgressIndicator> {
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.centerLeft,
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.primary,
Theme.of(context).colorScheme.secondary,
],
),
),
height: 5,
width: MediaQuery.of(context).size.width * widget.progress!,
),
);
}
}

View File

@ -61,6 +61,13 @@ class _AboutWidgetState extends State<AboutWidget> {
fontWeight: FontWeight.w300,
),
),
Text(
'Build: ${snapshot.data!['flavor']}',
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w300,
),
),
Text(
'Model: ${snapshot.data!['model']}',
style: const TextStyle(

View File

@ -6,7 +6,7 @@ import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
import 'package:expandable/expandable.dart';
import 'package:timeago/timeago.dart';
class ApplicationItem extends StatelessWidget {
class ApplicationItem extends StatefulWidget {
final Uint8List icon;
final String name;
final DateTime patchDate;
@ -24,10 +24,39 @@ class ApplicationItem extends StatelessWidget {
required this.onPressed,
}) : super(key: key);
@override
State<ApplicationItem> createState() => _ApplicationItemState();
}
class _ApplicationItemState extends State<ApplicationItem>
with TickerProviderStateMixin {
late AnimationController _animationController;
@override
initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
ExpandableController expController = ExpandableController();
return ExpandablePanel(
controller: expController,
theme: const ExpandableThemeData(
inkWellBorderRadius: BorderRadius.all(Radius.circular(16)),
tapBodyToCollapse: false,
tapBodyToExpand: false,
tapHeaderToExpand: false,
hasIcon: false,
animationDuration: Duration(milliseconds: 450),
),
@ -35,33 +64,54 @@ class ApplicationItem extends StatelessWidget {
child: Row(
children: <Widget>[
SizedBox(
width: 60,
child: Image.memory(icon, height: 39, width: 39),
width: 40,
child: Image.memory(widget.icon, height: 40, width: 40),
),
const SizedBox(width: 4),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
name,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.name.length > 10
? '${widget.name.substring(0, 10)}...'
: widget.name,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
),
Text(format(patchDate)),
],
Text(format(widget.patchDate)),
],
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.only(right: 5.0),
child: RotationTransition(
turns:
Tween(begin: 0.0, end: 0.50).animate(_animationController),
child: IconButton(
onPressed: () {
expController.toggle();
_animationController.isCompleted
? _animationController.reverse()
: _animationController.forward();
},
icon: const Icon(Icons.arrow_drop_down),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
CustomMaterialButton(
label: isUpdatableApp
label: widget.isUpdatableApp
? I18nText('applicationItem.patchButton')
: I18nText('applicationItem.infoButton'),
onPressed: onPressed,
onPressed: widget.onPressed,
),
],
),
@ -70,7 +120,7 @@ class ApplicationItem extends StatelessWidget {
),
collapsed: const Text(''),
expanded: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
@ -82,7 +132,7 @@ class ApplicationItem extends StatelessWidget {
),
),
const SizedBox(height: 4),
Text('\u2022 ${changelog.join('\n\u2022 ')}'),
Text('\u2022 ${widget.changelog.join('\n\u2022 ')}'),
],
),
),

View File

@ -16,7 +16,7 @@ class CustomCard extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: isFilled
? Theme.of(context).colorScheme.secondaryContainer
? Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.40)
: Colors.transparent,
border: isFilled
? null

View File

@ -22,7 +22,7 @@ class DashboardChip extends StatelessWidget {
color: isSelected
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
fontWeight: FontWeight.w500,
),
backgroundColor: Colors.transparent,
selectedColor: Theme.of(context).colorScheme.secondaryContainer,

View File

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:device_info_plus/device_info_plus.dart';
@ -7,6 +8,7 @@ class AboutInfo {
final info = await DeviceInfoPlugin().androidInfo;
return {
'version': packageInfo.version,
'flavor': kReleaseMode ? 'release' : 'debug',
'model': info.model,
'androidVersion': info.version.release,
'arch': info.supportedAbis.first

View File

@ -4,7 +4,7 @@ homepage: https://github.com/revanced/revanced-manager
publish_to: 'none'
version: 0.0.5+5
version: 0.0.9+9
environment:
sdk: ">=2.17.5 <3.0.0"
@ -52,7 +52,7 @@ dependencies:
ref: feature/nullSafe
package_info_plus: ^1.4.3+1
path_provider: ^2.0.11
permission_handler: ^10.0.0
#permission_handler: ^10.0.0
pull_to_refresh: ^2.0.0
root: ^2.0.2
share_extend: ^2.0.0