Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Pull Request] Sort device cards, display more devices service status info #32

Merged
merged 10 commits into from
Jul 4, 2023
2 changes: 1 addition & 1 deletion kitx_mobile/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

Expand Down
28 changes: 28 additions & 0 deletions kitx_mobile/lib/pages/controls/device_status_icon.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:kitx_mobile/services/public/service_status.dart';
import 'package:kitx_mobile/utils/global.dart';

/// Device Status Icon
class DeviceStatusIcon extends StatelessWidget {
/// Constructor for Device Status Icon
const DeviceStatusIcon({super.key});

@override
Widget build(BuildContext context) {
return Obx(() {
switch (Global.webService.webServiceStatus.value) {
case ServiceStatus.running:
return const Icon(Icons.circle, color: Colors.greenAccent);
case ServiceStatus.pending:
return const Icon(Icons.timer);
case ServiceStatus.error:
return const Icon(Icons.error, color: Colors.redAccent);
case ServiceStatus.starting:
return const Icon(Icons.rocket_launch, color: Colors.lightBlueAccent);
case ServiceStatus.stopping:
return const Icon(Icons.square, color: Colors.yellowAccent);
}
});
}
}
35 changes: 35 additions & 0 deletions kitx_mobile/lib/pages/controls/device_status_label.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:kitx_mobile/services/public/service_status.dart';
import 'package:kitx_mobile/utils/global.dart';

/// Device Status Label
class DeviceStatusLabel extends StatelessWidget {
/// Constructor for Device Status Label
const DeviceStatusLabel({super.key});

@override
Widget build(BuildContext context) {
return Obx(() {
var textStyle = Theme.of(context).textTheme.bodyMedium;
switch (Global.webService.webServiceStatus.value) {
case ServiceStatus.running:
return Text(
'${Global.deviceService.length.obs} ${'HomePage_DevicesCount'.tr}',
style: textStyle,
);
case ServiceStatus.starting:
return Text('Public_Launching'.tr, style: textStyle);
case ServiceStatus.stopping:
return Text('Public_Stopping'.tr, style: textStyle);
case ServiceStatus.error:
return Text(
'${'Public_Error'.tr}: ${Global.webService.webServiceErrorMessage}',
style: textStyle,
);
default:
return Text('Public_Closed'.tr, style: textStyle);
}
});
}
}
33 changes: 8 additions & 25 deletions kitx_mobile/lib/pages/device_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:kitx_mobile/models/device_info.dart';
import 'package:kitx_mobile/pages/controls/device_card.dart';
import 'package:kitx_mobile/pages/controls/device_status_icon.dart';
import 'package:kitx_mobile/pages/controls/device_status_label.dart';
import 'package:kitx_mobile/pages/sub_pages/device_chat_page.dart';
import 'package:kitx_mobile/services/public/service_status.dart';
import 'package:kitx_mobile/utils/global.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';

