Skip to content

Commit

Permalink
Implement package listing
Browse files Browse the repository at this point in the history
  • Loading branch information
Fernthedev committed Jul 19, 2024
1 parent 1b34ead commit 97ca437
Show file tree
Hide file tree
Showing 8 changed files with 330 additions and 104 deletions.
38 changes: 22 additions & 16 deletions lib/pages/main/devices.dart
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import 'package:desktop_adb_file_browser/pages/adb_check.dart';
import 'package:desktop_adb_file_browser/riverpod/selected_device.dart';
import 'package:desktop_adb_file_browser/routes.dart';
import 'package:desktop_adb_file_browser/utils/adb.dart';
import 'package:desktop_adb_file_browser/widgets/device_card.dart';
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:routemaster/routemaster.dart';

class DevicesPage extends StatefulWidget {
const DevicesPage(
{super.key, this.serialSelector, required this.canNavigate});
class DevicesPage extends ConsumerStatefulWidget {
const DevicesPage({super.key, required this.canNavigate});

final ValueNotifier<String?>? serialSelector;
final bool canNavigate;

@override
State<DevicesPage> createState() => _DevicesPageState();
ConsumerState<DevicesPage> createState() => _DevicesPageState();
}

class _DevicesPageState extends State<DevicesPage> {
class _DevicesPageState extends ConsumerState<DevicesPage> {
Future<List<Device>>? _deviceListFuture;

@override
Expand Down Expand Up @@ -105,6 +105,8 @@ class _DevicesPageState extends State<DevicesPage> {
}

Widget _deviceListView(Iterable<Device> devices) {
final deviceSelector = ref.watch(selectedDeviceProvider);

if (devices.isEmpty) {
return Center(
child: Text("No devices found",
Expand All @@ -113,19 +115,23 @@ class _DevicesPageState extends State<DevicesPage> {
}

return ListView(
padding: const EdgeInsets.all(4.0),
children: devices
.map((e) => DeviceCard(
device: e,
onTap: _onDeviceSelect,
showLogButton: widget.canNavigate,
selected: widget.serialSelector?.value == e.serialName,
))
.toList(growable: false));
padding: const EdgeInsets.all(4.0),
children: devices
.map(
(e) => DeviceCard(
device: e,
onTap: _onDeviceSelect,
showLogButton: widget.canNavigate,
selected: deviceSelector?.serialName == e.serialName,
),
)
.toList(growable: false),
);
}

void _onDeviceSelect(Device device) {
widget.serialSelector?.value = device.serialName;
final deviceSelector = ref.read(selectedDeviceProvider.notifier);
deviceSelector.selectDevice(device);

if (widget.canNavigate) {
Routes.browse(context, device.serialName);
Expand Down
107 changes: 50 additions & 57 deletions lib/pages/main/package_list.dart
Original file line number Diff line number Diff line change
@@ -1,81 +1,74 @@
import 'package:desktop_adb_file_browser/riverpod/package_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

// part 'package_list.g.dart';
part 'package_list.freezed.dart';

@freezed
class PackageMetadata with _$PackageMetadata {
const factory PackageMetadata({
required String packageName,
required String packageId,
required String version,
required String groupId,
}) = _PackageMetadata;
}

class PackageList extends StatefulWidget {
class PackageList extends ConsumerStatefulWidget {
const PackageList({super.key, required this.serial});

final String serial;

@override
State<PackageList> createState() => _PackageListState();
ConsumerState<PackageList> createState() => _PackageListState();
}

class _PackageListState extends State<PackageList> {
final packageList = [
const PackageMetadata(
groupId: "flamingo",
packageId: "wen",
packageName: "hoodie",
version: "1.0.0"),
const PackageMetadata(
groupId: "flamingo",
packageId: "wen",
packageName: "hoodie",
version: "1.0.0"),
const PackageMetadata(
groupId: "flamingo",
packageId: "wen",
packageName: "hoodie",
version: "1.0.0"),
const PackageMetadata(
groupId: "flamingo",
packageId: "wen",
packageName: "hoodie",
version: "1.0.0"),
];

class _PackageListState extends ConsumerState<PackageList> {
@override
Widget build(BuildContext context) {
final packageListFuture = ref.watch(packageListProvider);

return Scaffold(
appBar: AppBar(
title: const Text("Packages"),
automaticallyImplyLeading: true,
),
body: ListView.separated(
itemBuilder: itemBuilder,
itemCount: packageList.length,
shrinkWrap: true,
separatorBuilder: (context, index) => const Divider(),
body: packageListFuture.when(
data: (packageList) => ListView.separated(
itemBuilder: (c, i) => itemBuilder(c, i, packageList),
itemCount: packageList.length,
shrinkWrap: true,
separatorBuilder: (context, index) => const Divider(),
),
error: (error, stackTrace) {
debugPrint(error.toString());
debugPrint(stackTrace.toString());
return Center(
child: Text("Error: $error"),
);
},
loading: () => const Center(
child: CircularProgressIndicator(),
),
),
);
}

Widget? itemBuilder(BuildContext context, int index) {
final item = packageList[index];
return ListTile(
title: Text(item.packageName),
subtitle: Text(item.packageId),
leading: const Icon(Icons.apps),
dense: true,
onTap: () {},
trailing: Wrap(
children: [
IconButton(onPressed: () {}, icon: const Icon(Icons.download)),
IconButton(onPressed: () {}, icon: const Icon(Icons.delete)),
],
Widget? itemBuilder(
BuildContext context, int index, List<String> packageList) {
final packageId = packageList[index];
final packageMetadataFuture = ref.watch(packageInfoProvider(packageId));

return packageMetadataFuture.when(
data: (packageMetadata) => ListTile(
title: Text(packageMetadata.packageName),
subtitle: Text(packageMetadata.packageId),
leading: const Icon(Icons.apps),
dense: true,
onTap: () {},
trailing: Wrap(
children: [
IconButton(onPressed: () {}, icon: const Icon(Icons.download)),
IconButton(onPressed: () {}, icon: const Icon(Icons.delete)),
],
),
),
error: (error, stackTrace) => ListTile(
title: Text(packageId),
subtitle: Text("Suffered error: $error"),
),
loading: () => ListTile(
title: Text(packageId),
leading: const CircularProgressIndicator(),
),
);
}
Expand Down
61 changes: 32 additions & 29 deletions lib/pages/main_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import 'package:desktop_adb_file_browser/pages/main/browser.dart';
import 'package:desktop_adb_file_browser/pages/main/devices.dart';
import 'package:desktop_adb_file_browser/pages/main/logger.dart';
import 'package:desktop_adb_file_browser/pages/main/package_list.dart';
import 'package:desktop_adb_file_browser/riverpod/selected_device.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

enum _Page {
devices("Devices", FluentIcons.phone_48_regular, false),
Expand All @@ -22,36 +24,33 @@ enum _Page {
_Page _pageForIndex(int v) =>
_Page.values.firstWhere((element) => element.index == v);

class MainPage extends StatefulWidget {
class MainPage extends ConsumerStatefulWidget {
const MainPage({super.key});

@override
State<MainPage> createState() => _MainPageState();
ConsumerState<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
class _MainPageState extends ConsumerState<MainPage> {
_Page _currentPage = _Page.devices;
final ValueNotifier<String?> _selectedDevice = ValueNotifier<String?>(null);

@override
void initState() {
super.initState();
_selectedDevice.addListener(_onDeviceSelect);
}

@override
void dispose() {
super.dispose();
_selectedDevice.removeListener(_onDeviceSelect);
_selectedDevice.dispose();
}

void _onDeviceSelect() {
setState(() {});
}

Widget addDisabledTooltip(Widget widget) {
if (_selectedDevice.value != null) return widget;
final selectedDevice = ref.read(selectedDeviceProvider);
if (selectedDevice != null) return widget;

return Tooltip(
message: "No device selected",
Expand All @@ -61,12 +60,13 @@ class _MainPageState extends State<MainPage> {

@override
Widget build(BuildContext context) {
final selectedDevice = ref.watch(selectedDeviceProvider);

final dests = _Page.values
.map((x) => NavigationRailDestination(
icon: addDisabledTooltip(Icon(x.icon)),
label: Text(x.name),
disabled:
x.requiresDevice && _selectedDevice.value == null,
disabled: x.requiresDevice && selectedDevice == null,
))
.toList();

Expand All @@ -93,23 +93,26 @@ class _MainPageState extends State<MainPage> {
);
}

Widget _buildCurrentPage(_Page p) => switch (p) {
_Page.devices => DevicesPage(
key: const ValueKey("devices"),
serialSelector: _selectedDevice,
canNavigate: false,
),
_Page.browser => DeviceBrowserPage(
key: const ValueKey("browser"),
serial: _selectedDevice.value!,
),
_Page.logger => LogPage(
key: const ValueKey("logger"),
serial: _selectedDevice.value!,
),
_Page.packages => PackageList(
key: const ValueKey("packages"),
serial: _selectedDevice.value!,
),
};
Widget _buildCurrentPage(_Page p) {
final selectedDevice = ref.watch(selectedDeviceProvider);

return switch (p) {
_Page.devices => const DevicesPage(
key: ValueKey("devices"),
canNavigate: false,
),
_Page.browser => DeviceBrowserPage(
key: const ValueKey("browser"),
serial: selectedDevice!.serialName,
),
_Page.logger => LogPage(
key: const ValueKey("logger"),
serial: selectedDevice!.serialName,
),
_Page.packages => PackageList(
key: const ValueKey("packages"),
serial: selectedDevice!.serialName,
),
};
}
}
47 changes: 47 additions & 0 deletions lib/riverpod/package_list.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'dart:collection';

import 'package:desktop_adb_file_browser/riverpod/selected_device.dart';
import 'package:desktop_adb_file_browser/utils/adb.dart';
import 'package:desktop_adb_file_browser/utils/stack.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:trace/trace.dart';

part 'package_list.g.dart';
part 'package_list.freezed.dart';

@freezed
class PackageMetadata with _$PackageMetadata {
const factory PackageMetadata({
required String packageName,
required String packageId,
required String version,
required String groupId,
}) = _PackageMetadata;
}

@riverpod
class PackageList extends _$PackageList {
@override
Future<List<String>> build() async {
final serial = ref.watch(selectedDeviceProvider);

return Adb.getPackageList(serial?.serialName);
}

void installToDevice(String path) {}

void deletePackage(String id) {}
}

@riverpod
Future<PackageMetadata> packageInfo(PackageInfoRef ref, String id) async {
final device = ref.watch(selectedDeviceProvider);

return PackageMetadata(
packageId: id,
groupId: "",
packageName: "",
version: "",
);
}
File renamed without changes.
Loading

0 comments on commit 97ca437

Please sign in to comment.