Compare commits

..

No commits in common. "f2c4b07154c94d609407a3249cc6a411d8c45d32" and "961312a20a6f9aaf8c2f87647132a0cdfe6e79ab" have entirely different histories.

4 changed files with 41 additions and 111 deletions

View file

@ -1,4 +1,8 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mobile_nebula/components/SpecialTextField.dart';
class ConfigTextItem extends StatelessWidget {
const ConfigTextItem(
@ -11,13 +15,14 @@ class ConfigTextItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoTextFormFieldRow(
autocorrect: false,
minLines: 3,
maxLines: 10,
placeholder: placeholder,
style: style,
controller: controller,
);
return Padding(
padding: Platform.isAndroid ? EdgeInsets.all(5) : EdgeInsets.zero,
child: SpecialTextField(
autocorrect: false,
minLines: 3,
maxLines: 10,
placeholder: placeholder,
style: style,
controller: controller));
}
}

View file

@ -5,8 +5,6 @@ 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';
@ -24,14 +22,14 @@ class SiteLogsScreen extends StatefulWidget {
}
class _SiteLogsScreenState extends State<SiteLogsScreen> {
final ScrollController controller = ScrollController();
final RefreshController refreshController = RefreshController(initialRefresh: false);
final LogsNotifier logsNotifier = LogsNotifier();
String logs = '';
ScrollController controller = ScrollController();
RefreshController refreshController = RefreshController(initialRefresh: false);
var settings = Settings();
@override
void initState() {
logsNotifier.loadLogs(logFile: widget.site.logFile);
loadLogs();
super.initState();
}
@ -51,29 +49,18 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
scrollable: SimpleScrollable.both,
scrollController: controller,
onRefresh: () async {
await logsNotifier.loadLogs(logFile: widget.site.logFile);
await loadLogs();
refreshController.refreshCompleted();
},
onLoading: () async {
await logsNotifier.loadLogs(logFile: widget.site.logFile);
await loadLogs();
refreshController.loadComplete();
},
refreshController: refreshController,
child: Container(
padding: EdgeInsets.all(5),
constraints: logBoxConstraints(context),
child: ListenableBuilder(
listenable: logsNotifier,
builder: (context, child) => SelectableText(
switch (logsNotifier.logsResult) {
Ok<String>(:var value) => value.trim(),
Error<String>(:var error) => error is LogsNotFoundException
? error.error()
: Utils.popError(context, "Error while reading logs.", error.toString()),
null => "",
},
style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14)),
)),
child: SelectableText(logs.trim(), style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14))),
bottomBar: _buildBottomBar(),
);
}
@ -156,6 +143,27 @@ 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);

View file

@ -1,31 +0,0 @@
import 'dart:io';
import 'package:flutter/widgets.dart';
import 'package:mobile_nebula/services/result.dart';
class LogsNotFoundException implements Exception {
String error() => 'No logs found. Logs will be available after starting the site for the first time.';
}
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();
}
}
}

View file

@ -1,52 +0,0 @@
/// 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)';
}