Expand Down Expand Up @@ -79,20 +80,7 @@ class _DevicePage extends State<DevicePage> {
PopupMenuButton(
tooltip: '',
padding: EdgeInsets.all(0),
icon: Obx(() {
switch (Global.webService.webServiceStatus.value) {
case ServiceStatus.running:
return const Icon(Icons.circle, color: Colors.greenAccent);
case ServiceStatus.pending:
return const Icon(Icons.timer);
case ServiceStatus.error:
return const Icon(Icons.error, color: Colors.redAccent);
case ServiceStatus.starting:
return const Icon(Icons.rocket_launch, color: Colors.lightBlueAccent);
case ServiceStatus.stopping:
return const Icon(Icons.square, color: Colors.yellowAccent);
}
}),
icon: DeviceStatusIcon(),
position: PopupMenuPosition.under,
itemBuilder: (context) => [
PopupMenuItem(
Expand Down Expand Up @@ -129,16 +117,11 @@ class _DevicePage extends State<DevicePage> {
ListView(
controller: _scrollController,
children: [
Obx(
() => Padding(
padding: EdgeInsets.fromLTRB(30, 30, 30, 0),
child: Hero(
tag: 'HeroTag_DevicesCount',
child: Text(
'${Global.deviceService.length.obs} ${'HomePage_DevicesCount'.tr}',
style: Theme.of(context).textTheme.bodyMedium,
),
),
Padding(
padding: EdgeInsets.fromLTRB(30, 30, 30, 0),
child: Hero(
tag: 'HeroTag_DevicesCount',
child: const DeviceStatusLabel(),
),
),
const SizedBox(height: 25),
Expand Down
58 changes: 27 additions & 31 deletions kitx_mobile/lib/pages/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import 'package:get/get.dart';
import 'package:kitx_mobile/pages/about_page.dart';
import 'package:kitx_mobile/pages/account_page.dart';
import 'package:kitx_mobile/pages/controls/device_status_label.dart';
import 'package:kitx_mobile/pages/controls/drawer.dart';
import 'package:kitx_mobile/pages/device_page.dart';
import 'package:kitx_mobile/pages/settings_page.dart';
Expand Down Expand Up @@ -63,38 +64,33 @@ class HomePage extends StatelessWidget {
const SizedBox(height: tilesPadding),
SizedBox(
width: tileWidth,
child: Obx(
() => ListTile(
leading: const Icon(Icons.devices),
title: Text('Drawer_Devices'.tr),
subtitle: Hero(
tag: 'HeroTag_DevicesCount',
child: Text(
'${Global.deviceService.length.obs} ${'HomePage_DevicesCount'.tr}',
style: Theme.of(context).textTheme.bodyMedium,
),
),
trailing: const Icon(Icons.keyboard_arrow_right),
shape: tileRadius,
onTap: () => Global.delay(() => Get.to(() => DevicePage()), pageOpenDelay),
onLongPress: () {
showMenu(
context: context,
position: RelativeRect.fromLTRB(100, 0, 0, 100),
items: [
PopupMenuItem(
child: Text('Option_RestartDevicesServer'.tr),
onTap: Global.restartDevicesServer,
),
PopupMenuItem(
child: Text('Option_ShutdownDevicesServer'.tr),
onTap: Global.shutdownDevicesServer,
),
],
elevation: 8.0,
);
},
child: ListTile(
leading: const Icon(Icons.devices),
title: Text('Drawer_Devices'.tr),
subtitle: Hero(
tag: 'HeroTag_DevicesCount',
child: const DeviceStatusLabel(),
),
trailing: const Icon(Icons.keyboard_arrow_right),
shape: tileRadius,
onTap: () => Global.delay(() => Get.to(() => DevicePage()), pageOpenDelay),
onLongPress: () {
showMenu(
context: context,
position: RelativeRect.fromLTRB(100, 0, 0, 100),
items: [
PopupMenuItem(
child: Text('Option_RestartDevicesServer'.tr),
onTap: Global.restartDevicesServer,
),
PopupMenuItem(
child: Text('Option_ShutdownDevicesServer'.tr),
onTap: Global.shutdownDevicesServer,
),
],
elevation: 8.0,
);
},
),
),
const SizedBox(height: tilesPadding),
Expand Down
1 change: 0 additions & 1 deletion kitx_mobile/lib/pages/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ class _SettingsPageState extends State<SettingsPage> {
),
body: ListView(
children: [
const SizedBox(height: 60 * 3),
group(
SettingsGroupTitle(titleKey: 'SettingsPage_Theme'),
Column(
Expand Down
112 changes: 76 additions & 36 deletions kitx_mobile/lib/services/device_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import 'dart:async';

import 'package:get/get.dart';
import 'package:kitx_mobile/models/device_info.dart';
import 'package:kitx_mobile/models/enums/device_os_type.dart';
import 'package:kitx_mobile/services/public/service_status.dart';
import 'package:kitx_mobile/utils/config.dart';
import 'package:kitx_mobile/utils/global.dart';
import 'package:kitx_mobile/utils/log.dart';

/// Device Service
class DeviceService {
Expand All @@ -25,44 +27,76 @@ class DeviceService {

/// Add a device by [DeviceInfoStruct]
Future<void> addDevice(DeviceInfoStruct info) async {
if (deviceInfoList.isEmpty) {
deviceInfoList.add(info);
if (deviceServiceStatus != ServiceStatus.running) return;

var _tempList = deviceInfoList.toList();

var findIndex = _tempList.indexWhere(
(element) => element.iPv4 == info.iPv4 || element.deviceMacAddress == info.deviceMacAddress,
);

if (findIndex != -1) {
// Update existing device.

deviceInfoList[findIndex] = info;
} else {
var _tempList = deviceInfoList.toList();
var _tag = true;
// Add new device.

for (var each in _tempList) {
if (each.iPv4 == info.iPv4 || each.deviceMacAddress == info.deviceMacAddress) {
deviceInfoList[deviceInfoList.indexOf(each)] = each.rebuild(
(b) {
b
..sendTime = info.sendTime
..isMainDevice = info.isMainDevice
..deviceOSVersion = info.deviceOSVersion
..deviceServerPort = info.deviceServerPort
..pluginServerPort = info.pluginServerPort
..pluginsCount = info.pluginsCount;
},
);
_tag = false;
break;
if (info.deviceName == Global.deviceName) {
// Local device.

deviceInfoList.insert(0, info);
localDeviceCardAdded = true;

Log.info('Insert local device to 0.');
} else if (info.isMainDevice) {
// Main device.

var index = localDeviceCardAdded ? 1 : 0;
deviceInfoList.insert(index, info);
mainDeviceCardAdded = true;

Log.info('Insert main device to $index.');
} else {
// Other device.

var fixedCardsCount = (localDeviceCardAdded ? 1 : 0) + (mainDeviceCardAdded ? 1 : 0);

var countDevices = (osType) => _tempList.where((element) => element.deviceOSType == osType).length;

var devicesCountPerOS = <DeviceOSTypeEnum, int>{};
for (var osType in DeviceOSTypeEnum.values) {
devicesCountPerOS[osType] = countDevices(osType);
}
}

if (_tag) {
if (info.deviceName == Global.deviceName) {
deviceInfoList.insert(0, info);
localDeviceCardAdded = true;
} else if (info.isMainDevice) {
if (localDeviceCardAdded) {
deviceInfoList.insert(1, info);
} else {
deviceInfoList.insert(0, info);
}
mainDeviceCardAdded = true;
} else {
deviceInfoList.add(info);
var localDeviceOS = _tempList.firstWhereOrNull((element) => element.deviceName == Global.deviceName);
var mainDeviceOS = _tempList.firstWhereOrNull((element) => element.isMainDevice);

if (localDeviceOS != null) {
devicesCountPerOS[localDeviceOS.deviceOSType] = devicesCountPerOS[localDeviceOS.deviceOSType]! - 1;
}
if (mainDeviceOS != null) {
devicesCountPerOS[mainDeviceOS.deviceOSType] = devicesCountPerOS[mainDeviceOS.deviceOSType]! - 1;
}

var instIndex = fixedCardsCount;

var sortList = [
DeviceOSTypeEnum.Windows,
DeviceOSTypeEnum.Linux,
DeviceOSTypeEnum.MacOS,
DeviceOSTypeEnum.Android,
DeviceOSTypeEnum.iOS,
];

for (var element in sortList) {
instIndex += devicesCountPerOS[element]!;
if (element == info.deviceOSType) break;
}

var targetIndex = instIndex > deviceInfoList.length ? deviceInfoList.length : instIndex;

deviceInfoList.insert(targetIndex, info);
}
}

Expand All @@ -72,11 +106,9 @@ class DeviceService {
/// 停止服务
Future<void> stopService() async {
deviceServiceStatus = ServiceStatus.stopping;

deviceInfoList.clear();

localDeviceCardAdded = false;

mainDeviceCardAdded = false;

deviceServiceStatus = ServiceStatus.pending;
Expand All @@ -87,7 +119,6 @@ class DeviceService {
deviceServiceStatus = ServiceStatus.starting;

localDeviceCardAdded = false;

mainDeviceCardAdded = false;

Timer.periodic(Duration(seconds: Config.WebService_DeviceInfoCheckTTLSeconds), (_) {
Expand All @@ -99,6 +130,15 @@ class DeviceService {

if (now.difference(time).inSeconds > Config.WebService_DeviceInfoTTLSeconds) {
deviceInfoList.remove(each);

if (each.deviceName == Global.deviceName) {
localDeviceCardAdded = false;

// If local device removed, restart devices server.
Global.restartDevicesServer();
} else if (each.isMainDevice) {
mainDeviceCardAdded = false;
}
}
}

Expand Down
Loading