Add flutter 3+ support. Update dependencies. Fix code style and format issues.
This commit is contained in:
@@ -1,15 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:thingsboard_app/core/context/tb_context.dart';
|
||||
import 'package:thingsboard_app/core/entity/entity_details_page.dart';
|
||||
import 'package:thingsboard_client/thingsboard_client.dart';
|
||||
|
||||
class DeviceDetailsPage extends EntityDetailsPage<DeviceInfo> {
|
||||
|
||||
DeviceDetailsPage(TbContext tbContext, String deviceId):
|
||||
super(tbContext,
|
||||
entityId: deviceId,
|
||||
defaultTitle: 'Device');
|
||||
DeviceDetailsPage(TbContext tbContext, String deviceId)
|
||||
: super(tbContext, entityId: deviceId, defaultTitle: 'Device');
|
||||
|
||||
@override
|
||||
Future<DeviceInfo?> fetchEntity(String deviceId) {
|
||||
@@ -23,5 +19,4 @@ class DeviceDetailsPage extends EntityDetailsPage<DeviceInfo> {
|
||||
subtitle: Text('${device.type}'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'dart:async';
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:thingsboard_app/constants/assets_path.dart';
|
||||
import 'package:thingsboard_app/core/context/tb_context.dart';
|
||||
@@ -14,7 +13,6 @@ import 'package:thingsboard_app/utils/utils.dart';
|
||||
import 'package:thingsboard_client/thingsboard_client.dart';
|
||||
|
||||
mixin DeviceProfilesBase on EntitiesBase<DeviceProfileInfo, PageLink> {
|
||||
|
||||
final RefreshDeviceCounts refreshDeviceCounts = RefreshDeviceCounts();
|
||||
|
||||
@override
|
||||
@@ -48,7 +46,8 @@ mixin DeviceProfilesBase on EntitiesBase<DeviceProfileInfo, PageLink> {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildEntityGridCard(BuildContext context, DeviceProfileInfo deviceProfile) {
|
||||
Widget buildEntityGridCard(
|
||||
BuildContext context, DeviceProfileInfo deviceProfile) {
|
||||
return DeviceProfileCard(tbContext, deviceProfile);
|
||||
}
|
||||
|
||||
@@ -56,7 +55,6 @@ mixin DeviceProfilesBase on EntitiesBase<DeviceProfileInfo, PageLink> {
|
||||
double? gridChildAspectRatio() {
|
||||
return 156 / 200;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RefreshDeviceCounts {
|
||||
@@ -64,20 +62,20 @@ class RefreshDeviceCounts {
|
||||
}
|
||||
|
||||
class AllDevicesCard extends TbContextWidget {
|
||||
|
||||
final RefreshDeviceCounts refreshDeviceCounts;
|
||||
|
||||
AllDevicesCard(TbContext tbContext, this.refreshDeviceCounts) : super(tbContext);
|
||||
AllDevicesCard(TbContext tbContext, this.refreshDeviceCounts)
|
||||
: super(tbContext);
|
||||
|
||||
@override
|
||||
_AllDevicesCardState createState() => _AllDevicesCardState();
|
||||
|
||||
}
|
||||
|
||||
class _AllDevicesCardState extends TbContextState<AllDevicesCard> {
|
||||
|
||||
final StreamController<int?> _activeDevicesCount = StreamController.broadcast();
|
||||
final StreamController<int?> _inactiveDevicesCount = StreamController.broadcast();
|
||||
final StreamController<int?> _activeDevicesCount =
|
||||
StreamController.broadcast();
|
||||
final StreamController<int?> _inactiveDevicesCount =
|
||||
StreamController.broadcast();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -103,9 +101,12 @@ class _AllDevicesCardState extends TbContextState<AllDevicesCard> {
|
||||
Future<void> _countDevices() {
|
||||
_activeDevicesCount.add(null);
|
||||
_inactiveDevicesCount.add(null);
|
||||
Future<int> activeDevicesCount = EntityQueryApi.countDevices(tbClient, active: true);
|
||||
Future<int> inactiveDevicesCount = EntityQueryApi.countDevices(tbClient, active: false);
|
||||
Future<List<int>> countsFuture = Future.wait([activeDevicesCount, inactiveDevicesCount]);
|
||||
Future<int> activeDevicesCount =
|
||||
EntityQueryApi.countDevices(tbClient, active: true);
|
||||
Future<int> inactiveDevicesCount =
|
||||
EntityQueryApi.countDevices(tbClient, active: false);
|
||||
Future<List<int>> countsFuture =
|
||||
Future.wait([activeDevicesCount, inactiveDevicesCount]);
|
||||
countsFuture.then((counts) {
|
||||
if (this.mounted) {
|
||||
_activeDevicesCount.add(counts[0]);
|
||||
@@ -117,20 +118,19 @@ class _AllDevicesCardState extends TbContextState<AllDevicesCard> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child:
|
||||
Container(
|
||||
child: Card(
|
||||
margin: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
elevation: 0,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(padding: EdgeInsets.fromLTRB(16, 12, 16, 15),
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
child: Card(
|
||||
margin: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
elevation: 0,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(16, 12, 16, 15),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -139,120 +139,126 @@ class _AllDevicesCardState extends TbContextState<AllDevicesCard> {
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 20 / 14
|
||||
)
|
||||
),
|
||||
height: 20 / 14)),
|
||||
Icon(Icons.arrow_forward, size: 18)
|
||||
],
|
||||
)
|
||||
),
|
||||
Divider(height: 1),
|
||||
Padding(padding: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(fit: FlexFit.tight,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: StreamBuilder<int?>(
|
||||
stream: _activeDevicesCount.stream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(context, true, deviceCount);
|
||||
} else {
|
||||
return Center(child:
|
||||
Container(height: 20, width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(tbContext.currentState!.context).colorScheme.primary),
|
||||
strokeWidth: 2.5)));
|
||||
}
|
||||
},
|
||||
)
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList?active=true');
|
||||
}
|
||||
),
|
||||
),
|
||||
// SizedBox(width: 4),
|
||||
Container(width: 1,
|
||||
height: 40,
|
||||
child: VerticalDivider(width: 1)
|
||||
),
|
||||
Flexible(fit: FlexFit.tight,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: StreamBuilder<int?>(
|
||||
stream: _inactiveDevicesCount.stream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(context, false, deviceCount);
|
||||
} else {
|
||||
return Center(child:
|
||||
Container(height: 20, width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(tbContext.currentState!.context).colorScheme.primary),
|
||||
strokeWidth: 2.5)));
|
||||
}
|
||||
},
|
||||
)
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList?active=false');
|
||||
}
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withAlpha((255 * 0.05).ceil()),
|
||||
blurRadius: 6.0,
|
||||
offset: Offset(0, 4)
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
Divider(height: 1),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: StreamBuilder<int?>(
|
||||
stream: _activeDevicesCount.stream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(
|
||||
context, true, deviceCount);
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation(
|
||||
Theme.of(tbContext
|
||||
.currentState!
|
||||
.context)
|
||||
.colorScheme
|
||||
.primary),
|
||||
strokeWidth: 2.5)));
|
||||
}
|
||||
},
|
||||
)),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList?active=true');
|
||||
}),
|
||||
),
|
||||
// SizedBox(width: 4),
|
||||
Container(
|
||||
width: 1,
|
||||
height: 40,
|
||||
child: VerticalDivider(width: 1)),
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: StreamBuilder<int?>(
|
||||
stream: _inactiveDevicesCount.stream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(
|
||||
context, false, deviceCount);
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation(
|
||||
Theme.of(tbContext
|
||||
.currentState!
|
||||
.context)
|
||||
.colorScheme
|
||||
.primary),
|
||||
strokeWidth: 2.5)));
|
||||
}
|
||||
},
|
||||
)),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList?active=false');
|
||||
}),
|
||||
)
|
||||
],
|
||||
))
|
||||
],
|
||||
)),
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withAlpha((255 * 0.05).ceil()),
|
||||
blurRadius: 6.0,
|
||||
offset: Offset(0, 4))
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList');
|
||||
}
|
||||
);
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DeviceProfileCard extends TbContextWidget {
|
||||
|
||||
final DeviceProfileInfo deviceProfile;
|
||||
|
||||
DeviceProfileCard(TbContext tbContext, this.deviceProfile) : super(tbContext);
|
||||
|
||||
@override
|
||||
_DeviceProfileCardState createState() => _DeviceProfileCardState();
|
||||
|
||||
}
|
||||
|
||||
class _DeviceProfileCardState extends TbContextState<DeviceProfileCard> {
|
||||
|
||||
late Future<int> activeDevicesCount;
|
||||
late Future<int> inactiveDevicesCount;
|
||||
|
||||
@@ -269,8 +275,10 @@ class _DeviceProfileCardState extends TbContextState<DeviceProfileCard> {
|
||||
}
|
||||
|
||||
_countDevices() {
|
||||
activeDevicesCount = EntityQueryApi.countDevices(tbClient, deviceType: widget.deviceProfile.name, active: true);
|
||||
inactiveDevicesCount = EntityQueryApi.countDevices(tbClient, deviceType: widget.deviceProfile.name, active: false);
|
||||
activeDevicesCount = EntityQueryApi.countDevices(tbClient,
|
||||
deviceType: widget.deviceProfile.name, active: true);
|
||||
inactiveDevicesCount = EntityQueryApi.countDevices(tbClient,
|
||||
deviceType: widget.deviceProfile.name, active: false);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -292,99 +300,95 @@ class _DeviceProfileCardState extends TbContextState<DeviceProfileCard> {
|
||||
imageFit = BoxFit.cover;
|
||||
padding = 0;
|
||||
}
|
||||
return
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Stack (
|
||||
children: [
|
||||
SizedBox.expand(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(padding),
|
||||
child: FittedBox(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
fit: imageFit,
|
||||
child: image
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
Container(
|
||||
height: 44,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 6),
|
||||
child: Center(
|
||||
child: AutoSizeText(entity.name,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
minFontSize: 12,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 20 / 14
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Divider(height: 1),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: FutureBuilder<int>(
|
||||
future: activeDevicesCount,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(context, true, deviceCount);
|
||||
} else {
|
||||
return Container(height: 40,
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 20, width: 20,
|
||||
child:
|
||||
CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(tbContext.currentState!.context).colorScheme.primary),
|
||||
strokeWidth: 2.5))));
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList?active=true&deviceType=${entity.name}');
|
||||
}
|
||||
),
|
||||
Divider(height: 1),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: FutureBuilder<int>(
|
||||
future: inactiveDevicesCount,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(context, false, deviceCount);
|
||||
} else {
|
||||
return Container(height: 40,
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 20, width: 20,
|
||||
child:
|
||||
CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(tbContext.currentState!.context).colorScheme.primary),
|
||||
strokeWidth: 2.5))));
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList?active=false&deviceType=${entity.name}');
|
||||
}
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: Stack(children: [
|
||||
SizedBox.expand(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(padding),
|
||||
child: FittedBox(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
fit: imageFit,
|
||||
child: image)))
|
||||
])),
|
||||
Container(
|
||||
height: 44,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 6),
|
||||
child: Center(
|
||||
child: AutoSizeText(
|
||||
entity.name,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
minFontSize: 12,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 20 / 14),
|
||||
)))),
|
||||
Divider(height: 1),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: FutureBuilder<int>(
|
||||
future: activeDevicesCount,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData &&
|
||||
snapshot.connectionState == ConnectionState.done) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(context, true, deviceCount);
|
||||
} else {
|
||||
return Container(
|
||||
height: 40,
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(
|
||||
tbContext.currentState!.context)
|
||||
.colorScheme
|
||||
.primary),
|
||||
strokeWidth: 2.5))));
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo('/deviceList?active=true&deviceType=${entity.name}');
|
||||
}),
|
||||
Divider(height: 1),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: FutureBuilder<int>(
|
||||
future: inactiveDevicesCount,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData &&
|
||||
snapshot.connectionState == ConnectionState.done) {
|
||||
var deviceCount = snapshot.data!;
|
||||
return _buildDeviceCount(context, false, deviceCount);
|
||||
} else {
|
||||
return Container(
|
||||
height: 40,
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(
|
||||
tbContext.currentState!.context)
|
||||
.colorScheme
|
||||
.primary),
|
||||
strokeWidth: 2.5))));
|
||||
}
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
navigateTo(
|
||||
'/deviceList?active=false&deviceType=${entity.name}');
|
||||
})
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,26 +406,27 @@ Widget _buildDeviceCount(BuildContext context, bool active, int count) {
|
||||
Stack(
|
||||
children: [
|
||||
Icon(Icons.devices_other, size: 16, color: color),
|
||||
if (!active) CustomPaint(
|
||||
size: Size.square(16),
|
||||
painter: StrikeThroughPainter(color: color, offset: 2),
|
||||
)
|
||||
if (!active)
|
||||
CustomPaint(
|
||||
size: Size.square(16),
|
||||
painter: StrikeThroughPainter(color: color, offset: 2),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(width: 8.67),
|
||||
Text(active ? 'Active' : 'Inactive', style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 16 / 12,
|
||||
color: color
|
||||
)),
|
||||
SizedBox(width: 8.67),
|
||||
Text(count.toString(), style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 16 / 12,
|
||||
color: color
|
||||
))
|
||||
SizedBox(width: 8.67),
|
||||
Text(active ? 'Active' : 'Inactive',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 16 / 12,
|
||||
color: color)),
|
||||
SizedBox(width: 8.67),
|
||||
Text(count.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 16 / 12,
|
||||
color: color))
|
||||
],
|
||||
),
|
||||
Icon(Icons.chevron_right, size: 16, color: Color(0xFFACACAC))
|
||||
@@ -431,7 +436,6 @@ Widget _buildDeviceCount(BuildContext context, bool active, int count) {
|
||||
}
|
||||
|
||||
class StrikeThroughPainter extends CustomPainter {
|
||||
|
||||
final Color color;
|
||||
final double offset;
|
||||
|
||||
@@ -441,7 +445,8 @@ class StrikeThroughPainter extends CustomPainter {
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()..color = color;
|
||||
paint.strokeWidth = 1.5;
|
||||
canvas.drawLine(Offset(offset, offset), Offset(size.width - offset, size.height - offset), paint);
|
||||
canvas.drawLine(Offset(offset, offset),
|
||||
Offset(size.width - offset, size.height - offset), paint);
|
||||
paint.color = Colors.white;
|
||||
canvas.drawLine(Offset(2, 0), Offset(size.width + 2, size.height), paint);
|
||||
}
|
||||
@@ -450,5 +455,4 @@ class StrikeThroughPainter extends CustomPainter {
|
||||
bool shouldRepaint(covariant StrikeThroughPainter oldDelegate) {
|
||||
return color != oldDelegate.color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@ import 'package:thingsboard_client/thingsboard_client.dart';
|
||||
|
||||
import 'device_profiles_base.dart';
|
||||
|
||||
class DeviceProfilesGrid extends BaseEntitiesWidget<DeviceProfileInfo, PageLink> with DeviceProfilesBase, EntitiesGridStateBase {
|
||||
|
||||
DeviceProfilesGrid(TbContext tbContext, PageKeyController<PageLink> pageKeyController) : super(tbContext, pageKeyController);
|
||||
|
||||
class DeviceProfilesGrid extends BaseEntitiesWidget<DeviceProfileInfo, PageLink>
|
||||
with DeviceProfilesBase, EntitiesGridStateBase {
|
||||
DeviceProfilesGrid(
|
||||
TbContext tbContext, PageKeyController<PageLink> pageKeyController)
|
||||
: super(tbContext, pageKeyController);
|
||||
}
|
||||
|
||||
@@ -9,24 +9,28 @@ import 'device_details_page.dart';
|
||||
import 'devices_list_page.dart';
|
||||
|
||||
class DeviceRoutes extends TbRoutes {
|
||||
|
||||
late var devicesHandler = Handler(handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
late var devicesHandler = Handler(
|
||||
handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
return MainPage(tbContext, path: '/devices');
|
||||
});
|
||||
|
||||
late var devicesPageHandler = Handler(handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
late var devicesPageHandler = Handler(
|
||||
handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
return DevicesPage(tbContext);
|
||||
});
|
||||
|
||||
late var deviceListHandler = Handler(handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
late var deviceListHandler = Handler(
|
||||
handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
var searchMode = params['search']?.first == 'true';
|
||||
var deviceType = params['deviceType']?.first;
|
||||
String? activeStr = params['active']?.first;
|
||||
bool? active = activeStr != null ? activeStr == 'true' : null;
|
||||
return DevicesListPage(tbContext, searchMode: searchMode, deviceType: deviceType, active: active);
|
||||
return DevicesListPage(tbContext,
|
||||
searchMode: searchMode, deviceType: deviceType, active: active);
|
||||
});
|
||||
|
||||
late var deviceDetailsHandler = Handler(handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
late var deviceDetailsHandler = Handler(
|
||||
handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
|
||||
return DeviceDetailsPage(tbContext, params["id"][0]);
|
||||
});
|
||||
|
||||
@@ -39,5 +43,4 @@ class DeviceRoutes extends TbRoutes {
|
||||
router.define("/deviceList", handler: deviceListHandler);
|
||||
router.define("/device/:id", handler: deviceDetailsHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:core';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:thingsboard_app/constants/assets_path.dart';
|
||||
@@ -14,7 +13,6 @@ import 'package:thingsboard_app/utils/utils.dart';
|
||||
import 'package:thingsboard_client/thingsboard_client.dart';
|
||||
|
||||
mixin DevicesBase on EntitiesBase<EntityData, EntityDataQuery> {
|
||||
|
||||
@override
|
||||
String get title => 'Devices';
|
||||
|
||||
@@ -28,14 +26,19 @@ mixin DevicesBase on EntitiesBase<EntityData, EntityDataQuery> {
|
||||
|
||||
@override
|
||||
void onEntityTap(EntityData device) async {
|
||||
var profile = await DeviceProfileCache.getDeviceProfileInfo(tbClient, device.field('type')!, device.entityId.id!);
|
||||
var profile = await DeviceProfileCache.getDeviceProfileInfo(
|
||||
tbClient, device.field('type')!, device.entityId.id!);
|
||||
if (profile.defaultDashboardId != null) {
|
||||
var dashboardId = profile.defaultDashboardId!.id!;
|
||||
var state = Utils.createDashboardEntityState(device.entityId, entityName: device.field('name')!, entityLabel: device.field('label')!);
|
||||
navigateToDashboard(dashboardId, dashboardTitle: device.field('name'), state: state);
|
||||
var state = Utils.createDashboardEntityState(device.entityId,
|
||||
entityName: device.field('name')!,
|
||||
entityLabel: device.field('label')!);
|
||||
navigateToDashboard(dashboardId,
|
||||
dashboardTitle: device.field('name'), state: state);
|
||||
} else {
|
||||
if (tbClient.isTenantAdmin()) {
|
||||
showWarnNotification('Mobile dashboard should be configured in device profile!');
|
||||
showWarnNotification(
|
||||
'Mobile dashboard should be configured in device profile!');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,42 +60,51 @@ mixin DevicesBase on EntitiesBase<EntityData, EntityDataQuery> {
|
||||
|
||||
bool displayCardImage(bool listWidgetCard) => listWidgetCard;
|
||||
|
||||
Widget _buildEntityListCard(BuildContext context, EntityData device, bool listWidgetCard) {
|
||||
return DeviceCard(tbContext, device: device, listWidgetCard: listWidgetCard, displayImage: displayCardImage(listWidgetCard));
|
||||
Widget _buildEntityListCard(
|
||||
BuildContext context, EntityData device, bool listWidgetCard) {
|
||||
return DeviceCard(tbContext,
|
||||
device: device,
|
||||
listWidgetCard: listWidgetCard,
|
||||
displayImage: displayCardImage(listWidgetCard));
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceQueryController extends PageKeyController<EntityDataQuery> {
|
||||
|
||||
DeviceQueryController({int pageSize = 20, String? searchText, String? deviceType, bool? active}):
|
||||
super(EntityQueryApi.createDefaultDeviceQuery(pageSize: pageSize, searchText: searchText, deviceType: deviceType, active: active));
|
||||
DeviceQueryController(
|
||||
{int pageSize = 20, String? searchText, String? deviceType, bool? active})
|
||||
: super(EntityQueryApi.createDefaultDeviceQuery(
|
||||
pageSize: pageSize,
|
||||
searchText: searchText,
|
||||
deviceType: deviceType,
|
||||
active: active));
|
||||
|
||||
@override
|
||||
EntityDataQuery nextPageKey(EntityDataQuery deviceQuery) => deviceQuery.next();
|
||||
EntityDataQuery nextPageKey(EntityDataQuery deviceQuery) =>
|
||||
deviceQuery.next();
|
||||
|
||||
onSearchText(String searchText) {
|
||||
value.pageKey.pageLink.page = 0;
|
||||
value.pageKey.pageLink.textSearch = searchText;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DeviceCard extends TbContextWidget {
|
||||
|
||||
final EntityData device;
|
||||
final bool listWidgetCard;
|
||||
final bool displayImage;
|
||||
|
||||
DeviceCard(TbContext tbContext, {required this.device, this.listWidgetCard = false, this.displayImage = false}) : super(tbContext);
|
||||
DeviceCard(TbContext tbContext,
|
||||
{required this.device,
|
||||
this.listWidgetCard = false,
|
||||
this.displayImage = false})
|
||||
: super(tbContext);
|
||||
|
||||
@override
|
||||
_DeviceCardState createState() => _DeviceCardState();
|
||||
|
||||
}
|
||||
|
||||
class _DeviceCardState extends TbContextState<DeviceCard> {
|
||||
|
||||
final entityDateFormat = DateFormat('yyyy-MM-dd');
|
||||
|
||||
late Future<DeviceProfileInfo> deviceProfileFuture;
|
||||
@@ -129,250 +141,256 @@ class _DeviceCardState extends TbContextState<DeviceCard> {
|
||||
}
|
||||
|
||||
Widget buildCard(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
return Stack(children: [
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Container(
|
||||
width: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.device.attribute('active') == 'true' ? Color(0xFF008A00) : Color(0xFFAFAFAF),
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(4), bottomLeft: Radius.circular(4))
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
FutureBuilder<DeviceProfileInfo>(
|
||||
width: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.device.attribute('active') == 'true'
|
||||
? Color(0xFF008A00)
|
||||
: Color(0xFFAFAFAF),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(4),
|
||||
bottomLeft: Radius.circular(4))),
|
||||
))),
|
||||
FutureBuilder<DeviceProfileInfo>(
|
||||
future: deviceProfileFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData &&
|
||||
snapshot.connectionState == ConnectionState.done) {
|
||||
var profile = snapshot.data!;
|
||||
bool hasDashboard = profile.defaultDashboardId != null;
|
||||
Widget image;
|
||||
BoxFit imageFit;
|
||||
if (profile.image != null) {
|
||||
image = Utils.imageFromBase64(profile.image!);
|
||||
imageFit = BoxFit.contain;
|
||||
} else {
|
||||
image = SvgPicture.asset(
|
||||
ThingsboardImage.deviceProfilePlaceholder,
|
||||
color: Theme.of(context).primaryColor,
|
||||
colorBlendMode: BlendMode.overlay,
|
||||
semanticsLabel: 'Device');
|
||||
imageFit = BoxFit.cover;
|
||||
}
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(width: 20),
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 12),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.displayImage)
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(4))),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(4)),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: FittedBox(
|
||||
fit: imageFit,
|
||||
child: image,
|
||||
))
|
||||
],
|
||||
))),
|
||||
SizedBox(width: 12),
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: Column(children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment:
|
||||
Alignment.centerLeft,
|
||||
child: Text(
|
||||
'${widget.device.field('name')!}',
|
||||
style: TextStyle(
|
||||
color: Color(
|
||||
0xFF282828),
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w500,
|
||||
height:
|
||||
20 / 14)))),
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
entityDateFormat.format(DateTime
|
||||
.fromMillisecondsSinceEpoch(
|
||||
widget.device
|
||||
.createdTime!)),
|
||||
style: TextStyle(
|
||||
color: Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
fontWeight:
|
||||
FontWeight.normal,
|
||||
height: 16 / 12))
|
||||
]),
|
||||
SizedBox(height: 4),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${widget.device.field('type')!}',
|
||||
style: TextStyle(
|
||||
color: Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
fontWeight:
|
||||
FontWeight.normal,
|
||||
height: 16 / 12)),
|
||||
Text(
|
||||
widget.device.attribute(
|
||||
'active') ==
|
||||
'true'
|
||||
? 'Active'
|
||||
: 'Inactive',
|
||||
style: TextStyle(
|
||||
color: widget.device
|
||||
.attribute(
|
||||
'active') ==
|
||||
'true'
|
||||
? Color(0xFF008A00)
|
||||
: Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
height: 16 / 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
))
|
||||
],
|
||||
)
|
||||
])),
|
||||
SizedBox(width: 16),
|
||||
if (hasDashboard)
|
||||
Icon(Icons.chevron_right,
|
||||
color: Color(0xFFACACAC)),
|
||||
if (hasDashboard) SizedBox(width: 16),
|
||||
]),
|
||||
SizedBox(height: 12)
|
||||
],
|
||||
))
|
||||
]);
|
||||
} else {
|
||||
return Container(
|
||||
height: 64,
|
||||
child: Center(
|
||||
child: RefreshProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(
|
||||
Theme.of(tbContext.currentState!.context)
|
||||
.colorScheme
|
||||
.primary))));
|
||||
}
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
Widget buildListWidgetCard(BuildContext context) {
|
||||
return Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
if (widget.displayImage)
|
||||
Container(
|
||||
width: 58,
|
||||
height: 58,
|
||||
decoration: BoxDecoration(
|
||||
// color: Color(0xFFEEEEEE),
|
||||
borderRadius: BorderRadius.horizontal(left: Radius.circular(4))),
|
||||
child: FutureBuilder<DeviceProfileInfo>(
|
||||
future: deviceProfileFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.hasData &&
|
||||
snapshot.connectionState == ConnectionState.done) {
|
||||
var profile = snapshot.data!;
|
||||
bool hasDashboard = profile.defaultDashboardId != null;
|
||||
Widget image;
|
||||
BoxFit imageFit;
|
||||
if (profile.image != null) {
|
||||
image = Utils.imageFromBase64(profile.image!);
|
||||
imageFit = BoxFit.contain;
|
||||
} else {
|
||||
image = SvgPicture.asset(ThingsboardImage.deviceProfilePlaceholder,
|
||||
image = SvgPicture.asset(
|
||||
ThingsboardImage.deviceProfilePlaceholder,
|
||||
color: Theme.of(context).primaryColor,
|
||||
colorBlendMode: BlendMode.overlay,
|
||||
semanticsLabel: 'Device');
|
||||
imageFit = BoxFit.cover;
|
||||
}
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(width: 20),
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 12),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.displayImage) Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(4))
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(4)),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: FittedBox(
|
||||
fit: imageFit,
|
||||
child: image,
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('${widget.device.field('name')!}',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF282828),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 20 / 14
|
||||
))
|
||||
)
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Text(entityDateFormat.format(DateTime.fromMillisecondsSinceEpoch(widget.device.createdTime!)),
|
||||
style: TextStyle(
|
||||
color: Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
height: 16 / 12
|
||||
))
|
||||
]
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('${widget.device.field('type')!}',
|
||||
style: TextStyle(
|
||||
color: Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
height: 16 / 12
|
||||
)),
|
||||
Text(widget.device.attribute('active') == 'true' ? 'Active' : 'Inactive',
|
||||
style: TextStyle(
|
||||
color: widget.device.attribute('active') == 'true' ? Color(0xFF008A00) : Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
height: 16 / 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
))
|
||||
],
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
if (hasDashboard) Icon(Icons.chevron_right, color: Color(0xFFACACAC)),
|
||||
if (hasDashboard) SizedBox(width: 16),
|
||||
]
|
||||
),
|
||||
SizedBox(height: 12)
|
||||
],
|
||||
)
|
||||
)
|
||||
]
|
||||
);
|
||||
return ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius.horizontal(left: Radius.circular(4)),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: FittedBox(
|
||||
fit: imageFit,
|
||||
child: image,
|
||||
))
|
||||
],
|
||||
));
|
||||
} else {
|
||||
return Container(
|
||||
height: 64,
|
||||
child: Center(
|
||||
child: RefreshProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(tbContext.currentState!.context).colorScheme.primary)
|
||||
)
|
||||
)
|
||||
);
|
||||
return Center(
|
||||
child: RefreshProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(
|
||||
Theme.of(tbContext.currentState!.context)
|
||||
.colorScheme
|
||||
.primary)));
|
||||
}
|
||||
}
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildListWidgetCard(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.displayImage) Container(
|
||||
width: 58,
|
||||
height: 58,
|
||||
decoration: BoxDecoration(
|
||||
// color: Color(0xFFEEEEEE),
|
||||
borderRadius: BorderRadius.horizontal(left: Radius.circular(4))
|
||||
),
|
||||
child: FutureBuilder<DeviceProfileInfo>(
|
||||
future: deviceProfileFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
|
||||
var profile = snapshot.data!;
|
||||
Widget image;
|
||||
BoxFit imageFit;
|
||||
if (profile.image != null) {
|
||||
image = Utils.imageFromBase64(profile.image!);
|
||||
imageFit = BoxFit.contain;
|
||||
} else {
|
||||
image = SvgPicture.asset(ThingsboardImage.deviceProfilePlaceholder,
|
||||
color: Theme.of(context).primaryColor,
|
||||
colorBlendMode: BlendMode.overlay,
|
||||
semanticsLabel: 'Device');
|
||||
imageFit = BoxFit.cover;
|
||||
}
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.horizontal(left: Radius.circular(4)),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: FittedBox(
|
||||
fit: imageFit,
|
||||
child: image,
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return Center(child: RefreshProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Theme.of(tbContext.currentState!.context).colorScheme.primary)
|
||||
));
|
||||
}
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
Flexible(
|
||||
fit: FlexFit.loose,
|
||||
child:
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 9, horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
FittedBox(
|
||||
fit: BoxFit.fitWidth,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('${widget.device.field('name')!}',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF282828),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 20 / 14
|
||||
))
|
||||
)
|
||||
]
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('${widget.device.field('type')!}',
|
||||
style: TextStyle(
|
||||
color: Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
height: 16 / 12
|
||||
)),
|
||||
]
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
);
|
||||
),
|
||||
Flexible(
|
||||
fit: FlexFit.loose,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 9, horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
FittedBox(
|
||||
fit: BoxFit.fitWidth,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('${widget.device.field('name')!}',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF282828),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 20 / 14)))
|
||||
]),
|
||||
SizedBox(height: 4),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('${widget.device.field('type')!}',
|
||||
style: TextStyle(
|
||||
color: Color(0xFFAFAFAF),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
height: 16 / 12)),
|
||||
])
|
||||
],
|
||||
)))
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ import 'package:thingsboard_app/core/entity/entities_list.dart';
|
||||
import 'package:thingsboard_app/modules/device/devices_base.dart';
|
||||
import 'package:thingsboard_client/thingsboard_client.dart';
|
||||
|
||||
class DevicesList extends BaseEntitiesWidget<EntityData, EntityDataQuery> with DevicesBase, EntitiesListStateBase {
|
||||
|
||||
class DevicesList extends BaseEntitiesWidget<EntityData, EntityDataQuery>
|
||||
with DevicesBase, EntitiesListStateBase {
|
||||
final bool displayDeviceImage;
|
||||
|
||||
DevicesList(TbContext tbContext, PageKeyController<EntityDataQuery> pageKeyController, {searchMode = false, this.displayDeviceImage = false}):
|
||||
super(tbContext, pageKeyController, searchMode: searchMode);
|
||||
DevicesList(
|
||||
TbContext tbContext, PageKeyController<EntityDataQuery> pageKeyController,
|
||||
{searchMode = false, this.displayDeviceImage = false})
|
||||
: super(tbContext, pageKeyController, searchMode: searchMode);
|
||||
|
||||
@override
|
||||
bool displayCardImage(bool listWidgetCard) => displayDeviceImage;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -6,87 +6,85 @@ import 'package:thingsboard_app/modules/device/devices_list.dart';
|
||||
import 'package:thingsboard_app/widgets/tb_app_bar.dart';
|
||||
|
||||
class DevicesListPage extends TbPageWidget {
|
||||
|
||||
final String? deviceType;
|
||||
final bool? active;
|
||||
final bool searchMode;
|
||||
|
||||
DevicesListPage(TbContext tbContext, {this.deviceType, this.active, this.searchMode = false}) : super(tbContext);
|
||||
DevicesListPage(TbContext tbContext,
|
||||
{this.deviceType, this.active, this.searchMode = false})
|
||||
: super(tbContext);
|
||||
|
||||
@override
|
||||
_DevicesListPageState createState() => _DevicesListPageState();
|
||||
|
||||
}
|
||||
|
||||
class _DevicesListPageState extends TbPageState<DevicesListPage> {
|
||||
|
||||
late final DeviceQueryController _deviceQueryController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_deviceQueryController = DeviceQueryController(deviceType: widget.deviceType, active: widget.active);
|
||||
_deviceQueryController = DeviceQueryController(
|
||||
deviceType: widget.deviceType, active: widget.active);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var devicesList = DevicesList(tbContext, _deviceQueryController, searchMode: widget.searchMode, displayDeviceImage: widget.deviceType == null);
|
||||
var devicesList = DevicesList(tbContext, _deviceQueryController,
|
||||
searchMode: widget.searchMode,
|
||||
displayDeviceImage: widget.deviceType == null);
|
||||
PreferredSizeWidget appBar;
|
||||
if (widget.searchMode) {
|
||||
appBar = TbAppSearchBar(
|
||||
tbContext,
|
||||
onSearch: (searchText) => _deviceQueryController.onSearchText(searchText),
|
||||
onSearch: (searchText) =>
|
||||
_deviceQueryController.onSearchText(searchText),
|
||||
);
|
||||
} else {
|
||||
String titleText = widget.deviceType != null ? widget.deviceType! : 'All devices';
|
||||
String titleText =
|
||||
widget.deviceType != null ? widget.deviceType! : 'All devices';
|
||||
String? subTitleText;
|
||||
if (widget.active != null) {
|
||||
subTitleText = widget.active == true ? 'Active' : 'Inactive';
|
||||
}
|
||||
Column title = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(titleText, style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: subTitleText != null ? 16 : 20,
|
||||
height: subTitleText != null ? 20 / 16 : 24 / 20
|
||||
)),
|
||||
if (subTitleText != null)
|
||||
Text(subTitleText, style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.headline6!.color!.withAlpha((0.38 * 255).ceil()),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
height: 16 / 12
|
||||
))
|
||||
]
|
||||
);
|
||||
Column title =
|
||||
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Text(titleText,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: subTitleText != null ? 16 : 20,
|
||||
height: subTitleText != null ? 20 / 16 : 24 / 20)),
|
||||
if (subTitleText != null)
|
||||
Text(subTitleText,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline6!
|
||||
.color!
|
||||
.withAlpha((0.38 * 255).ceil()),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
height: 16 / 12))
|
||||
]);
|
||||
|
||||
appBar = TbAppBar(
|
||||
tbContext,
|
||||
title: title,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.search
|
||||
),
|
||||
onPressed: () {
|
||||
List<String> params = [];
|
||||
params.add('search=true');
|
||||
if (widget.deviceType != null) {
|
||||
params.add('deviceType=${widget.deviceType}');
|
||||
}
|
||||
if (widget.active != null) {
|
||||
params.add('active=${widget.active}');
|
||||
}
|
||||
navigateTo('/deviceList?${params.join('&')}');
|
||||
},
|
||||
)
|
||||
]);
|
||||
appBar = TbAppBar(tbContext, title: title, actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.search),
|
||||
onPressed: () {
|
||||
List<String> params = [];
|
||||
params.add('search=true');
|
||||
if (widget.deviceType != null) {
|
||||
params.add('deviceType=${widget.deviceType}');
|
||||
}
|
||||
if (widget.active != null) {
|
||||
params.add('active=${widget.active}');
|
||||
}
|
||||
navigateTo('/deviceList?${params.join('&')}');
|
||||
},
|
||||
)
|
||||
]);
|
||||
}
|
||||
return Scaffold(
|
||||
appBar: appBar,
|
||||
body: devicesList
|
||||
);
|
||||
return Scaffold(appBar: appBar, body: devicesList);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -94,5 +92,4 @@ class _DevicesListPageState extends TbPageState<DevicesListPage> {
|
||||
_deviceQueryController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@ import 'package:thingsboard_app/core/entity/entities_list_widget.dart';
|
||||
import 'package:thingsboard_app/modules/device/devices_base.dart';
|
||||
import 'package:thingsboard_client/thingsboard_client.dart';
|
||||
|
||||
class DevicesListWidget extends EntitiesListWidget<EntityData, EntityDataQuery> with DevicesBase {
|
||||
|
||||
DevicesListWidget(TbContext tbContext, {EntitiesListWidgetController? controller}): super(tbContext, controller: controller);
|
||||
class DevicesListWidget extends EntitiesListWidget<EntityData, EntityDataQuery>
|
||||
with DevicesBase {
|
||||
DevicesListWidget(TbContext tbContext,
|
||||
{EntitiesListWidgetController? controller})
|
||||
: super(tbContext, controller: controller);
|
||||
|
||||
@override
|
||||
void onViewAll() {
|
||||
@@ -14,6 +16,6 @@ class DevicesListWidget extends EntitiesListWidget<EntityData, EntityDataQuery>
|
||||
}
|
||||
|
||||
@override
|
||||
PageKeyController<EntityDataQuery> createPageKeyController() => DeviceQueryController(pageSize: 5);
|
||||
|
||||
PageKeyController<EntityDataQuery> createPageKeyController() =>
|
||||
DeviceQueryController(pageSize: 5);
|
||||
}
|
||||
|
||||
@@ -6,16 +6,14 @@ import 'package:thingsboard_app/modules/device/device_profiles_grid.dart';
|
||||
import 'package:thingsboard_app/widgets/tb_app_bar.dart';
|
||||
|
||||
class DevicesMainPage extends TbContextWidget {
|
||||
|
||||
DevicesMainPage(TbContext tbContext) : super(tbContext);
|
||||
|
||||
@override
|
||||
_DevicesMainPageState createState() => _DevicesMainPageState();
|
||||
|
||||
}
|
||||
|
||||
class _DevicesMainPageState extends TbContextState<DevicesMainPage> with AutomaticKeepAliveClientMixin<DevicesMainPage> {
|
||||
|
||||
class _DevicesMainPageState extends TbContextState<DevicesMainPage>
|
||||
with AutomaticKeepAliveClientMixin<DevicesMainPage> {
|
||||
final PageLinkController _pageLinkController = PageLinkController();
|
||||
|
||||
@override
|
||||
@@ -28,12 +26,8 @@ class _DevicesMainPageState extends TbContextState<DevicesMainPage> with Automat
|
||||
super.build(context);
|
||||
var deviceProfilesList = DeviceProfilesGrid(tbContext, _pageLinkController);
|
||||
return Scaffold(
|
||||
appBar: TbAppBar(
|
||||
tbContext,
|
||||
title: Text(deviceProfilesList.title)
|
||||
),
|
||||
body: deviceProfilesList
|
||||
);
|
||||
appBar: TbAppBar(tbContext, title: Text(deviceProfilesList.title)),
|
||||
body: deviceProfilesList);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -41,5 +35,4 @@ class _DevicesMainPageState extends TbContextState<DevicesMainPage> with Automat
|
||||
_pageLinkController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,28 +6,21 @@ import 'package:thingsboard_app/modules/device/device_profiles_grid.dart';
|
||||
import 'package:thingsboard_app/widgets/tb_app_bar.dart';
|
||||
|
||||
class DevicesPage extends TbPageWidget {
|
||||
|
||||
DevicesPage(TbContext tbContext) : super(tbContext);
|
||||
|
||||
@override
|
||||
_DevicesPageState createState() => _DevicesPageState();
|
||||
|
||||
}
|
||||
|
||||
class _DevicesPageState extends TbPageState<DevicesPage> {
|
||||
|
||||
final PageLinkController _pageLinkController = PageLinkController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var deviceProfilesList = DeviceProfilesGrid(tbContext, _pageLinkController);
|
||||
return Scaffold(
|
||||
appBar: TbAppBar(
|
||||
tbContext,
|
||||
title: Text(deviceProfilesList.title)
|
||||
),
|
||||
body: deviceProfilesList
|
||||
);
|
||||
appBar: TbAppBar(tbContext, title: Text(deviceProfilesList.title)),
|
||||
body: deviceProfilesList);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -35,5 +28,4 @@ class _DevicesPageState extends TbPageState<DevicesPage> {
|
||||
_pageLinkController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user