Skip to content

Commit

Permalink
Don't pop an error when there is no logs file
Browse files Browse the repository at this point in the history
  • Loading branch information
jasikpark committed Jan 31, 2025
1 parent f69f7cc commit d398814
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 28 deletions.
48 changes: 20 additions & 28 deletions lib/screens/SiteLogsScreen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:mobile_nebula/components/SimplePage.dart';
import 'package:mobile_nebula/models/Site.dart';
import 'package:mobile_nebula/services/logs.dart';
import 'package:mobile_nebula/services/result.dart';
import 'package:mobile_nebula/services/settings.dart';
import 'package:mobile_nebula/services/share.dart';
import 'package:mobile_nebula/services/utils.dart';
Expand All @@ -22,14 +24,14 @@ class SiteLogsScreen extends StatefulWidget {
}

class _SiteLogsScreenState extends State<SiteLogsScreen> {
String logs = '';
ScrollController controller = ScrollController();
RefreshController refreshController = RefreshController(initialRefresh: false);
final ScrollController controller = ScrollController();
final RefreshController refreshController = RefreshController(initialRefresh: false);
final LogsNotifier logsNotifier = LogsNotifier();

var settings = Settings();
@override
void initState() {
loadLogs();
logsNotifier.loadLogs(logFile: widget.site.logFile);
super.initState();
}

Expand All @@ -49,18 +51,29 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
scrollable: SimpleScrollable.both,
scrollController: controller,
onRefresh: () async {
await loadLogs();
await logsNotifier.loadLogs(logFile: widget.site.logFile);
refreshController.refreshCompleted();
},
onLoading: () async {
await loadLogs();
await logsNotifier.loadLogs(logFile: widget.site.logFile);
refreshController.loadComplete();
},
refreshController: refreshController,
child: Container(
padding: EdgeInsets.all(5),
constraints: logBoxConstraints(context),
child: SelectableText(logs.trim(), style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14))),
child: ListenableBuilder(
listenable: logsNotifier,
builder: (context, child) => SelectableText(
switch (logsNotifier.logsResult) {
Ok<String>(:var value) => value.trim(),
Error<String>(:var error) => error is LogsNotFoundException
? "No logs file found."
: Utils.popError(context, "Error while reading logs.", error.toString()),
null => "",
},
style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14)),
)),
bottomBar: _buildBottomBar(),
);
}
Expand Down Expand Up @@ -143,27 +156,6 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
material: (context, child, platform) => BottomAppBar(child: child));
}

loadLogs() async {
var file = File(widget.site.logFile);
try {
final v = await file.readAsString();

setState(() {
logs = v;
});
} on FileSystemException {
Utils.popError(context, 'Error while reading logs', 'No log file was present');
} catch (err) {
Utils.popError(context, 'Error while reading logs', err.toString());
}
}

deleteLogs() async {
var file = File(widget.site.logFile);
await file.writeAsBytes([]);
await loadLogs();
}

logBoxConstraints(BuildContext context) {
if (settings.logWrap) {
return BoxConstraints(maxWidth: MediaQuery.of(context).size.width);
Expand Down
31 changes: 31 additions & 0 deletions lib/services/logs.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'dart:io';

import 'package:flutter/widgets.dart';
import 'package:mobile_nebula/services/result.dart';

class LogsNotFoundException implements Exception {
String error() => 'No logs file found';
}

class LogsNotifier extends ChangeNotifier {
Result<String>? logsResult;

LogsNotifier();

loadLogs({required String logFile}) async {
final file = File(logFile);
try {
logsResult = Result.ok(await file.readAsString());
notifyListeners();
} on FileSystemException {
logsResult = Result.error(LogsNotFoundException());
notifyListeners();
} on Exception catch (err) {
logsResult = Result.error(err);
notifyListeners();
} catch (err) {
logsResult = Result.error(Exception(err));
notifyListeners();
}
}
}
52 changes: 52 additions & 0 deletions lib/services/result.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/// Utility class that simplifies handling errors.
///
/// Return a [Result] from a function to indicate success or failure.
///
/// A [Result] is either an [Ok] with a value of type [T]
/// or an [Error] with an [Exception].
///
/// Use [Result.ok] to create a successful result with a value of type [T].
/// Use [Result.error] to create an error result with an [Exception].
///
/// Evaluate the result using a switch statement:
/// ```dart
/// switch (result) {
/// case Ok(): {
/// print(result.value);
/// }
/// case Error(): {
/// print(result.error);
/// }
/// }
/// ```
sealed class Result<T> {
const Result();

/// Creates a successful [Result], completed with the specified [value].
const factory Result.ok(T value) = Ok._;

/// Creates an error [Result], completed with the specified [error].
const factory Result.error(Exception error) = Error._;
}

/// A successful [Result] with a returned [value].
final class Ok<T> extends Result<T> {
const Ok._(this.value);

/// The returned value of this result.
final T value;

@override
String toString() => 'Result<$T>.ok($value)';
}

/// An error [Result] with a resulting [error].
final class Error<T> extends Result<T> {
const Error._(this.error);

/// The resulting error of this result.
final Exception error;

@override
String toString() => 'Result<$T>.error($error)';
}

0 comments on commit d398814

Please sign in to comment.