add version field, installable app caching

This commit is contained in:
Andrew 2022-09-13 11:45:10 +07:00
parent 4833b5c18c
commit 2141e144be
7 changed files with 79 additions and 9 deletions

View file

@ -9,17 +9,47 @@ part 'scoop_search_event.dart';
part 'scoop_search_state.dart'; part 'scoop_search_state.dart';
class ScoopSearchBloc extends Bloc<ScoopSearchEvent, ScoopSearchState> { class ScoopSearchBloc extends Bloc<ScoopSearchEvent, ScoopSearchState> {
final Map<String, List<ScoopAppModel>> _cachedApps = {};
ScoopSearchBloc() : super(ScoopSearchInitial()) { ScoopSearchBloc() : super(ScoopSearchInitial()) {
on<ScoopSearchReload>(
(event, emit) async {
_cachedApps.clear();
try {
Map<String, List<ScoopAppModel>> data = await getAllInstallableApps();
_cachedApps.addAll(data);
emit(ScoopSearchLoaded(data));
} catch (e) {
emit(const ScoopSearchLoaded({}));
}
},
transformer: droppable(),
);
on<ScoopSearchQueryChanged>( on<ScoopSearchQueryChanged>(
(event, emit) async { (event, emit) async {
emit(ScoopSearchLoading()); emit(ScoopSearchLoading());
try { try {
Map<String, List<ScoopAppModel>> data = {}; Map<String, List<ScoopAppModel>> data = {};
if (event.query.isEmpty) { if (_cachedApps.isEmpty) {
data = await getAllInstallableApps(); _cachedApps.addAll(await getAllInstallableApps());
}
if (event.query.isNotEmpty) {
for (final bucket in _cachedApps.keys) {
data[bucket] = _cachedApps[bucket]
?.where((app) =>
app.name
.toLowerCase()
.contains(event.query.toLowerCase()) ||
app.description
.toLowerCase()
.contains(event.query.toLowerCase()))
.toList() ??
[];
}
} else { } else {
data = await searchInstallableApps(event.query); data.addAll(_cachedApps);
} }
emit(ScoopSearchLoaded(data)); emit(ScoopSearchLoaded(data));
} catch (e) { } catch (e) {

View file

@ -7,6 +7,8 @@ abstract class ScoopSearchEvent extends Equatable {
List<Object> get props => []; List<Object> get props => [];
} }
class ScoopSearchReload extends ScoopSearchEvent {}
class ScoopSearchQueryChanged extends ScoopSearchEvent { class ScoopSearchQueryChanged extends ScoopSearchEvent {
final String query; final String query;

View file

@ -31,8 +31,7 @@ void main() async {
create: (context) => ScoopListBloc()..add(ScoopLocate()), create: (context) => ScoopListBloc()..add(ScoopLocate()),
), ),
BlocProvider( BlocProvider(
create: (context) => create: (context) => ScoopSearchBloc()..add(ScoopSearchReload()),
ScoopSearchBloc()..add(const ScoopSearchQueryChanged("")),
), ),
], ],
child: const LadleApp(), child: const LadleApp(),

View file

@ -4,6 +4,8 @@ class ScoopAppModel extends Equatable {
final String name; final String name;
final String description; final String description;
final String bucket; final String bucket;
final String homepage;
final String version;
final DateTime updatedAt; final DateTime updatedAt;
const ScoopAppModel({ const ScoopAppModel({
@ -11,8 +13,11 @@ class ScoopAppModel extends Equatable {
required this.description, required this.description,
required this.bucket, required this.bucket,
required this.updatedAt, required this.updatedAt,
required this.homepage,
required this.version,
}); });
@override @override
List<Object?> get props => [name, description, bucket, updatedAt]; List<Object?> get props =>
[name, description, bucket, homepage, version, updatedAt];
} }

View file

@ -9,6 +9,7 @@ import 'package:ladle/models/scoop_app_model.dart';
import 'package:ladle/utils/scoop_utils.dart'; import 'package:ladle/utils/scoop_utils.dart';
import 'package:ladle/utils/set_extension.dart'; import 'package:ladle/utils/set_extension.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:url_launcher/url_launcher_string.dart';
import '../bloc/scoop_list_bloc.dart'; import '../bloc/scoop_list_bloc.dart';
@ -218,7 +219,14 @@ class _AppSearchFragmentState extends State<AppSearchFragment> {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(appModel.name).fontSize(32).bold().paddingDirectional(bottom: 16), Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(appModel.name).fontSize(32).bold(),
Text(appModel.version).padding(all: 4)
],
).paddingDirectional(bottom: 16),
Row( Row(
children: [ children: [
Chip( Chip(
@ -251,6 +259,15 @@ class _AppSearchFragmentState extends State<AppSearchFragment> {
}, },
), ),
], ],
).paddingDirectional(bottom: 8),
Row(
children: [
OutlinedButton(
child: const Text("Homepage"),
onPressed: () {
launchUrlString(appModel.homepage);
}).padding(right: 8),
],
).paddingDirectional(bottom: 16), ).paddingDirectional(bottom: 16),
Text( Text(
appModel.description, appModel.description,

View file

@ -1,6 +1,7 @@
import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ladle/bloc/scoop_search_bloc.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -92,8 +93,10 @@ class _HomePageState extends State<HomePage> {
), ),
onPressed: state is ScoopListLoading onPressed: state is ScoopListLoading
? null ? null
: () => : () {
context.read<ScoopListBloc>().add(ScoopUpdateRequested()), context.read<ScoopListBloc>().add(ScoopUpdateRequested());
context.read<ScoopSearchBloc>().add(ScoopSearchReload());
},
), ),
WindowButton( WindowButton(
iconBuilder: (buttonContext) => const Icon( iconBuilder: (buttonContext) => const Icon(

View file

@ -50,6 +50,8 @@ Future<Map<String, List<ScoopAppModel>>> searchInstallableApps(
String appName = String appName =
file.path.split("\\").last.replaceAll(RegExp(r"\.(json|ya?ml)"), ""); file.path.split("\\").last.replaceAll(RegExp(r"\.(json|ya?ml)"), "");
String appDescription = data["description"] ?? "No description"; String appDescription = data["description"] ?? "No description";
String appHomepage = data["homepage"] ?? "";
String appVersion = data["version"] ?? "0.0.0";
DateTime appUpdatedAt = await file.lastModified(); DateTime appUpdatedAt = await file.lastModified();
if (appName.toLowerCase().contains(query.toLowerCase()) || if (appName.toLowerCase().contains(query.toLowerCase()) ||
@ -58,6 +60,8 @@ Future<Map<String, List<ScoopAppModel>>> searchInstallableApps(
name: appName, name: appName,
description: appDescription, description: appDescription,
bucket: bucket, bucket: bucket,
homepage: appHomepage,
version: appVersion,
updatedAt: appUpdatedAt, updatedAt: appUpdatedAt,
)); ));
} }
@ -91,12 +95,16 @@ Future<Map<String, List<ScoopAppModel>>> getAllInstallableApps() async {
String appName = String appName =
file.path.split("\\").last.replaceAll(RegExp(r"\.(json|ya?ml)"), ""); file.path.split("\\").last.replaceAll(RegExp(r"\.(json|ya?ml)"), "");
String appDescription = data["description"] ?? "No description"; String appDescription = data["description"] ?? "No description";
String appHomepage = data["homepage"] ?? "";
String appVersion = data["version"] ?? "0.0.0";
DateTime appUpdatedAt = await file.lastModified(); DateTime appUpdatedAt = await file.lastModified();
apps.add(ScoopAppModel( apps.add(ScoopAppModel(
name: appName, name: appName,
description: appDescription, description: appDescription,
bucket: bucket, bucket: bucket,
homepage: appHomepage,
version: appVersion,
updatedAt: appUpdatedAt, updatedAt: appUpdatedAt,
)); ));
} }
@ -117,12 +125,16 @@ Future<List<ScoopAppModel>> getInstalledScoopApps() async {
String appName = element.path.split("\\").last; String appName = element.path.split("\\").last;
String appDescription = "No description"; String appDescription = "No description";
String appBucket = "UNKNOWN"; String appBucket = "UNKNOWN";
String appHomepage = "";
String appVersion = "0.0.0";
DateTime appUpdatedAt = DateTime.fromMicrosecondsSinceEpoch(0); DateTime appUpdatedAt = DateTime.fromMicrosecondsSinceEpoch(0);
final manifestFile = File("${element.path}/current/manifest.json"); final manifestFile = File("${element.path}/current/manifest.json");
if (await manifestFile.exists()) { if (await manifestFile.exists()) {
final manifestData = jsonDecode(await manifestFile.readAsString()); final manifestData = jsonDecode(await manifestFile.readAsString());
appDescription = manifestData["description"] ?? appDescription; appDescription = manifestData["description"] ?? appDescription;
appHomepage = manifestData["homepage"] ?? appHomepage;
appVersion = manifestData["version"] ?? appVersion;
appUpdatedAt = await manifestFile.lastModified(); appUpdatedAt = await manifestFile.lastModified();
} }
@ -136,6 +148,8 @@ Future<List<ScoopAppModel>> getInstalledScoopApps() async {
name: appName, name: appName,
description: appDescription, description: appDescription,
bucket: appBucket, bucket: appBucket,
homepage: appHomepage,
version: appVersion,
updatedAt: appUpdatedAt, updatedAt: appUpdatedAt,
)); ));
} }