mirror of
https://github.com/revanced/revanced-manager
synced 2024-05-14 13:56:57 +02:00
feat: ability to search query for suggested version (#1151)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de> Co-authored-by: Ushie <ushiekane@gmail.com>
This commit is contained in:
parent
c0516c3665
commit
9bd48c19ff
@ -1,5 +1,7 @@
|
|||||||
package app.revanced.manager.flutter
|
package app.revanced.manager.flutter
|
||||||
|
|
||||||
|
import android.app.SearchManager
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import app.revanced.manager.flutter.utils.Aapt
|
import app.revanced.manager.flutter.utils.Aapt
|
||||||
@ -41,6 +43,17 @@ class MainActivity : FlutterActivity() {
|
|||||||
|
|
||||||
val patcherChannel = "app.revanced.manager.flutter/patcher"
|
val patcherChannel = "app.revanced.manager.flutter/patcher"
|
||||||
val installerChannel = "app.revanced.manager.flutter/installer"
|
val installerChannel = "app.revanced.manager.flutter/installer"
|
||||||
|
val openBrowserChannel = "app.revanced.manager.flutter/browser"
|
||||||
|
|
||||||
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, openBrowserChannel).setMethodCallHandler { call, result ->
|
||||||
|
if (call.method == "openBrowser") {
|
||||||
|
val searchQuery = call.argument<String>("query")
|
||||||
|
openBrowser(searchQuery)
|
||||||
|
result.success(null)
|
||||||
|
} else {
|
||||||
|
result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val mainChannel =
|
val mainChannel =
|
||||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, patcherChannel)
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, patcherChannel)
|
||||||
@ -176,6 +189,15 @@ class MainActivity : FlutterActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun openBrowser(query: String?) {
|
||||||
|
val intent = Intent(Intent.ACTION_WEB_SEARCH).apply {
|
||||||
|
putExtra(SearchManager.QUERY, query)
|
||||||
|
}
|
||||||
|
if (intent.resolveActivity(packageManager) != null) {
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(InternalCoroutinesApi::class)
|
@OptIn(InternalCoroutinesApi::class)
|
||||||
private fun runPatcher(
|
private fun runPatcher(
|
||||||
result: MethodChannel.Result,
|
result: MethodChannel.Result,
|
||||||
|
@ -112,6 +112,10 @@ class _AppSelectorViewState extends State<AppSelectorView> {
|
|||||||
context,
|
context,
|
||||||
app.packageName,
|
app.packageName,
|
||||||
),
|
),
|
||||||
|
onLinkTap: () =>
|
||||||
|
model.searchSuggestedVersionOnWeb(
|
||||||
|
packageName: app.packageName,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
,
|
,
|
||||||
@ -126,6 +130,10 @@ class _AppSelectorViewState extends State<AppSelectorView> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
model.showDownloadToast();
|
model.showDownloadToast();
|
||||||
},
|
},
|
||||||
|
onLinkTap: () =>
|
||||||
|
model.searchSuggestedVersionOnWeb(
|
||||||
|
packageName: app,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
,
|
,
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:io';
|
|||||||
import 'package:device_apps/device_apps.dart';
|
import 'package:device_apps/device_apps.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
||||||
import 'package:flutter_i18n/flutter_i18n.dart';
|
import 'package:flutter_i18n/flutter_i18n.dart';
|
||||||
import 'package:revanced_manager/app/app.locator.dart';
|
import 'package:revanced_manager/app/app.locator.dart';
|
||||||
@ -70,6 +71,33 @@ class AppSelectorViewModel extends BaseViewModel {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> searchSuggestedVersionOnWeb({
|
||||||
|
required String packageName,
|
||||||
|
}) async {
|
||||||
|
final String suggestedVersion = getSuggestedVersion(packageName);
|
||||||
|
|
||||||
|
if (suggestedVersion.isNotEmpty) {
|
||||||
|
await openDefaultBrowser('$packageName apk version v$suggestedVersion');
|
||||||
|
} else {
|
||||||
|
await openDefaultBrowser('$packageName apk');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> openDefaultBrowser(String query) async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
try {
|
||||||
|
const platform = MethodChannel('app.revanced.manager.flutter/browser');
|
||||||
|
await platform.invokeMethod('openBrowser', {'query': query});
|
||||||
|
} catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw 'Platform not supported';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> selectApp(
|
Future<void> selectApp(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
ApplicationWithIcon application, [
|
ApplicationWithIcon application, [
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
// ignore_for_file: use_build_context_synchronously
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_i18n/flutter_i18n.dart';
|
import 'package:flutter_i18n/flutter_i18n.dart';
|
||||||
import 'package:injectable/injectable.dart';
|
import 'package:injectable/injectable.dart';
|
||||||
import 'package:revanced_manager/app/app.locator.dart';
|
import 'package:revanced_manager/app/app.locator.dart';
|
||||||
@ -157,6 +161,29 @@ class PatcherViewModel extends BaseViewModel {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getCurrentVersionString(BuildContext context) {
|
||||||
|
return '${FlutterI18n.translate(
|
||||||
|
context,
|
||||||
|
'appSelectorCard.currentVersion',
|
||||||
|
)}: v${selectedApp!.version}';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> searchSuggestedVersionOnWeb() async {
|
||||||
|
final String suggestedVersion =
|
||||||
|
_patcherAPI.getSuggestedVersion(selectedApp!.packageName);
|
||||||
|
|
||||||
|
if (suggestedVersion.isNotEmpty) {
|
||||||
|
await openDefaultBrowser(
|
||||||
|
'${selectedApp!.packageName} apk version v$suggestedVersion');
|
||||||
|
} else {
|
||||||
|
await openDefaultBrowser('${selectedApp!.packageName} apk');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getSuggestedVersion() {
|
||||||
|
return _patcherAPI.getSuggestedVersion(selectedApp!.packageName);
|
||||||
|
}
|
||||||
|
|
||||||
String getSuggestedVersionString(BuildContext context) {
|
String getSuggestedVersionString(BuildContext context) {
|
||||||
String suggestedVersion =
|
String suggestedVersion =
|
||||||
_patcherAPI.getSuggestedVersion(selectedApp!.packageName);
|
_patcherAPI.getSuggestedVersion(selectedApp!.packageName);
|
||||||
@ -169,14 +196,26 @@ class PatcherViewModel extends BaseViewModel {
|
|||||||
suggestedVersion = 'v$suggestedVersion';
|
suggestedVersion = 'v$suggestedVersion';
|
||||||
}
|
}
|
||||||
return '${FlutterI18n.translate(
|
return '${FlutterI18n.translate(
|
||||||
context,
|
|
||||||
'appSelectorCard.currentVersion',
|
|
||||||
)}: v${selectedApp!.version}\n${FlutterI18n.translate(
|
|
||||||
context,
|
context,
|
||||||
'appSelectorCard.suggestedVersion',
|
'appSelectorCard.suggestedVersion',
|
||||||
)}: $suggestedVersion';
|
)}: $suggestedVersion';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> openDefaultBrowser(String query) async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
try {
|
||||||
|
const platform = MethodChannel('app.revanced.manager.flutter/browser');
|
||||||
|
await platform.invokeMethod('openBrowser', {'query': query});
|
||||||
|
} catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw 'Platform not supported';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> loadLastSelectedPatches() async {
|
Future<void> loadLastSelectedPatches() async {
|
||||||
this.selectedPatches.clear();
|
this.selectedPatches.clear();
|
||||||
removedPatches.clear();
|
removedPatches.clear();
|
||||||
|
@ -13,7 +13,9 @@ class InstalledAppItem extends StatefulWidget {
|
|||||||
required this.suggestedVersion,
|
required this.suggestedVersion,
|
||||||
required this.installedVersion,
|
required this.installedVersion,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.onLinkTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final String pkgName;
|
final String pkgName;
|
||||||
final Uint8List icon;
|
final Uint8List icon;
|
||||||
@ -21,6 +23,7 @@ class InstalledAppItem extends StatefulWidget {
|
|||||||
final String suggestedVersion;
|
final String suggestedVersion;
|
||||||
final String installedVersion;
|
final String installedVersion;
|
||||||
final Function()? onTap;
|
final Function()? onTap;
|
||||||
|
final Function()? onLinkTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<InstalledAppItem> createState() => _InstalledAppItemState();
|
State<InstalledAppItem> createState() => _InstalledAppItemState();
|
||||||
@ -71,17 +74,52 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Wrap(
|
Wrap(
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
I18nText(
|
Material(
|
||||||
'suggested',
|
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
translationParams: {
|
borderRadius:
|
||||||
'version': widget.suggestedVersion.isEmpty
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
? FlutterI18n.translate(
|
child: InkWell(
|
||||||
context,
|
onTap: widget.onLinkTap,
|
||||||
'appSelectorCard.allVersions',
|
borderRadius:
|
||||||
)
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
: 'v${widget.suggestedVersion}',
|
child: Container(
|
||||||
},
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
I18nText(
|
||||||
|
'suggested',
|
||||||
|
translationParams: {
|
||||||
|
'version': widget.suggestedVersion.isEmpty
|
||||||
|
? FlutterI18n.translate(
|
||||||
|
context,
|
||||||
|
'appSelectorCard.allVersions',
|
||||||
|
)
|
||||||
|
: 'v${widget.suggestedVersion}',
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Icon(
|
||||||
|
Icons.search,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
|
@ -9,11 +9,14 @@ class NotInstalledAppItem extends StatefulWidget {
|
|||||||
required this.patchesCount,
|
required this.patchesCount,
|
||||||
required this.suggestedVersion,
|
required this.suggestedVersion,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.onLinkTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final int patchesCount;
|
final int patchesCount;
|
||||||
final String suggestedVersion;
|
final String suggestedVersion;
|
||||||
final Function()? onTap;
|
final Function()? onTap;
|
||||||
|
final Function()? onLinkTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<NotInstalledAppItem> createState() => _NotInstalledAppItem();
|
State<NotInstalledAppItem> createState() => _NotInstalledAppItem();
|
||||||
@ -65,17 +68,52 @@ class _NotInstalledAppItem extends State<NotInstalledAppItem> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Wrap(
|
Wrap(
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
I18nText(
|
Material(
|
||||||
'suggested',
|
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
translationParams: {
|
borderRadius:
|
||||||
'version': widget.suggestedVersion.isEmpty
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
? FlutterI18n.translate(
|
child: InkWell(
|
||||||
context,
|
onTap: widget.onLinkTap,
|
||||||
'appSelectorCard.allVersions',
|
borderRadius:
|
||||||
)
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
: 'v${widget.suggestedVersion}',
|
child: Container(
|
||||||
},
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
I18nText(
|
||||||
|
'suggested',
|
||||||
|
translationParams: {
|
||||||
|
'version': widget.suggestedVersion.isEmpty
|
||||||
|
? FlutterI18n.translate(
|
||||||
|
context,
|
||||||
|
'appSelectorCard.allVersions',
|
||||||
|
)
|
||||||
|
: 'v${widget.suggestedVersion}',
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Icon(
|
||||||
|
Icons.search,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
|
@ -10,6 +10,7 @@ class AppSelectorCard extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Function() onPressed;
|
final Function() onPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -61,11 +62,52 @@ class AppSelectorCard extends StatelessWidget {
|
|||||||
Container()
|
Container()
|
||||||
else
|
else
|
||||||
Column(
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
locator<PatcherViewModel>()
|
locator<PatcherViewModel>().getCurrentVersionString(context),
|
||||||
.getSuggestedVersionString(context),
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Material(
|
||||||
|
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
locator<PatcherViewModel>()
|
||||||
|
.searchSuggestedVersionOnWeb();
|
||||||
|
},
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
locator<PatcherViewModel>()
|
||||||
|
.getSuggestedVersionString(context),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Icon(
|
||||||
|
Icons.search,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user