Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions lib/helpers/errors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ void showHttpExceptionErrorDialog(WgerHttpException exception, {BuildContext? co
return;
}

final errorList = formatErrors(extractErrors(exception.errors));
final errorList = formatApiErrors(extractErrors(exception.errors));

showDialog(
context: dialogContext,
Expand Down Expand Up @@ -104,6 +104,15 @@ void showGeneralErrorDialog(dynamic error, StackTrace? stackTrace, {BuildContext
} else if (error is SocketException) {
isNetworkError = true;
}
/*
else if (error is PlatformException) {
errorTitle = 'Problem with media';
errorMessage =
'There was a problem loading the media. This can be a e.g. problem with the codec that'
'is not supported by your device. Original error message: ${error.message}';
}

*/

final String fullStackTrace = stackTrace?.toString() ?? 'No stack trace available.';

Expand All @@ -115,13 +124,13 @@ void showGeneralErrorDialog(dynamic error, StackTrace? stackTrace, {BuildContext
builder: (BuildContext context) {
return AlertDialog(
title: Row(
spacing: 8,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
isNetworkError ? Icons.signal_wifi_connected_no_internet_4_outlined : Icons.error,
color: Theme.of(context).colorScheme.error,
),
const SizedBox(width: 8),
Expanded(
child: Text(
isNetworkError ? i18n.errorCouldNotConnectToServer : i18n.anErrorOccurred,
Expand Down Expand Up @@ -309,7 +318,7 @@ List<ApiError> extractErrors(Map<String, dynamic> errors) {
}

/// Processes the error messages from the server and returns a list of widgets
List<Widget> formatErrors(List<ApiError> errors, {Color? color}) {
List<Widget> formatApiErrors(List<ApiError> errors, {Color? color}) {
final textColor = color ?? Colors.black;

final List<Widget> errorList = [];
Expand All @@ -328,6 +337,26 @@ List<Widget> formatErrors(List<ApiError> errors, {Color? color}) {
return errorList;
}

/// Processes the error messages from the server and returns a list of widgets
List<Widget> formatTextErrors(List<String> errors, {String? title, Color? color}) {
final textColor = color ?? Colors.black;

final List<Widget> errorList = [];

if (title != null) {
errorList.add(
Text(title, style: TextStyle(fontWeight: FontWeight.bold, color: textColor)),
);
}

for (final message in errors) {
errorList.add(Text(message, style: TextStyle(color: textColor)));
}
errorList.add(const SizedBox(height: 8));

return errorList;
}

class FormHttpErrorsWidget extends StatelessWidget {
final WgerHttpException exception;

Expand All @@ -338,11 +367,32 @@ class FormHttpErrorsWidget extends StatelessWidget {
return Column(
children: [
Icon(Icons.error_outline, color: Theme.of(context).colorScheme.error),
...formatErrors(
...formatApiErrors(
extractErrors(exception.errors),
color: Theme.of(context).colorScheme.error,
),
],
);
}
}

class GeneralErrorsWidget extends StatelessWidget {
final String? title;
final List<String> widgets;

const GeneralErrorsWidget(this.widgets, {this.title, super.key});

@override
Widget build(BuildContext context) {
return Column(
children: [
Icon(Icons.error_outline, color: Theme.of(context).colorScheme.error),
...formatTextErrors(
widgets,
title: title,
color: Theme.of(context).colorScheme.error,
),
],
);
}
}
2 changes: 2 additions & 0 deletions lib/models/exercises/video.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class Video {
@JsonKey(name: 'video', required: true)
final String url;

Uri get uri => Uri.parse(url);

@JsonKey(name: 'exercise', required: true)
final int exerciseId;

Expand Down
52 changes: 38 additions & 14 deletions lib/widgets/exercises/videos.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
*/

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:logging/logging.dart';
import 'package:video_player/video_player.dart';
import 'package:wger/helpers/errors.dart';
import 'package:wger/models/exercises/video.dart';

class ExerciseVideoWidget extends StatefulWidget {
Expand All @@ -31,35 +34,56 @@ class ExerciseVideoWidget extends StatefulWidget {

class _ExerciseVideoWidgetState extends State<ExerciseVideoWidget> {
late VideoPlayerController _controller;
bool hasError = false;
final logger = Logger('ExerciseVideoWidgetState');

@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.video.url);
_controller.addListener(() {
_controller = VideoPlayerController.networkUrl(widget.video.uri);
_initializeVideo();
}

Future<void> _initializeVideo() async {
try {
await _controller.initialize();
setState(() {});
});
_controller.initialize().then((_) => setState(() {}));
} on PlatformException catch (e) {
if (mounted) {
setState(() => hasError = true);
}

logger.warning('PlatformException while initializing video: ${e.message}');
}
}

@override
void dispose() {
super.dispose();
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(alignment: Alignment.bottomCenter, children: [
VideoPlayer(_controller),
_ControlsOverlay(controller: _controller),
VideoProgressIndicator(_controller, allowScrubbing: true),
]),
return hasError
? const GeneralErrorsWidget(
[
'An error happened while loading the video. If you can, please check the application logs.'
],
)
: Container();
: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayer(_controller),
_ControlsOverlay(controller: _controller),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
)
: Container();
}
}

Expand Down