Skip to content

Commit

Permalink
Info page (#32)
Browse files Browse the repository at this point in the history
* Wip info page

* Update linux_system_info to 0.0.6

* Add useful packages

* Clean single_info_row code

* Add many missing infos

- Gpu name
- Hostname
- OS type
- Gnome version
- Window server

* Move to model

* Get gpu name

* Get disk capacity

* Move hostname to new top section

* Make hostname editable

* Drop unused file

* Make text selectable

* Move formating out of model

* Make init tasks asynchronous

* Move info class call to constructor

* Use int for numbers

* Fix terminology

* Use SafeChangeNotifier

* Format files

* Revert sdk version
  • Loading branch information
Jupi007 committed Sep 20, 2021
1 parent 22eeed8 commit dc10a11
Show file tree
Hide file tree
Showing 6 changed files with 667 additions and 2 deletions.
76 changes: 76 additions & 0 deletions lib/view/pages/info/info_model.dart
@@ -0,0 +1,76 @@
import 'dart:ffi';
import 'dart:io';

import 'package:linux_system_info/linux_system_info.dart';
import 'package:safe_change_notifier/safe_change_notifier.dart';
import 'package:udisks/udisks.dart';

import 'hostname_service.dart';

class InfoModel extends SafeChangeNotifier {
InfoModel(
[HostnameService? hostnameService,
UDisksClient? uDisksClient,
List<Cpu>? cpus,
SystemInfo? systemInfo,
MemInfo? memInfo,
GnomeInfo? gnomeInfo])
: _hostnameService = hostnameService ?? HostnameService(),
_uDisksClient = uDisksClient ?? UDisksClient(),
_cpus = cpus ?? CpuInfo.getProcessors(),
_systemInfo = systemInfo ?? SystemInfo(),
_memInfo = memInfo ?? MemInfo(),
_gnomeInfo = gnomeInfo ?? GnomeInfo();

final HostnameService _hostnameService;
final UDisksClient _uDisksClient;
final List<Cpu> _cpus;
final SystemInfo _systemInfo;
final MemInfo _memInfo;
final GnomeInfo _gnomeInfo;

String _gpuName = '';
int? _diskCapacity;

Future<void> init() async {
await _hostnameService.init();

await GpuInfo.load().then((gpus) {
_gpuName = gpus.first.model;
});

await _uDisksClient.connect().then((value) {
_diskCapacity =
_uDisksClient.drives.fold<int>(0, (sum, drive) => sum + drive.size);
});

notifyListeners();
}

String get hostname => _hostnameService.hostname;
String get staticHostname => _hostnameService.staticHostname;

void setHostname(String hostname) {
_hostnameService.setHostname(hostname).then((_) => notifyListeners());
}

String get osName => _systemInfo.os_name;
String get osVersion => _systemInfo.os_version;
int get osType => sizeOf<IntPtr>() * 8;

String get processorName => _cpus[0].model_name;
int get processorCount => _cpus.length + 1;
int get memory => _memInfo.mem_total_gb;
String get graphics => _gpuName;
int? get diskCapacity => _diskCapacity;

String get gnomeVersion => _gnomeInfo.version;
String get windowServer => Platform.environment['XDG_SESSION_TYPE'] ?? '';

@override
void dispose() {
_hostnameService.dispose();
_uDisksClient.close();
super.dispose();
}
}
173 changes: 173 additions & 0 deletions lib/view/pages/info/info_page.dart
@@ -0,0 +1,173 @@
import 'package:filesize/filesize.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:settings/view/widgets/settings_row.dart';
import 'package:settings/view/widgets/settings_section.dart';
import 'package:settings/view/widgets/single_info_row.dart';
import 'package:yaru_icons/widgets/yaru_icons.dart';
import 'package:yaru/yaru.dart' as yaru;

import 'info_model.dart';

class InfoPage extends StatefulWidget {
const InfoPage({Key? key}) : super(key: key);

@override
_InfoPageState createState() => _InfoPageState();
}

class _InfoPageState extends State<InfoPage> {
@override
void initState() {
super.initState();

final model = context.read<InfoModel>();
model.init();
}

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

return Column(
children: [
const Icon(YaruIcons.ubuntu_logo, size: 128, color: yaru.Colors.orange),
const SizedBox(height: 10),
Text('${model.osName} ${model.osVersion}',
style: Theme.of(context).textTheme.headline5),
const SizedBox(height: 30),
const _Computer(),
SettingsSection(headline: 'Hardware', children: [
SingleInfoRow(
infoLabel: 'Processor',
infoValue: '${model.processorName} x ${model.processorCount}',
),
SingleInfoRow(
infoLabel: 'Memory',
infoValue: '${model.memory} Gb',
),
SingleInfoRow(
infoLabel: 'Graphics',
infoValue: model.graphics,
),
SingleInfoRow(
infoLabel: 'Disk Capacity',
infoValue:
model.diskCapacity != null ? filesize(model.diskCapacity) : '',
),
]),
SettingsSection(headline: 'System', children: [
SingleInfoRow(
infoLabel: 'OS name',
infoValue: '${model.osName} ${model.osVersion}',
),
SingleInfoRow(
infoLabel: 'OS type',
infoValue: '${model.osType}-bit',
),
SingleInfoRow(
infoLabel: 'GNOME version',
infoValue: model.gnomeVersion,
),
SingleInfoRow(
infoLabel: 'Windowing System',
infoValue: model.windowServer,
),
]),
],
);
}
}

