feat: amd gpu (#831)

This commit is contained in:
lollipopkit🏳️‍⚧️
2025-07-28 22:26:29 +08:00
committed by GitHub
parent 682a6e4f2d
commit 8d597294a4
7 changed files with 759 additions and 67 deletions

View File

@@ -1,7 +1,7 @@
part of 'view.dart';
extension on _ServerDetailPageState {
void _onTapGpuItem(NvidiaSmiItem item) {
void _onTapNvidiaGpuItem(NvidiaSmiItem item) {
final processes = item.memory.processes;
final displayCount = processes.length > 5 ? 5 : processes.length;
final height = displayCount * 47.0;
@@ -19,6 +19,24 @@ extension on _ServerDetailPageState {
);
}
void _onTapAmdGpuItem(AmdSmiItem item) {
final processes = item.memory.processes;
final displayCount = processes.length > 5 ? 5 : processes.length;
final height = displayCount * 47.0;
context.showRoundDialog(
title: item.name,
child: SizedBox(
width: double.maxFinite,
height: height,
child: ListView.builder(
itemCount: processes.length,
itemBuilder: (_, idx) => _buildAmdGpuProcessItem(processes[idx]),
),
),
actions: Btnx.oks,
);
}
void _onTapGpuProcessItem(NvidiaSmiMemProcess process) {
context.showRoundDialog(
title: '${process.pid}',
@@ -37,6 +55,24 @@ extension on _ServerDetailPageState {
);
}
void _onTapAmdGpuProcessItem(AmdSmiMemProcess process) {
context.showRoundDialog(
title: '${process.pid}',
titleMaxLines: 1,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
UIs.height13,
Text('Memory: ${process.memory} ${process.memory > 1024 ? 'MB' : 'KB'}'),
UIs.height13,
Text('Process: ${process.name}'),
],
),
actions: [TextButton(onPressed: () => context.pop(), child: Text(libL10n.close))],
);
}
void _onTapCustomItem(MapEntry<String, String> cmd) {
context.showRoundDialog(
title: cmd.key,

View File

@@ -8,6 +8,7 @@ import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/core/route.dart';
import 'package:server_box/data/model/app/server_detail_card.dart';
import 'package:server_box/data/model/app/shell_func.dart';
import 'package:server_box/data/model/server/amd.dart';
import 'package:server_box/data/model/server/battery.dart';
import 'package:server_box/data/model/server/cpu.dart';
import 'package:server_box/data/model/server/disk.dart';
@@ -410,9 +411,23 @@ class _ServerDetailPageState extends State<ServerDetailPage> with SingleTickerPr
Widget? _buildGpuView(Server si) {
final ss = si.status;
if (ss.nvidia == null || ss.nvidia?.isEmpty == true) return null;
final hasNvidia = ss.nvidia != null && ss.nvidia!.isNotEmpty;
final hasAmd = ss.amd != null && ss.amd!.isNotEmpty;
if (!hasNvidia && !hasAmd) return null;
final children = <Widget>[];
// Add NVIDIA GPUs
if (hasNvidia) {
children.addAll(ss.nvidia!.map((e) => _buildNvidiaGpuItem(e)));
}
// Add AMD GPUs
if (hasAmd) {
children.addAll(ss.amd!.map((e) => _buildAmdGpuItem(e)));
}
final children = ss.nvidia?.map((e) => _buildGpuItem(e)).toList() ?? [];
return ExpandTile(
title: const Text('GPU'),
leading: const Icon(Icons.memory, size: 17),
@@ -421,7 +436,7 @@ class _ServerDetailPageState extends State<ServerDetailPage> with SingleTickerPr
).cardx;
}
Widget _buildGpuItem(NvidiaSmiItem item) {
Widget _buildNvidiaGpuItem(NvidiaSmiItem item) {
final mem = item.memory;
return ListTile(
title: Text(item.name, style: UIs.text13),
@@ -441,7 +456,36 @@ class _ServerDetailPageState extends State<ServerDetailPage> with SingleTickerPr
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
IconButton(onPressed: () => _onTapGpuItem(item), icon: const Icon(Icons.info_outline, size: 17)),
IconButton(
onPressed: () => _onTapNvidiaGpuItem(item),
icon: const Icon(Icons.info_outline, size: 17),
),
],
),
);
}
Widget _buildAmdGpuItem(AmdSmiItem item) {
final mem = item.memory;
return ListTile(
title: Text('${item.name} (AMD)', style: UIs.text13),
leading: Text(
'${item.utilization}%\n${item.temp} °C',
style: UIs.text12Grey,
textScaler: _textFactor,
textAlign: TextAlign.center,
),
subtitle: Text(
'${item.power} - FAN ${item.fanSpeed} RPM\n${item.clockSpeed} MHz\n${mem.used} / ${mem.total} ${mem.unit}',
style: UIs.text12Grey,
textScaler: _textFactor,
),
contentPadding: const EdgeInsets.only(left: 17, right: 17),
trailing: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
IconButton(onPressed: () => _onTapAmdGpuItem(item), icon: const Icon(Icons.info_outline, size: 17)),
],
),
);
@@ -468,6 +512,27 @@ class _ServerDetailPageState extends State<ServerDetailPage> with SingleTickerPr
);
}
Widget _buildAmdGpuProcessItem(AmdSmiMemProcess process) {
return ListTile(
title: Text(
process.name,
style: UIs.text12,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textScaler: _textFactor,
),
subtitle: Text(
'PID: ${process.pid} - ${process.memory} MiB',
style: UIs.text12Grey,
textScaler: _textFactor,
),
trailing: InkWell(
onTap: () => _onTapAmdGpuProcessItem(process),
child: const Icon(Icons.info_outline, size: 17),
),
);
}
Widget? _buildDiskView(Server si) {
final ss = si.status;
final children = <Widget>[];
@@ -646,7 +711,9 @@ class _ServerDetailPageState extends State<ServerDetailPage> with SingleTickerPr
if (smart.model != null) details.add('Model: ${smart.model}');
if (smart.serial != null) details.add('Serial: ${smart.serial}');
if (smart.temperature != null) details.add('Temperature: ${smart.temperature!.toStringAsFixed(1)}°C');
if (smart.temperature != null) {
details.add('Temperature: ${smart.temperature!.toStringAsFixed(1)}°C');
}
if (smart.powerOnHours != null) {
details.add('Power On: ${smart.powerOnHours} ${libL10n.hour}');