Skip to content

Commit

Permalink
Improve logger code and fix line endings
Browse files Browse the repository at this point in the history
  • Loading branch information
Fernthedev committed Oct 30, 2022
1 parent bdfb06f commit fd274e5
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 88 deletions.
4 changes: 0 additions & 4 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import 'package:desktop_adb_file_browser/pages/browser.dart';
import 'package:desktop_adb_file_browser/pages/devices.dart';
import 'package:desktop_adb_file_browser/pages/logger.dart';
import 'package:desktop_adb_file_browser/pigeon_impl.dart';
import 'package:desktop_adb_file_browser/routes.dart';
import 'package:desktop_adb_file_browser/utils/adb.dart';
import 'package:dio/dio.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -85,7 +82,6 @@ class MyApp extends StatelessWidget {
scheme: FlexScheme.sanJuanBlue,
surfaceMode: FlexSurfaceMode.highScaffoldLowSurface,
blendLevel: 15,
appBarStyle: FlexAppBarStyle.background,
appBarOpacity: 0.90,
subThemesData: const FlexSubThemesData(
blendOnLevel: 30,
Expand Down
5 changes: 4 additions & 1 deletion lib/pages/devices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ class _DevicesPageState extends State<DevicesPage> {
return FutureBuilder(
future: _deviceListFuture,
builder: (BuildContext context, AsyncSnapshot<List<Device>?> snapshot) {
// TODO: Error handling
if (snapshot.hasError) {
return Text("Error occurred: ${snapshot.error}");
}

if (snapshot.hasData &&
snapshot.data != null &&
snapshot.connectionState == ConnectionState.done) {
Expand Down
159 changes: 114 additions & 45 deletions lib/pages/logger.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,84 @@
import 'dart:convert';
import 'dart:async';
import 'dart:io';

import 'package:desktop_adb_file_browser/utils/adb.dart';
import 'package:desktop_adb_file_browser/utils/scroll.dart';
import 'package:desktop_adb_file_browser/utils/platform.dart';
import 'package:file_selector/file_selector.dart';
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/material.dart';
import 'package:routemaster/routemaster.dart';

class LogPage extends StatelessWidget {
import '../utils/scroll.dart';

class LogPage extends StatefulWidget {
LogPage({Key? key, required String serial})
: logFuture = Adb.logcat(serial),
super(key: key);

final Future<Stream<String>> logFuture;
final scrollController = AdjustableScrollController();

@override
State<LogPage> createState() => _LogPageState();
}

class _LogPageState extends State<LogPage> {
final List<String> logs = [];
bool showLogs = false;
StreamSubscription<String>? _streamSubscription;

// Since Dart can't keep up fast enough with logcat when spammed,
// we queue the save for when the stream slows down
// which we assume is no longer spam
bool waitForSave = false;
DateTime lastStreamSend = DateTime.now();

@override
void initState() {
super.initState();
widget.logFuture.then((stream) {
try {
_streamSubscription = stream.listen((event) {
setState(() {
var newLogs = event
.split(PlatformUtils.platformFileEnding)
.where((element) => element.trim().isNotEmpty);
logs.addAll(newLogs);

if (waitForSave) {
var timeSinceSend = DateTime.now().difference(lastStreamSend);
if (timeSinceSend.inMilliseconds > 30) {
_saveLog();
waitForSave = false;
}
}

lastStreamSend = DateTime.now();
});
});
_streamSubscription?.onError((e) {
debugPrint(e);
_showError(e);
});
_streamSubscription?.onDone(() {
debugPrint("Done");
});
} catch (e) {
debugPrint(e.toString());
_showError(e.toString());
}
}).onError((error, stackTrace) {
debugPrint("Error $error");
debugPrint(stackTrace.toString());
_showError(error.toString());
});
}

@override
void dispose() {
super.dispose();
_streamSubscription?.cancel();
}

@override
Widget build(BuildContext context) {
Expand All @@ -34,67 +98,70 @@ class LogPage extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
onPressed: _saveLog,
onPressed: _queueSave,
icon: const Icon(
FluentIcons.save_28_regular,
size: 28,
)),
)
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Switch(
value: showLogs,
onChanged: (v) => setState(() {
showLogs = v;
})))
],
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: Theme.of(context).backgroundColor,
child: FutureBuilder<Stream<String>>(
future: logFuture,
builder: buildStream,
child: Visibility(
visible: showLogs,
replacement: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Padding(
padding: EdgeInsets.all(8.0),
child: CircularProgressIndicator(),
),
Text("Reading from logcat")
],
),
),
child: Container(
color: Theme.of(context).backgroundColor,
child: buildList(),
),
),
),
);
}

