]> git.proxmox.com Git - flutter/pve_flutter_frontend.git/blobdiff - lib/widgets/pve_task_log_widget.dart
tree-wide: prefer sized box for whitespace
[flutter/pve_flutter_frontend.git] / lib / widgets / pve_task_log_widget.dart
index c40952bc35a7c24ba644b48b3577bfdfdde13828..f34b73af13e42d4e6f81cb0d78f3d76f316d5164 100644 (file)
@@ -9,7 +9,7 @@ import 'package:pve_flutter_frontend/widgets/proxmox_stream_listener.dart';
 import 'package:pve_flutter_frontend/widgets/pve_task_log_expansiontile_widget.dart';
 
 class PveTaskLog extends StatefulWidget {
-  PveTaskLog({Key key}) : super(key: key);
+  const PveTaskLog({super.key});
 
   @override
   _PveTaskLogState createState() => _PveTaskLogState();
@@ -17,13 +17,13 @@ class PveTaskLog extends StatefulWidget {
 
 class _PveTaskLogState extends State<PveTaskLog> {
   final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
-  TextEditingController _userFilterController;
-  TextEditingController _typeFilterController;
+  late TextEditingController _userFilterController;
+  late TextEditingController _typeFilterController;
   @override
   void initState() {
     super.initState();
     final bloc = Provider.of<PveTaskLogBloc>(context, listen: false);
-    final state = bloc.latestState;
+    final PveTaskLogState state = bloc.latestState;
     _userFilterController = TextEditingController.fromValue(
         TextEditingValue(text: state.userFilter ?? ''));
     _typeFilterController = TextEditingController.fromValue(
@@ -36,132 +36,129 @@ class _PveTaskLogState extends State<PveTaskLog> {
     return ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
         bloc: bloc,
         builder: (context, state) {
-          if (state.tasks != null) {
-            return SafeArea(
-              child: Scaffold(
-                key: _scaffoldKey,
-                appBar: AppBar(
-                  leading: IconButton(
-                    icon: Icon(Icons.close),
-                    onPressed: () => Navigator.of(context).pop(),
-                  ),
-                  actions: <Widget>[
-                    IconButton(
-                      icon: Icon(Icons.more_vert),
-                      onPressed: () =>
-                          _scaffoldKey.currentState.openEndDrawer(),
-                    )
-                  ],
+          return SafeArea(
+            child: Scaffold(
+              key: _scaffoldKey,
+              appBar: AppBar(
+                leading: IconButton(
+                  icon: const Icon(Icons.close),
+                  onPressed: () => Navigator.of(context).pop(),
                 ),
-                endDrawer: Drawer(
-                  child: Padding(
-                    padding: const EdgeInsets.fromLTRB(16.0, 20.0, 16.0, 0),
-                    child: Column(
-                      crossAxisAlignment: CrossAxisAlignment.start,
-                      children: <Widget>[
-                        Text(
-                          'Filters',
-                          style: Theme.of(context).textTheme.headline5,
-                        ),
-                        SizedBox(
-                          height: 20,
-                        ),
-                        TextFormField(
-                          decoration: InputDecoration(
-                              labelText: 'by user',
-                              filled: true,
-                              prefixIcon: Icon(Icons.person)),
-                          onChanged: (newValue) {
-                            bloc.events.add(FilterTasksByUser(newValue));
-                            bloc.events.add(LoadTasks());
-                          },
-                          controller: _userFilterController,
-                        ),
-                        SizedBox(
-                          height: 20,
-                        ),
-                        TextFormField(
-                          decoration: InputDecoration(
-                              labelText: 'by type',
-                              filled: true,
-                              prefixIcon: Icon(Icons.description)),
-                          onChanged: (newValue) {
-                            bloc.events.add(FilterTasksByType(newValue));
-                            bloc.events.add(LoadTasks());
-                          },
-                          controller: _typeFilterController,
-                        ),
-                        SizedBox(
-                          height: 20,
-                        ),
-                        DropdownButtonFormField<String>(
-                          decoration: InputDecoration(labelText: 'Source'),
-                          value: state.source,
-                          icon: Icon(Icons.arrow_downward),
-                          iconSize: 24,
-                          elevation: 16,
-                          onChanged: (String newValue) {
-                            bloc.events.add(FilterTasksBySource(newValue));
-                            bloc.events.add(LoadTasks());
-                          },
-                          items: <String>[
-                            'all',
-                            'active',
-                            'archive',
-                          ].map<DropdownMenuItem<String>>((String value) {
-                            return DropdownMenuItem<String>(
-                              value: value,
-                              child: Container(child: Text(value)),
-                            );
-                          }).toList(),
-                        ),
-                        SizedBox(
-                          height: 20,
+                actions: <Widget>[
+                  IconButton(
+                    icon: const Icon(Icons.more_vert),
+                    onPressed: () => _scaffoldKey.currentState?.openEndDrawer(),
+                  )
+                ],
+              ),
+              endDrawer: Drawer(
+                child: Padding(
+                  padding: const EdgeInsets.fromLTRB(16.0, 20.0, 16.0, 0),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: <Widget>[
+                      Text(
+                        'Filters',
+                        style: Theme.of(context).textTheme.headlineSmall,
+                      ),
+                      const SizedBox(
+                        height: 20,
+                      ),
+                      TextFormField(
+                        decoration: const InputDecoration(
+                            labelText: 'by user',
+                            filled: true,
+                            prefixIcon: Icon(Icons.person)),
+                        onChanged: (newValue) {
+                          bloc.events.add(FilterTasksByUser(newValue));
+                          bloc.events.add(LoadTasks());
+                        },
+                        controller: _userFilterController,
+                      ),
+                      const SizedBox(
+                        height: 20,
+                      ),
+                      TextFormField(
+                        decoration: const InputDecoration(
+                            labelText: 'by type',
+                            filled: true,
+                            prefixIcon: Icon(Icons.description)),
+                        onChanged: (newValue) {
+                          bloc.events.add(FilterTasksByType(newValue));
+                          bloc.events.add(LoadTasks());
+                        },
+                        controller: _typeFilterController,
+                      ),
+                      const SizedBox(
+                        height: 20,
+                      ),
+                      DropdownButtonFormField<String>(
+                        decoration: const InputDecoration(labelText: 'Source'),
+                        value: state.source,
+                        icon: const Icon(Icons.arrow_downward),
+                        iconSize: 24,
+                        elevation: 16,
+                        onChanged: (String? newValue) {
+                          bloc.events.add(FilterTasksBySource(newValue));
+                          bloc.events.add(LoadTasks());
+                        },
+                        items: <String>[
+                          'all',
+                          'active',
+                          'archive',
+                        ].map<DropdownMenuItem<String>>((String value) {
+                          return DropdownMenuItem<String>(
+                            value: value,
+                            child: Container(child: Text(value)),
+                          );
+                        }).toList(),
+                      ),
+                      const SizedBox(
+                        height: 20,
+                      ),
+                      FormField(
+                        builder: (FormFieldState<bool> formFieldState) => Row(
+                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                          children: <Widget>[
+                            const Text("Only errors"),
+                            Checkbox(
+                              value: state.onlyErrors,
+                              onChanged: (value) {
+                                formFieldState.didChange(value);
+                                bloc.events.add(FilterTasksByError());
+                                bloc.events.add(LoadTasks());
+                              },
+                            ),
+                          ],
                         ),
-                        FormField(
-                          builder: (FormFieldState<bool> formFieldState) => Row(
-                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                            children: <Widget>[
-                              Text("Only errors"),
-                              Checkbox(
-                                value: state.onlyErrors,
-                                onChanged: (value) {
-                                  formFieldState.didChange(value);
-                                  bloc.events.add(FilterTasksByError());
-                                  bloc.events.add(LoadTasks());
-                                },
-                              ),
-                            ],
-                          ),
-                        )
-                      ],
-                    ),
+                      )
+                    ],
                   ),
                 ),
-                body: NotificationListener<ScrollNotification>(
-                  onNotification: (ScrollNotification scrollInfo) {
-                    if (scrollInfo.metrics.pixels >=
-                        (0.8 * scrollInfo.metrics.maxScrollExtent)) {
-                      if (!state.isLoading) {
-                        bloc.events.add(LoadMoreTasks());
-                      }
+              ),
+              body: NotificationListener<ScrollNotification>(
+                onNotification: (ScrollNotification scrollInfo) {
+                  if (scrollInfo.metrics.pixels >=
+                      (0.8 * scrollInfo.metrics.maxScrollExtent)) {
+                    if (!state.isLoading) {
+                      bloc.events.add(LoadMoreTasks());
                     }
-                    return false;
-                  },
-                  child: state.tasks.isNotEmpty
-                      ? ListView.builder(
-                          itemCount: state.tasks.length,
-                          itemBuilder: (context, index) => PveTaskExpansionTile(
-                            task: state.tasks[index],
-                          ),
-                        )
-                      : Center(
-                          child: Text("No tasks found"),
+                  }
+                  return false;
+                },
+                child: state.tasks.isNotEmpty
+                    ? ListView.builder(
+                        itemCount: state.tasks.length,
+                        itemBuilder: (context, index) => PveTaskExpansionTile(
+                          task: state.tasks[index],
                         ),
-                ),
+                      )
+                    : const Center(
+                        child: Text("No tasks found"),
+                      ),
               ),
-            );
-          }
+            ),
+          );
 
           return Container();
         });
@@ -173,16 +170,16 @@ class PveTaskLogScrollView extends StatefulWidget {
   final Widget jobTitle;
 
   const PveTaskLogScrollView({
-    Key key,
-    this.icon,
-    this.jobTitle,
-  }) : super(key: key);
+    super.key,
+    required this.icon,
+    required this.jobTitle,
+  });
   @override
   _PveTaskLogScrollViewState createState() => _PveTaskLogScrollViewState();
 }
 
 class _PveTaskLogScrollViewState extends State<PveTaskLogScrollView> {
-  ScrollController _scrollController = new ScrollController();
+  ScrollController _scrollController = ScrollController();
   @override
   void initState() {
     super.initState();
@@ -209,22 +206,22 @@ class _PveTaskLogScrollViewState extends State<PveTaskLogScrollView> {
               indicatorColor = Colors.red;
               statusChipColor = Colors.red.shade100;
             }
-            return Container(
+            return SizedBox(
               height: MediaQuery.of(context).size.height * 0.5,
               child: Column(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: <Widget>[
                   if (state.isBlank)
-                    Align(
+                    const Align(
                       alignment: Alignment.center,
                       child: Padding(
-                        padding: const EdgeInsets.symmetric(vertical: 8.0),
+                        padding: EdgeInsets.symmetric(vertical: 8.0),
                         child: Text("Loading log data.."),
                       ),
                     ),
                   if (!state.isBlank) ...[
                     Padding(
-                      padding: EdgeInsets.fromLTRB(0, 5, 0, 5),
+                      padding: const EdgeInsets.fromLTRB(0, 5, 0, 5),
                       child: Align(
                         alignment: Alignment.topCenter,
                         child: Container(
@@ -240,40 +237,44 @@ class _PveTaskLogScrollViewState extends State<PveTaskLogScrollView> {
                         title: AnimatedDefaultTextStyle(
                           style: Theme.of(context)
                               .textTheme
-                              .subtitle1
+                              .titleMedium!
                               .copyWith(fontWeight: FontWeight.bold),
                           duration: kThemeChangeDuration,
-                          child: widget.jobTitle ?? const SizedBox(),
+                          child: widget.jobTitle,
                         ),
                         trailing: Chip(
                           label: Text(
-                            state.status.status.name,
+                            state.status!.status.name,
                             style: TextStyle(color: indicatorColor),
                           ),
                           backgroundColor: statusChipColor,
                         ),
                       ),
-                    Divider(),
+                    const Divider(),
                     if (state.log != null)
                       Expanded(
                         child: Padding(
                           padding: const EdgeInsets.all(14.0),
                           child: ListView.builder(
                             controller: _scrollController,
-                            itemCount: state.log.lines.length,
+                            itemCount: state.log!.lines!.length,
                             itemBuilder: (context, index) {
-                              final isLast =
-                                  index == state.log.lines.length - 1;
-                              final errorLine = state.log.lines[index].lineText
-                                  .contains('ERROR');
+                              final log = state.log!.lines!;
+                              final isLast = index == log.length - 1;
+                              final errorLine =
+                                  log[index].lineText?.contains('ERROR') ??
+                                      false;
+                              final warningLine =
+                                  log[index].lineText?.contains('WARNING') ??
+                                      false;
                               return Card(
                                 color: isLast || errorLine
                                     ? indicatorColor
                                     : Colors.white,
                                 child: Padding(
-                                  padding: const EdgeInsets.all(8.0),
+                                  padding: const EdgeInsets.all(5.0),
                                   child: Text(
-                                    state.log.lines[index].lineText,
+                                    log[index].lineText ?? '<unknown>',
                                     style: TextStyle(
                                       color: isLast || errorLine
                                           ? Colors.white
@@ -297,7 +298,7 @@ class _PveTaskLogScrollViewState extends State<PveTaskLogScrollView> {
   void _scrollToBottom() {
     if (_scrollController.hasClients) {
       _scrollController.animateTo(_scrollController.position.maxScrollExtent,
-          duration: Duration(milliseconds: 50), curve: Curves.ease);
+          duration: const Duration(milliseconds: 500), curve: Curves.easeOut);
     }
   }
 }