mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-05-29 12:50:12 +02:00
perf: Reduce amount of network requests
This commit is contained in:
parent
8661d72e45
commit
8ce266bc94
@ -56,9 +56,7 @@
|
|||||||
"updatesDisabled": "Updating a patched app is currently disabled. Repatch the app again."
|
"updatesDisabled": "Updating a patched app is currently disabled. Repatch the app again."
|
||||||
},
|
},
|
||||||
"applicationItem": {
|
"applicationItem": {
|
||||||
"patchButton": "Patch",
|
"infoButton": "Info"
|
||||||
"infoButton": "Info",
|
|
||||||
"changelogLabel": "Changelog"
|
|
||||||
},
|
},
|
||||||
"latestCommitCard": {
|
"latestCommitCard": {
|
||||||
"loadingLabel": "Loading...",
|
"loadingLabel": "Loading...",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:revanced_manager/utils/string.dart';
|
|
||||||
|
|
||||||
part 'patch.g.dart';
|
part 'patch.g.dart';
|
||||||
|
|
||||||
|
@ -16,9 +16,7 @@ class PatchedApplication {
|
|||||||
required this.patchDate,
|
required this.patchDate,
|
||||||
this.isRooted = false,
|
this.isRooted = false,
|
||||||
this.isFromStorage = false,
|
this.isFromStorage = false,
|
||||||
this.hasUpdates = false,
|
|
||||||
this.appliedPatches = const [],
|
this.appliedPatches = const [],
|
||||||
this.changelog = const [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory PatchedApplication.fromJson(Map<String, dynamic> json) =>
|
factory PatchedApplication.fromJson(Map<String, dynamic> json) =>
|
||||||
@ -36,9 +34,7 @@ class PatchedApplication {
|
|||||||
DateTime patchDate;
|
DateTime patchDate;
|
||||||
bool isRooted;
|
bool isRooted;
|
||||||
bool isFromStorage;
|
bool isFromStorage;
|
||||||
bool hasUpdates;
|
|
||||||
List<String> appliedPatches;
|
List<String> appliedPatches;
|
||||||
List<String> changelog;
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$PatchedApplicationToJson(this);
|
Map<String, dynamic> toJson() => _$PatchedApplicationToJson(this);
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ class GithubAPI {
|
|||||||
Future<void> clearAllCache() async {
|
Future<void> clearAllCache() async {
|
||||||
try {
|
try {
|
||||||
await _cacheOptions.store!.clean();
|
await _cacheOptions.store!.clean();
|
||||||
|
await DefaultCacheManager().emptyCache();
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print(e);
|
print(e);
|
||||||
@ -142,38 +143,6 @@ class GithubAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<String>> getCommits(
|
|
||||||
String packageName,
|
|
||||||
String repoName,
|
|
||||||
DateTime since,
|
|
||||||
) async {
|
|
||||||
final String path =
|
|
||||||
'src/main/kotlin/app/revanced/patches/${repoAppPath[packageName]}';
|
|
||||||
try {
|
|
||||||
final response = await _dio.get(
|
|
||||||
'/repos/$repoName/commits',
|
|
||||||
queryParameters: {
|
|
||||||
'path': path,
|
|
||||||
'since': since.toIso8601String(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
final List<dynamic> commits = response.data;
|
|
||||||
return commits
|
|
||||||
.map(
|
|
||||||
(commit) => commit['commit']['message'].split('\n')[0] +
|
|
||||||
' - ' +
|
|
||||||
commit['commit']['author']['name'] +
|
|
||||||
'\n' as String,
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
} on Exception catch (e) {
|
|
||||||
if (kDebugMode) {
|
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<File?> getLatestReleaseFile(
|
Future<File?> getLatestReleaseFile(
|
||||||
String extension,
|
String extension,
|
||||||
String repoName,
|
String repoName,
|
||||||
@ -237,30 +206,4 @@ class GithubAPI {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Patch>> getPatches(
|
|
||||||
String repoName,
|
|
||||||
String version,
|
|
||||||
String url,
|
|
||||||
) async {
|
|
||||||
List<Patch> patches = [];
|
|
||||||
try {
|
|
||||||
final File? f = await getPatchesReleaseFile(
|
|
||||||
'.json',
|
|
||||||
repoName,
|
|
||||||
version,
|
|
||||||
url,
|
|
||||||
);
|
|
||||||
if (f != null) {
|
|
||||||
final List<dynamic> list = jsonDecode(f.readAsStringSync());
|
|
||||||
patches = list.map((patch) => Patch.fromJson(patch)).toList();
|
|
||||||
}
|
|
||||||
} on Exception catch (e) {
|
|
||||||
if (kDebugMode) {
|
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return patches;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -616,39 +616,6 @@ class ManagerAPI {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> reAssessSavedApps() async {
|
|
||||||
final List<PatchedApplication> patchedApps = getPatchedApps();
|
|
||||||
final List<PatchedApplication> unsavedApps =
|
|
||||||
await getUnsavedApps(patchedApps);
|
|
||||||
patchedApps.addAll(unsavedApps);
|
|
||||||
final List<PatchedApplication> toRemove =
|
|
||||||
await getAppsToRemove(patchedApps);
|
|
||||||
patchedApps.removeWhere((a) => toRemove.contains(a));
|
|
||||||
for (final PatchedApplication app in patchedApps) {
|
|
||||||
app.hasUpdates =
|
|
||||||
await hasAppUpdates(app.originalPackageName, app.patchDate);
|
|
||||||
app.changelog =
|
|
||||||
await getAppChangelog(app.originalPackageName, app.patchDate);
|
|
||||||
if (!app.hasUpdates) {
|
|
||||||
final String? currentInstalledVersion =
|
|
||||||
(await DeviceApps.getApp(app.packageName))?.versionName;
|
|
||||||
if (currentInstalledVersion != null) {
|
|
||||||
final String currentSavedVersion = app.version;
|
|
||||||
final int currentInstalledVersionInt = int.parse(
|
|
||||||
currentInstalledVersion.replaceAll(RegExp('[^0-9]'), ''),
|
|
||||||
);
|
|
||||||
final int currentSavedVersionInt = int.parse(
|
|
||||||
currentSavedVersion.replaceAll(RegExp('[^0-9]'), ''),
|
|
||||||
);
|
|
||||||
if (currentInstalledVersionInt > currentSavedVersionInt) {
|
|
||||||
app.hasUpdates = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await setPatchedApps(patchedApps);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> isAppUninstalled(PatchedApplication app) async {
|
Future<bool> isAppUninstalled(PatchedApplication app) async {
|
||||||
bool existsRoot = false;
|
bool existsRoot = false;
|
||||||
final bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
|
final bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
|
||||||
@ -662,37 +629,6 @@ class ManagerAPI {
|
|||||||
return !existsNonRoot;
|
return !existsNonRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> hasAppUpdates(
|
|
||||||
String packageName,
|
|
||||||
DateTime patchDate,
|
|
||||||
) async {
|
|
||||||
final List<String> commits = await _githubAPI.getCommits(
|
|
||||||
packageName,
|
|
||||||
getPatchesRepo(),
|
|
||||||
patchDate,
|
|
||||||
);
|
|
||||||
return commits.isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<String>> getAppChangelog(
|
|
||||||
String packageName,
|
|
||||||
DateTime patchDate,
|
|
||||||
) async {
|
|
||||||
List<String> newCommits = await _githubAPI.getCommits(
|
|
||||||
packageName,
|
|
||||||
getPatchesRepo(),
|
|
||||||
patchDate,
|
|
||||||
);
|
|
||||||
if (newCommits.isEmpty) {
|
|
||||||
newCommits = await _githubAPI.getCommits(
|
|
||||||
packageName,
|
|
||||||
getPatchesRepo(),
|
|
||||||
patchDate,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return newCommits;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> isSplitApk(PatchedApplication patchedApp) async {
|
Future<bool> isSplitApk(PatchedApplication patchedApp) async {
|
||||||
Application? app;
|
Application? app;
|
||||||
if (patchedApp.isFromStorage) {
|
if (patchedApp.isFromStorage) {
|
||||||
@ -760,6 +696,8 @@ class ManagerAPI {
|
|||||||
|
|
||||||
Future<void> resetLastSelectedPatches() async {
|
Future<void> resetLastSelectedPatches() async {
|
||||||
final File selectedPatchesFile = File(storedPatchesFile);
|
final File selectedPatchesFile = File(storedPatchesFile);
|
||||||
selectedPatchesFile.deleteSync();
|
if (selectedPatchesFile.existsSync()) {
|
||||||
|
selectedPatchesFile.deleteSync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,15 @@ import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
import 'package:injectable/injectable.dart';
|
import 'package:injectable/injectable.dart';
|
||||||
|
import 'package:synchronized/synchronized.dart';
|
||||||
import 'package:timeago/timeago.dart';
|
import 'package:timeago/timeago.dart';
|
||||||
|
|
||||||
@lazySingleton
|
@lazySingleton
|
||||||
class RevancedAPI {
|
class RevancedAPI {
|
||||||
late Dio _dio = Dio();
|
late Dio _dio = Dio();
|
||||||
|
|
||||||
|
final Lock getToolsLock = Lock();
|
||||||
|
|
||||||
final _cacheOptions = CacheOptions(
|
final _cacheOptions = CacheOptions(
|
||||||
store: MemCacheStore(),
|
store: MemCacheStore(),
|
||||||
maxStale: const Duration(days: 1),
|
maxStale: const Duration(days: 1),
|
||||||
@ -38,6 +41,7 @@ class RevancedAPI {
|
|||||||
Future<void> clearAllCache() async {
|
Future<void> clearAllCache() async {
|
||||||
try {
|
try {
|
||||||
await _cacheOptions.store!.clean();
|
await _cacheOptions.store!.clean();
|
||||||
|
await DefaultCacheManager().emptyCache();
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print(e);
|
print(e);
|
||||||
@ -66,21 +70,23 @@ class RevancedAPI {
|
|||||||
Future<Map<String, dynamic>?> _getLatestRelease(
|
Future<Map<String, dynamic>?> _getLatestRelease(
|
||||||
String extension,
|
String extension,
|
||||||
String repoName,
|
String repoName,
|
||||||
) async {
|
) {
|
||||||
try {
|
return getToolsLock.synchronized(() async {
|
||||||
final response = await _dio.get('/tools');
|
try {
|
||||||
final List<dynamic> tools = response.data['tools'];
|
final response = await _dio.get('/tools');
|
||||||
return tools.firstWhereOrNull(
|
final List<dynamic> tools = response.data['tools'];
|
||||||
(t) =>
|
return tools.firstWhereOrNull(
|
||||||
t['repository'] == repoName &&
|
(t) =>
|
||||||
(t['name'] as String).endsWith(extension),
|
t['repository'] == repoName &&
|
||||||
);
|
(t['name'] as String).endsWith(extension),
|
||||||
} on Exception catch (e) {
|
);
|
||||||
if (kDebugMode) {
|
} on Exception catch (e) {
|
||||||
print(e);
|
if (kDebugMode) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getLatestReleaseVersion(
|
Future<String?> getLatestReleaseVersion(
|
||||||
|
@ -37,15 +37,15 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
DateTime? _lastUpdate;
|
DateTime? _lastUpdate;
|
||||||
bool showUpdatableApps = false;
|
bool showUpdatableApps = false;
|
||||||
List<PatchedApplication> patchedInstalledApps = [];
|
List<PatchedApplication> patchedInstalledApps = [];
|
||||||
List<PatchedApplication> patchedUpdatableApps = [];
|
|
||||||
String? _latestManagerVersion = '';
|
String? _latestManagerVersion = '';
|
||||||
File? downloadedApk;
|
File? downloadedApk;
|
||||||
|
|
||||||
Future<void> initialize(BuildContext context) async {
|
Future<void> initialize(BuildContext context) async {
|
||||||
_latestManagerVersion = await _managerAPI.getLatestManagerVersion();
|
|
||||||
if (!_managerAPI.getPatchesConsent()) {
|
if (!_managerAPI.getPatchesConsent()) {
|
||||||
await showPatchesConsent(context);
|
await showPatchesConsent(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_latestManagerVersion = await _managerAPI.getLatestManagerVersion();
|
||||||
await _patcherAPI.initialize();
|
await _patcherAPI.initialize();
|
||||||
await flutterLocalNotificationsPlugin.initialize(
|
await flutterLocalNotificationsPlugin.initialize(
|
||||||
const InitializationSettings(
|
const InitializationSettings(
|
||||||
@ -83,7 +83,6 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_getPatchedApps();
|
_getPatchedApps();
|
||||||
_managerAPI.reAssessSavedApps().then((_) => _getPatchedApps());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void navigateToAppInfo(PatchedApplication app) {
|
void navigateToAppInfo(PatchedApplication app) {
|
||||||
@ -108,10 +107,6 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
|
|
||||||
void _getPatchedApps() {
|
void _getPatchedApps() {
|
||||||
patchedInstalledApps = _managerAPI.getPatchedApps().toList();
|
patchedInstalledApps = _managerAPI.getPatchedApps().toList();
|
||||||
patchedUpdatableApps = _managerAPI
|
|
||||||
.getPatchedApps()
|
|
||||||
.where((app) => app.hasUpdates == true)
|
|
||||||
.toList();
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,9 +39,9 @@ class NavigationViewModel extends IndexTrackingViewModel {
|
|||||||
|
|
||||||
// Force disable Material You on Android 11 and below
|
// Force disable Material You on Android 11 and below
|
||||||
if (dynamicTheme.themeId.isOdd) {
|
if (dynamicTheme.themeId.isOdd) {
|
||||||
const int ANDROID_12_SDK_VERSION = 31;
|
const int android12SdkVersion = 31;
|
||||||
final AndroidDeviceInfo info = await DeviceInfoPlugin().androidInfo;
|
final AndroidDeviceInfo info = await DeviceInfoPlugin().androidInfo;
|
||||||
if (info.version.sdkInt < ANDROID_12_SDK_VERSION) {
|
if (info.version.sdkInt < android12SdkVersion) {
|
||||||
await prefs.setInt('themeMode', 0);
|
await prefs.setInt('themeMode', 0);
|
||||||
await prefs.setBool('useDynamicTheme', false);
|
await prefs.setBool('useDynamicTheme', false);
|
||||||
await dynamicTheme.setTheme(0);
|
await dynamicTheme.setTheme(0);
|
||||||
|
@ -79,8 +79,6 @@ class InstalledAppsCard extends StatelessWidget {
|
|||||||
icon: app.icon,
|
icon: app.icon,
|
||||||
name: app.name,
|
name: app.name,
|
||||||
patchDate: app.patchDate,
|
patchDate: app.patchDate,
|
||||||
changelog: app.changelog,
|
|
||||||
isUpdatableApp: false,
|
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
locator<HomeViewModel>().navigateToAppInfo(app),
|
locator<HomeViewModel>().navigateToAppInfo(app),
|
||||||
),
|
),
|
||||||
|
@ -5,8 +5,8 @@ import 'package:flutter_i18n/widgets/I18nText.dart';
|
|||||||
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_api_url.dart';
|
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_api_url.dart';
|
||||||
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_sources.dart';
|
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_sources.dart';
|
||||||
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart';
|
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_patches.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_patches.dart';
|
||||||
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_experimental_patches.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_experimental_patches.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_experimental_universal_patches.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_experimental_universal_patches.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
|
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:expandable/expandable.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_i18n/flutter_i18n.dart';
|
import 'package:flutter_i18n/flutter_i18n.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
|
||||||
@ -13,151 +12,84 @@ class ApplicationItem extends StatefulWidget {
|
|||||||
required this.icon,
|
required this.icon,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.patchDate,
|
required this.patchDate,
|
||||||
required this.changelog,
|
|
||||||
required this.isUpdatableApp,
|
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
final Uint8List icon;
|
final Uint8List icon;
|
||||||
final String name;
|
final String name;
|
||||||
final DateTime patchDate;
|
final DateTime patchDate;
|
||||||
final List<String> changelog;
|
|
||||||
final bool isUpdatableApp;
|
|
||||||
final Function() onPressed;
|
final Function() onPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ApplicationItem> createState() => _ApplicationItemState();
|
State<ApplicationItem> createState() => _ApplicationItemState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ApplicationItemState extends State<ApplicationItem>
|
class _ApplicationItemState extends State<ApplicationItem> {
|
||||||
with TickerProviderStateMixin {
|
|
||||||
late AnimationController _animationController;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_animationController = AnimationController(
|
|
||||||
vsync: this,
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_animationController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ExpandableController expController = ExpandableController();
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 16.0),
|
margin: const EdgeInsets.only(bottom: 16.0),
|
||||||
child: CustomCard(
|
child: CustomCard(
|
||||||
onTap: () {
|
child: Row(
|
||||||
expController.toggle();
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
_animationController.isCompleted
|
children: [
|
||||||
? _animationController.reverse()
|
Flexible(
|
||||||
: _animationController.forward();
|
child: Row(
|
||||||
},
|
|
||||||
child: ExpandablePanel(
|
|
||||||
controller: expController,
|
|
||||||
theme: const ExpandableThemeData(
|
|
||||||
inkWellBorderRadius: BorderRadius.all(Radius.circular(16)),
|
|
||||||
tapBodyToCollapse: false,
|
|
||||||
tapBodyToExpand: false,
|
|
||||||
tapHeaderToExpand: false,
|
|
||||||
hasIcon: false,
|
|
||||||
animationDuration: Duration(milliseconds: 450),
|
|
||||||
),
|
|
||||||
header: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: 40,
|
|
||||||
child: Image.memory(widget.icon, height: 40, width: 40),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 19),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
widget.name,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
format(widget.patchDate),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
children: [
|
||||||
RotationTransition(
|
SizedBox(
|
||||||
turns: Tween(begin: 0.0, end: 0.50)
|
width: 40,
|
||||||
.animate(_animationController),
|
child: Image.memory(widget.icon, height: 40, width: 40),
|
||||||
child: const Padding(
|
|
||||||
padding: EdgeInsets.all(8.0),
|
|
||||||
child: Icon(Icons.arrow_drop_down),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 19),
|
||||||
Column(
|
Expanded(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
CustomMaterialButton(
|
Text(
|
||||||
label: widget.isUpdatableApp
|
widget.name,
|
||||||
? I18nText('applicationItem.patchButton')
|
maxLines: 1,
|
||||||
: I18nText('applicationItem.infoButton'),
|
overflow: TextOverflow.ellipsis,
|
||||||
onPressed: widget.onPressed,
|
style: const TextStyle(
|
||||||
),
|
fontSize: 16,
|
||||||
],
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
format(widget.patchDate),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
collapsed: const SizedBox(),
|
|
||||||
expanded: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 16.0,
|
|
||||||
left: 4.0,
|
|
||||||
right: 4.0,
|
|
||||||
bottom: 4.0,
|
|
||||||
),
|
),
|
||||||
child: Column(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: <Widget>[
|
const SizedBox(width: 8),
|
||||||
I18nText(
|
Column(
|
||||||
'applicationItem.changelogLabel',
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
child: const Text(
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
'',
|
children: <Widget>[
|
||||||
style: TextStyle(fontWeight: FontWeight.w700),
|
CustomMaterialButton(
|
||||||
),
|
label: I18nText('applicationItem.infoButton'),
|
||||||
|
onPressed: widget.onPressed,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
|
||||||
Text('\u2022 ${widget.changelog.join('\n\u2022 ')}'),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -75,6 +75,7 @@ dependencies:
|
|||||||
flutter_markdown: ^0.6.14
|
flutter_markdown: ^0.6.14
|
||||||
dio_cache_interceptor: ^3.4.0
|
dio_cache_interceptor: ^3.4.0
|
||||||
install_plugin: ^2.1.0
|
install_plugin: ^2.1.0
|
||||||
|
synchronized: ^3.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
json_serializable: ^6.6.1
|
json_serializable: ^6.6.1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user