Widget buildStream(
BuildContext context, AsyncSnapshot<Stream<String>> snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}

return StreamBuilder<String>(
stream: snapshot.data!,
builder: buildList,
);
Future<AlertDialog?> _showError(String error) {
return showDialog<AlertDialog>(
context: context,
builder: (context) => AlertDialog(
title: const Text("Error while streaming logcat"),
content: Text(error),
actions: [
TextButton(onPressed: _queueSave, child: const Text("Save")),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text("Back"))
],
));
}

Widget buildList(BuildContext context, AsyncSnapshot<String> snapshot) {
if (!snapshot.hasData) {
Widget buildList() {
if (_streamSubscription == null) {
return const CircularProgressIndicator();
}

if (snapshot.hasError) {
showDialog<AlertDialog>(
context: context,
builder: (context) => AlertDialog(
title: const Text("Error while streaming logcat"),
content: Text(snapshot.error.toString()),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text("Back"))
],
));
}

final newString = snapshot.data;
if (newString != null) {
logs.add(newString);
}

return ListView.builder(
key: ValueKey(logs.length),
shrinkWrap: true,
controller: AdjustableScrollController(),
controller: widget.scrollController,
itemBuilder: ((context, index) => SelectableText(
logs[index],
key: ValueKey(index),
Expand All @@ -103,6 +170,10 @@ class LogPage extends StatelessWidget {
);
}

void _queueSave() {
waitForSave = true;
}

void _saveLog() async {
const String fileName = 'log.txt';
final String? path = await getSavePath(suggestedName: fileName);
Expand All @@ -112,9 +183,7 @@ class LogPage extends StatelessWidget {
var file = File(path);
var writer = file.openWrite();

String lineEnding = Platform.isWindows ? '\n\r' : '\n';

writer.writeAll(logs, lineEnding);
writer.writeAll(logs, PlatformUtils.platformFileEnding);
await writer.flush();
await writer.close();

Expand Down
16 changes: 11 additions & 5 deletions lib/utils/adb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:io';

import 'package:archive/archive_io.dart';
import 'package:async/async.dart';
import 'package:desktop_adb_file_browser/utils/platform.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
Expand Down Expand Up @@ -90,7 +91,10 @@ abstract class Adb {

var process = await Process.run(await _getAdbPath(), newArgs);
if (process.stderr != null && process.stderr.toString().isNotEmpty) {
throw process.stderr.toString();
final error = process.stderr;
debugPrint("Error $error");
debugPrintStack();
throw error.toString();
}

// if (process.exitCode != 0) throw "Process exit code was not 0!";
Expand Down Expand Up @@ -193,10 +197,12 @@ abstract class Adb {
await runAdbCommand(serialName, ["logcat", "-c"]); // flush

var result = await startAdbCommand(serialName, ["logcat"]);

return result.stdout
.transform(utf8.decoder)
.transform(const LineSplitter());

return StreamGroup.mergeBroadcast([
result.stderr.transform(utf8.decoder),
result.stdout.transform(utf8.decoder),
]);
// .transform(const LineSplitter());
}

static Future<String?> getDeviceName(String? serialName) async {
Expand Down
2 changes: 2 additions & 0 deletions lib/utils/platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import 'package:path/path.dart' as host_path;


abstract class PlatformUtils {
static String get platformFileEnding => Platform.isWindows ? '\r\n' : '\n';

/// The default directory name for Flutter's configs.
/// Configs will be written to the user's config path. If there is already a
/// file with the name `.${kConfigDir}_$name` in the user's home path, that
Expand Down
Loading

0 comments on commit fd274e5

Please sign in to comment.