class _Computer extends StatelessWidget {
const _Computer({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
final model = Provider.of<InfoModel>(context);

return SettingsSection(headline: 'Computer', children: [
SettingsRow(
actionLabel: 'Hostname',
secondChild: Row(
children: [
SelectableText(
model.hostname,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface.withAlpha(150),
),
),
const SizedBox(width: 16.0),
SizedBox(
width: 40,
height: 40,
child: OutlinedButton(
style:
OutlinedButton.styleFrom(padding: const EdgeInsets.all(0)),
onPressed: () => showDialog(
context: context,
builder: (_) => ChangeNotifierProvider.value(
value: model,
child: const _HostnameSettings(),
),
),
child: const Icon(YaruIcons.settings),
),
),
],
),
)
]);
}
}

class _HostnameSettings extends StatefulWidget {
const _HostnameSettings({Key? key}) : super(key: key);

@override
State<_HostnameSettings> createState() => _HostnameSettingsState();
}

class _HostnameSettingsState extends State<_HostnameSettings> {
final _controller = TextEditingController();

@override
void initState() {
super.initState();

final model = context.read<InfoModel>();
_controller.value = TextEditingValue(
text: model.hostname,
selection: TextSelection.collapsed(offset: model.hostname.length),
);
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final model = context.watch<InfoModel>();
return SimpleDialog(
title: const Center(child: Text('Edit hostname')),
contentPadding: const EdgeInsets.all(16.0),
children: [
TextField(controller: _controller),
const SizedBox(height: 16.0),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => model.setHostname(_controller.value.text),
child: const Text('Rename'),
)
],
)
],
);
}
}
9 changes: 7 additions & 2 deletions lib/view/pages/menu_items.dart
Expand Up @@ -5,6 +5,8 @@ import 'package:settings/view/pages/accessibility/accessibility_model.dart';
import 'package:settings/view/pages/accessibility/accessibility_page.dart';
import 'package:settings/view/pages/appearance/appearance_model.dart';
import 'package:settings/view/pages/appearance/appearance_page.dart';
import 'package:settings/view/pages/info/info_model.dart';
import 'package:settings/view/pages/info/info_page.dart';
import 'package:settings/view/pages/keyboard_shortcuts_page/keyboard_shortcuts_page.dart';
import 'package:settings/view/pages/mouse_and_touchpad/mouse_and_touchpad_model.dart';
import 'package:settings/view/pages/mouse_and_touchpad/mouse_and_touchpad_page.dart';
Expand Down Expand Up @@ -151,9 +153,12 @@ final menuItems = <MenuItem>[
iconData: YaruIcons.clock,
details: Text('Date and time'),
),
const MenuItem(
MenuItem(
name: 'Info',
iconData: YaruIcons.information,
details: Text('Info'),
details: ChangeNotifierProvider<InfoModel>(
create: (_) => InfoModel(),
child: const InfoPage(),
)
),
];
29 changes: 29 additions & 0 deletions lib/view/widgets/single_info_row.dart
@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';

import 'settings_row.dart';

class SingleInfoRow extends StatelessWidget {
final String infoLabel;
final String infoValue;

const SingleInfoRow(
{Key? key, required this.infoLabel, required this.infoValue})
: super(key: key);

@override
Widget build(BuildContext context) {
return SettingsRow(
actionLabel: infoLabel,
secondChild: Expanded(
flex: 2,
child: SelectableText(
infoValue,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface.withAlpha(150),
),
textAlign: TextAlign.right
)
)
);
}
}

0 comments on commit dc10a11

Please sign in to comment.