/// Chat file tile /// /// @author Pierre Hubert import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:comunic/helpers/conversation_files_helper.dart'; import 'package:comunic/models/conversation_message.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/audio_player_widget.dart'; import 'package:comunic/ui/widgets/network_image_widget.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/log_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:dio/dio.dart'; import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; const _AreaSize = 150.0; class ConversationFileWidget extends StatefulWidget { final int messageID; final ConversationMessageFile file; const ConversationFileWidget({ Key key, @required this.messageID, @required this.file, }) : assert(messageID != null), assert(file != null), super(key: key); @override _ConversationFileWidgetState createState() => _ConversationFileWidgetState(); } class _ConversationFileWidgetState extends State { final _refreshKey = GlobalKey(); File _targetFile; bool _isDownloaded; bool _downloading = false; var _downloadProgress = 0.0; CancelToken _cancelDownloadToken; ConversationMessageFile get file => widget.file; Future _refresh() async { _targetFile = await ConversationFilesHelper.getPathForChatFile( widget.messageID, file); _isDownloaded = await _targetFile.exists(); } @override Widget build(BuildContext context) { return Container( width: _AreaSize, height: _AreaSize, child: AsyncScreenWidget( key: _refreshKey, onReload: _refresh, onBuild: _buildContent, errorMessage: tr("Error!"), ), ); } Widget _buildContent() => _isDownloaded || !file.downloadable ? _buildFileWidget() : _buildDownloadWidget(); Widget _buildDownloadWidget() => Stack( children: [ // Thumbnail, if possible !file.hasThumbnail ? Container() : CachedNetworkImage( imageUrl: file.thumbnail, width: _AreaSize, height: _AreaSize, fit: BoxFit.fill, ), Container( width: _AreaSize, color: Color(0x66000000), child: DefaultTextStyle( style: TextStyle(color: Colors.white), child: Column( children: [ Spacer(), Icon(file.icon, color: Colors.white), Spacer(), _buildDownloadArea(), Spacer(), Text(filesize(file.size)), Spacer(), ], ), ), ) ], ); Widget _buildDownloadArea() => _downloading ? _buildDownloadingWidget() : Material( borderRadius: BorderRadius.all(Radius.circular(2.0)), color: Colors.green, child: IconButton( icon: Icon(Icons.file_download), onPressed: _downloadFile, color: Colors.white, ), ); Widget _buildDownloadingWidget() => Container( width: 36, height: 36, child: Stack( children: [ CircularProgressIndicator(value: _downloadProgress), Center( child: InkWell( onTap: () => _cancelDownloadToken.cancel(), child: Icon(Icons.cancel, color: Colors.white), ), ) ], ), ); Future _downloadFile() async { try { setState(() { _cancelDownloadToken = CancelToken(); _downloading = true; _downloadProgress = 0.0; }); await ConversationFilesHelper.download( msgID: widget.messageID, fileInfo: file, onProgress: (p) => setState(() => _downloadProgress = p), cancelToken: _cancelDownloadToken, ); await _refreshKey.currentState.refresh(); } catch (e, s) { logError(e, s); showSimpleSnack(context, tr("Failed to download file!")); } setState(() { _downloading = false; }); } Widget _buildFileWidget() { switch (file.fileType) { // Images case ConversationMessageFileType.IMAGE: return Center( child: NetworkImageWidget( url: file.url, thumbnailURL: file.thumbnail, allowFullScreen: true, ), ); // Audio player case ConversationMessageFileType.AUDIO: return AudioPlayerWidget(_targetFile); // The file is not downloadable, we open it in the browser default: return Center( child: MaterialButton( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Spacer(flex: 2), Icon(file.icon, color: Colors.white), Spacer(), Text(file.name, textAlign: TextAlign.center), Spacer(flex: 2), ], ), onPressed: () => launch(file.url), ), ); break; } } }