Skip to content

Commit

Permalink
Add packagekit package search (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
Feichtmeier authored Jun 20, 2022
1 parent ea0d258 commit d891874
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 62 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ An alternative software store for the Ubuntu Desktop made with Flutter.
- [X] install from file-explorer
- [X] list installed debs/rpms
- [X] remove
- [ ] search for debs/rpms (TBD if wanted)
- [X] update
- [X] search for debs/rpms (TBD if wanted)

## Firmware updater

Expand Down
6 changes: 4 additions & 2 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@
"media": "Media",
"done": "Done",
"systemUpdates": "System updates",
"searchHint": "Search",
"searchHint": "Press enter to search",
"updateAll": "Update all",
"noUpdates": "No updates available"
"noUpdates": "No updates available",
"apps": "apps",
"filterSnaps": "Set the snap filter"
}
34 changes: 30 additions & 4 deletions lib/store_app/explore/explore_model.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import 'dart:async';

import 'package:packagekit/packagekit.dart';
import 'package:safe_change_notifier/safe_change_notifier.dart';
import 'package:snapd/snapd.dart';
import 'package:software/store_app/common/snap_section.dart';

class ExploreModel extends SafeChangeNotifier {
final SnapdClient client;
final SnapdClient _snapDClient;
final PackageKitClient _packageKitClient;

ExploreModel(
this.client,
this._snapDClient,
this._packageKitClient,
) : _searchQuery = '',
sectionNameToSnapsMap = {},
_errorMessage = '',
Expand Down Expand Up @@ -59,7 +62,7 @@ class ExploreModel extends SafeChangeNotifier {
return [];
} else {
try {
return await client.find(
return await _snapDClient.find(
query: _searchQuery,
section:
selectedSection == SnapSection.all ? null : selectedSection.title,
Expand All @@ -74,7 +77,7 @@ class ExploreModel extends SafeChangeNotifier {
Future<List<Snap>> findSnapsBySection({SnapSection? section}) async {
if (section == null) return [];
try {
return (await client.find(
return (await _snapDClient.find(
section: section == SnapSection.all
? SnapSection.featured.title
: section.title,
Expand All @@ -96,4 +99,27 @@ class ExploreModel extends SafeChangeNotifier {
sectionNameToSnapsMap.putIfAbsent(section.title, () => sectionList);
notifyListeners();
}

Future<List<PackageKitPackageId>> findPackageKitPackageIds() async {
if (searchQuery.isEmpty) return [];
final List<PackageKitPackageId> ids = [];
final transaction = await _packageKitClient.createTransaction();
final completer = Completer();
transaction.events.listen((event) {
if (event is PackageKitPackageEvent) {
final id = event.packageId;
ids.add(id);
} else if (event is PackageKitErrorCodeEvent) {
} else if (event is PackageKitFinishedEvent) {
completer.complete();
}
});
await transaction.searchNames(
[searchQuery],
filter: {},
);
await completer.future;

return ids;
}
}
53 changes: 31 additions & 22 deletions lib/store_app/explore/explore_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:packagekit/packagekit.dart';
import 'package:provider/provider.dart';
import 'package:snapd/snapd.dart';
import 'package:software/l10n/l10n.dart';
Expand All @@ -19,6 +20,7 @@ class ExplorePage extends StatelessWidget {
return ChangeNotifierProvider(
create: (_) => ExploreModel(
getService<SnapdClient>(),
getService<PackageKitClient>(),
),
child: const ExplorePage(),
);
Expand All @@ -41,31 +43,38 @@ class ExplorePage extends StatelessWidget {
: null,
flexibleSpace: !model.searchActive ? null : const SearchField(),
),
body: Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
children: [
if ((model.selectedSection == SnapSection.featured ||
model.selectedSection == SnapSection.all) &&
model.searchQuery.isEmpty)
const Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SnapBannerCarousel(
snapSection: SnapSection.featured,
height: 220,
),
body: Column(
children: [
if ((model.selectedSection == SnapSection.featured ||
model.selectedSection == SnapSection.all) &&
model.searchQuery.isEmpty)
const Padding(
padding: EdgeInsets.only(top: 20, left: 20, right: 20),
child: SnapBannerCarousel(
snapSection: SnapSection.featured,
height: 220,
),
if (model.searchQuery.isEmpty &&
model.sectionNameToSnapsMap.isNotEmpty)
Expanded(
),
if (model.searchQuery.isEmpty &&
model.sectionNameToSnapsMap.isNotEmpty)
Expanded(
child: Padding(
padding: EdgeInsets.only(
top: (model.selectedSection == SnapSection.featured ||
model.selectedSection == SnapSection.all)
? 0
: 20,
),
child: SectionBannerGrid(snapSection: model.selectedSection),
),
if (model.errorMessage.isNotEmpty)
_ErrorPage(errorMessage: model.errorMessage),
if (model.searchQuery.isNotEmpty)
const Expanded(child: SearchPage())
],
),
),
if (model.errorMessage.isNotEmpty)
_ErrorPage(errorMessage: model.errorMessage),
if (model.searchQuery.isNotEmpty)
const Expanded(
child: SearchPage(),
)
],
),
);
}
Expand Down
10 changes: 7 additions & 3 deletions lib/store_app/explore/search_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ class _SearchFieldState extends State<SearchField> {
final model = context.watch<ExploreModel>();
return TextField(
controller: _controller,
onChanged: (value) => model.searchQuery = value,
onEditingComplete: () {
model.searchQuery = _controller.text;
},
textInputAction: TextInputAction.send,
autofocus: true,
decoration: InputDecoration(
hintText:
'${context.l10n.searchHint} ${model.selectedSection.localize(context.l10n)} snaps',
suffixText:
'${context.l10n.searchHint} ${model.selectedSection.localize(context.l10n)} ${context.l10n.apps}',
suffixIcon: _SectionDropdown(
value: model.selectedSection,
onChanged: (v) => model.selectedSection = v!,
Expand Down Expand Up @@ -83,6 +86,7 @@ class _SectionDropdown extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PopupMenuButton<SnapSection>(
tooltip: context.l10n.filterSnaps,
splashRadius: 20,
onSelected: onChanged,
icon: Icon(snapSectionToIcon[value]),
Expand Down
125 changes: 96 additions & 29 deletions lib/store_app/explore/search_page.dart
Original file line number Diff line number Diff line change
@@ -1,50 +1,117 @@
import 'package:flutter/material.dart';
import 'package:packagekit/packagekit.dart';
import 'package:provider/provider.dart';
import 'package:snapd/snapd.dart';
import 'package:software/l10n/l10n.dart';
import 'package:software/snapx.dart';
import 'package:software/store_app/common/app_banner.dart';
import 'package:software/store_app/common/constants.dart';
import 'package:software/store_app/common/snap_dialog.dart';
import 'package:software/store_app/explore/explore_model.dart';
import 'package:software/store_app/my_apps/package_dialog.dart';
import 'package:yaru_icons/yaru_icons.dart';
import 'package:yaru_widgets/yaru_widgets.dart';

class SearchPage extends StatelessWidget {
const SearchPage({super.key});

@override
Widget build(BuildContext context) {
return YaruTabbedPage(
tabIcons: const [YaruIcons.package_snap, YaruIcons.package_deb],
tabTitles: [
context.l10n.snapPackages,
context.l10n.debianPackages,
],
views: const [
_SnapSearchPage(),
_PackageKitSearchPage(),
],
);
}
}

class _SnapSearchPage extends StatelessWidget {
// ignore: unused_element
const _SnapSearchPage({super.key});

@override
Widget build(BuildContext context) {
final model = context.watch<ExploreModel>();

return Padding(
padding: const EdgeInsets.only(top: 20),
child: FutureBuilder<List<Snap>>(
future: model.findSnapsByQuery(),
builder: (context, snapshot) =>
snapshot.hasData && snapshot.data!.isNotEmpty
? GridView(
controller: ScrollController(),
padding: const EdgeInsets.symmetric(horizontal: 20),
gridDelegate: kGridDelegate,
shrinkWrap: true,
children: [
for (final snap in snapshot.data!)
AppBanner(
name: snap.name,
summary: snap.summary,
url: snap.iconUrl,
onTap: () => showDialog(
context: context,
builder: (context) => SnapDialog.create(
context: context,
huskSnapName: snap.name,
),
),
)
],
)
: const SizedBox(),
),
);
}
}

class _PackageKitSearchPage extends StatelessWidget {
// ignore: unused_element
const _PackageKitSearchPage({super.key});

@override
Widget build(BuildContext context) {
final model = context.watch<ExploreModel>();
if (model.searchQuery.isEmpty) return const SizedBox();
return FutureBuilder<List<Snap>>(
future: model.findSnapsByQuery(),
builder: (context, snapshot) =>
snapshot.hasData && snapshot.data!.isNotEmpty
? GridView(
padding: const EdgeInsets.symmetric(horizontal: 20),
gridDelegate: kGridDelegate,
shrinkWrap: true,
children: [
for (final snap in snapshot.data!)
AppBanner(
name: snap.name,
summary: snap.summary,
url: snap.iconUrl,
onTap: () => showDialog(
context: context,
builder: (context) => SnapDialog.create(

return Padding(
padding: const EdgeInsets.only(top: 20),
child: FutureBuilder<List<PackageKitPackageId>>(
future: model.findPackageKitPackageIds(),
builder: (context, snapshot) =>
snapshot.hasData && snapshot.data!.isNotEmpty
? GridView(
controller: ScrollController(),
padding: const EdgeInsets.symmetric(horizontal: 20),
gridDelegate: kGridDelegate,
shrinkWrap: true,
children: [
for (final id in snapshot.data!)
AppBanner(
name: id.name,
summary: id.version,
icon: const Icon(
YaruIcons.package_deb,
size: 50,
),
onTap: () => showDialog(
context: context,
huskSnapName: snap.name,
builder: (context) => PackageDialog.create(
context,
id,
),
),
),
)
],
)
: const Center(
child: Padding(
padding: EdgeInsets.all(20.0),
child: YaruCircularProgressIndicator(),
),
),
)
],
)
: const SizedBox(),
),
);
}
}
2 changes: 1 addition & 1 deletion lib/store_app/my_apps/my_apps_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class MyAppsPage extends StatelessWidget {
tabIcons: const [
YaruIcons.package_snap,
YaruIcons.package_deb,
YaruIcons.computer
YaruIcons.synchronizing
],
tabTitles: [
context.l10n.snapPackages,
Expand Down

0 comments on commit d891874

Please sign in to comment.