diff --git a/lib/pages/home_panels/assets_panel.dart b/lib/pages/home_panels/assets_panel.dart index f011029..82c828d 100644 --- a/lib/pages/home_panels/assets_panel.dart +++ b/lib/pages/home_panels/assets_panel.dart @@ -1,8 +1,13 @@ +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:data_table_2/data_table_2.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_fast_forms/flutter_fast_forms.dart'; import 'package:get/get.dart' hide MultipartFile; +import 'package:mime/mime.dart'; +import 'package:photo_view/photo_view.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:super_drag_and_drop/super_drag_and_drop.dart'; import 'package:tuuli_api/tuuli_api.dart'; @@ -252,6 +257,95 @@ class AssetsPagePanelController extends GetxController { .toList(growable: false), ).paddingAll(8).card(color: Colors.blueGrey.shade200).expanded(), ), + ElevatedButton( + onPressed: () { + Get.dialog( + Stack( + children: [ + FutureBuilder( + future: () async { + final resp = await ApiController.to.apiClient + .getAsset(fid: e.fid); + + final respData = resp.data; + if (respData == null) { + throw Exception("No data in response"); + } + + return respData; + }(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return const CircularProgressIndicator(); + } + + if (snapshot.hasError) { + printError(info: snapshot.error.toString()); + return const Icon(Icons.error); + } + + if (snapshot.hasData && snapshot.data == null) { + return const Icon(Icons.error); + } + + final data = snapshot.data!; + final mime = lookupMimeType( + "file", + headerBytes: data, + ); + switch (mime) { + case "image/gif": + case "image/gif": + case "image/jpeg": + case "image/png": + case "image/tiff": + case "image/webp": + return PhotoView( + imageProvider: MemoryImage(data), + enablePanAlways: true, + ); + case "application/pdf": + case "application/postscript": + return const Icon(Icons.picture_as_pdf); + case "application/zip": + case "application/x-rar-compressed": + return const Icon(Icons.archive); + case "audio/x-aiff": + case "audio/x-flac": + case "audio/x-wav": + case "audio/aac": + case "audio/aac": + case "audio/weba": + case "audio/mpeg": + case "audio/mpeg": + case "audio/ogg": + return const Icon(Icons.audiotrack); + case "video/mp4": + return const Icon(Icons.movie); + case "model/gltf-binary": + case "font/woff2": + default: + return const Icon(Icons.device_unknown); + } + }, + ).center(), + Positioned( + top: 8, + right: 8, + child: Material( + color: Colors.transparent, + child: IconButton( + onPressed: () => Get.back(), + icon: const Icon(Icons.close), + ), + ), + ), + ], + ), + ); + }, + child: const Text("View asset")), ], ).constrained(width: Get.width * 0.5, height: Get.width * 0.5), actions: [ @@ -449,6 +543,7 @@ class AssetsPagePanel extends GetView { Widget get assetsPanel => Obx( () => DataTable2( columns: const [ + DataColumn2(label: Text(""), size: ColumnSize.S), DataColumn2(label: Text("ID"), size: ColumnSize.S, numeric: true), DataColumn2(label: Text("Filename"), size: ColumnSize.M), DataColumn2(label: Text("Description"), size: ColumnSize.L), @@ -467,6 +562,75 @@ class AssetsPagePanel extends GetView { }) .map((e) => DataRow2( cells: [ + DataCell( + FutureBuilder( + future: () async { + final resp = await ApiController.to.apiClient + .getAsset(fid: e.fid); + + final respData = resp.data; + if (respData == null) { + throw Exception("No data in response"); + } + + return respData; + }(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return const CircularProgressIndicator(); + } + + if (snapshot.hasError) { + printError(info: snapshot.error.toString()); + return const Icon(Icons.error); + } + + if (snapshot.hasData && snapshot.data == null) { + return const Icon(Icons.error); + } + + final data = snapshot.data!; + final mime = lookupMimeType( + "file", + headerBytes: data, + ); + switch (mime) { + case "image/gif": + case "image/gif": + case "image/jpeg": + case "image/png": + case "image/tiff": + case "image/webp": + return Image.memory(data).card( + clipBehavior: Clip.antiAlias, + ); + case "application/pdf": + case "application/postscript": + return const Icon(Icons.picture_as_pdf); + case "application/zip": + case "application/x-rar-compressed": + return const Icon(Icons.archive); + case "audio/x-aiff": + case "audio/x-flac": + case "audio/x-wav": + case "audio/aac": + case "audio/aac": + case "audio/weba": + case "audio/mpeg": + case "audio/mpeg": + case "audio/ogg": + return const Icon(Icons.audiotrack); + case "video/mp4": + return const Icon(Icons.movie); + case "model/gltf-binary": + case "font/woff2": + default: + return const Icon(Icons.device_unknown); + } + }, + ), + ), DataCell(Text(e.id.toString())), DataCell(Tooltip( message: e.name,