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

Info page #32

Merged
merged 24 commits into from Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
)
)
);
}
}