Skip to content

Commit

Permalink
added process selection UI
Browse files Browse the repository at this point in the history
  • Loading branch information
dealnotedev committed Jun 19, 2024
1 parent eeeda79 commit 6adeaed
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 8 deletions.
4 changes: 2 additions & 2 deletions lib/process_finder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class ProcessFinder {
}

/// Returns a list of running processes on the current system.
static List<ProcessInfo> listRunningProcesses() {
static List<ProcessInfo> listRunningProcesses({int priority = 8}) {
final processes = <ProcessInfo>[];
final connected = _connect();

Expand All @@ -138,7 +138,7 @@ class ProcessFinder {
// For example, query for all the running processes
var hr = wbemServices.execQuery(
TEXT('WQL'),
TEXT('SELECT * FROM Win32_Process WHERE Priority = 8'),
TEXT('SELECT * FROM Win32_Process WHERE Priority = $priority'),
// ExecutablePath IS NOT NULL removed because apex legends
WBEM_GENERIC_FLAG_TYPE.WBEM_FLAG_FORWARD_ONLY |
WBEM_GENERIC_FLAG_TYPE.WBEM_FLAG_RETURN_IMMEDIATELY,
Expand Down
140 changes: 134 additions & 6 deletions lib/rewards/crash_process_widget.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:twitch_listener/process_finder.dart';
import 'package:twitch_listener/reward.dart';
import 'package:twitch_listener/reward_widget.dart';
import 'package:twitch_listener/themes.dart';
Expand All @@ -18,19 +22,19 @@ class CrashProcessWidget extends StatefulWidget {
class _State extends State<CrashProcessWidget> {
@override
void initState() {
_sceneNameController = TextEditingController(text: widget.action.target);
_processNameController = TextEditingController(text: widget.action.target);
widget.saveHook.addHandler(_handleSave);
super.initState();
}

@override
void dispose() {
_sceneNameController.dispose();
_processNameController.dispose();
widget.saveHook.removeHandler(_handleSave);
super.dispose();
}

late final TextEditingController _sceneNameController;
late final TextEditingController _processNameController;

@override
Widget build(BuildContext context) {
Expand All @@ -44,17 +48,37 @@ class _State extends State<CrashProcessWidget> {
Expanded(
child: TextFormField(
maxLines: 1,
controller: _sceneNameController,
controller: _processNameController,
style: const TextStyle(
fontSize: 14,
),
decoration: const DefaultInputDecoration(hintText: 'Process name'),
),
)
),
const Gap(8),
ElevatedButton(onPressed: _selectProcess, child: const Text('Select'))
])
]);
}

Future<void> _selectProcess() async {
final processName = await showModalBottomSheet<String>(
context: context,
constraints: const BoxConstraints(maxWidth: 512),
backgroundColor: const Color(0xFF404450),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(8), topLeft: Radius.circular(8)),
),
builder: (context) {
return _ProcessListWidget();
});

if (processName != null) {
_processNameController.text = processName;
}
}

@override
void didUpdateWidget(covariant CrashProcessWidget oldWidget) {
if (widget.saveHook != oldWidget.saveHook) {
Expand All @@ -65,6 +89,110 @@ class _State extends State<CrashProcessWidget> {
}

void _handleSave() {
widget.action.target = _sceneNameController.text.trim();
widget.action.target = _processNameController.text.trim();
}
}

class _ProcessListWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ProcessListState();
}

class _ProcessListState extends State<_ProcessListWidget> {
@override
void initState() {
_searchController.addListener(_handleSearchQuery);
_runTickerLoop();
super.initState();
}

bool _disposed = false;
List<String> _processes = [];

void _runTickerLoop() async {
while (true) {
if (_disposed) break;

final processes = await compute(_getRunningProcesses, 8);
if (_disposed) break;

setState(() {
_processes = processes.map((e) => e.name).toSet().toList();
_processes.sort((a, b) => a.compareTo(b));
});
}
}

@override
void dispose() {
_searchController.removeListener(_handleSearchQuery);
_searchController.dispose();
_disposed = true;
super.dispose();
}

static List<ProcessInfo> _getRunningProcesses(int priority) {
ProcessFinder.initialize();

final data = ProcessFinder.listRunningProcesses(priority: priority);
ProcessFinder.uninitialize();

return data;
}

final _searchController = TextEditingController();

@override
Widget build(BuildContext context) {
final filtered = _processes
.where((p) => _q.isEmpty || p.toLowerCase().contains(_q))
.toList();

return Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 16, left: 16, right: 16),
child: TextField(
maxLines: 1,
controller: _searchController,
style: const TextStyle(
fontSize: 14,
),
decoration:
const DefaultInputDecoration(hintText: 'Type to search...'),
),
),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.only(top: 8),
itemCount: filtered.length,
itemBuilder: (context, index) {
final info = filtered[index];
return InkWell(
onTap: () => _selectProcess(context, info),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
child: Text(
info,
style: const TextStyle(color: Colors.white),
),
),
);
}))
],
);
}

String _q = '';

void _handleSearchQuery() {
setState(() {
_q = _searchController.text.toLowerCase().trim();
});
}

_selectProcess(BuildContext contex, String info) {
Navigator.pop(context, info);
}
}

0 comments on commit 6adeaed

Please sign in to comment.