Preview for audio and images, better asset table
This commit is contained in:
parent
a4ab10db17
commit
bce8e97368
4 changed files with 196 additions and 173 deletions
|
|
@ -1,18 +1,16 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:data_table_2/data_table_2.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:file_icon/file_icon.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';
|
||||
import 'package:tuuli_app/api_controller.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
import 'package:tuuli_app/widgets/audio_player_widget.dart';
|
||||
|
||||
class AssetsPagePanelController extends GetxController {
|
||||
@override
|
||||
|
|
@ -22,6 +20,8 @@ class AssetsPagePanelController extends GetxController {
|
|||
refreshData();
|
||||
}
|
||||
|
||||
final scrollController = ScrollController();
|
||||
|
||||
final _isLoading = false.obs;
|
||||
bool get isLoading => _isLoading.value;
|
||||
|
||||
|
|
@ -258,93 +258,7 @@ class AssetsPagePanelController extends GetxController {
|
|||
).paddingAll(8).card(color: Colors.blueGrey.shade200).expanded(),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Get.dialog(
|
||||
Stack(
|
||||
children: [
|
||||
FutureBuilder<Uint8List>(
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
onPressed: () => previewAsset(e),
|
||||
child: const Text("View asset")),
|
||||
],
|
||||
).constrained(width: Get.width * 0.5, height: Get.width * 0.5),
|
||||
|
|
@ -473,6 +387,43 @@ class AssetsPagePanelController extends GetxController {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
void previewAsset(Asset e) {
|
||||
Get.dialog(
|
||||
Stack(
|
||||
children: [
|
||||
if (e.mime.split("/").first == "image")
|
||||
PhotoView(
|
||||
imageProvider:
|
||||
NetworkImage("${ApiController.to.endPoint}/assets/${e.fid}"),
|
||||
enablePanAlways: true,
|
||||
)
|
||||
else if (e.mime.split("/").first == "audio")
|
||||
AudioPlayerWidget.create(
|
||||
title: e.name,
|
||||
url: "${ApiController.to.endPoint}/assets/${e.fid}",
|
||||
)
|
||||
else
|
||||
const Text("Unsupported media type")
|
||||
.fontSize(16)
|
||||
.paddingAll(8)
|
||||
.card()
|
||||
.center(),
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
onPressed: () => Get.back(),
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AssetsPagePanel extends GetView<AssetsPagePanelController> {
|
||||
|
|
@ -542,9 +493,9 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
|
|||
|
||||
Widget get assetsPanel => Obx(
|
||||
() => DataTable2(
|
||||
horizontalScrollController: controller.scrollController,
|
||||
columns: const [
|
||||
DataColumn2(label: Text(""), size: ColumnSize.S),
|
||||
DataColumn2(label: Text("ID"), size: ColumnSize.S, numeric: true),
|
||||
DataColumn2(label: Text(""), fixedWidth: 16),
|
||||
DataColumn2(label: Text("Filename"), size: ColumnSize.M),
|
||||
DataColumn2(label: Text("Description"), size: ColumnSize.L),
|
||||
DataColumn2(label: Text("File ID"), size: ColumnSize.M),
|
||||
|
|
@ -562,76 +513,7 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
|
|||
})
|
||||
.map((e) => DataRow2(
|
||||
cells: [
|
||||
DataCell(
|
||||
FutureBuilder<Uint8List>(
|
||||
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(FileIcon(e.name)),
|
||||
DataCell(Tooltip(
|
||||
message: e.name,
|
||||
child: Text(
|
||||
|
|
@ -665,6 +547,10 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
|
|||
),
|
||||
)),
|
||||
DataCell(Row(children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.preview),
|
||||
onPressed: () => controller.previewAsset(e),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () => controller.editAsset(e),
|
||||
|
|
|
|||
72
lib/widgets/audio_player_widget.dart
Normal file
72
lib/widgets/audio_player_widget.dart
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
class AudioPlayerWidgetController extends GetxController {
|
||||
final String title;
|
||||
final String url;
|
||||
|
||||
AudioPlayerWidgetController({
|
||||
required this.title,
|
||||
required this.url,
|
||||
});
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
player = AudioPlayer();
|
||||
player.play(UrlSource(url));
|
||||
|
||||
player.onPlayerStateChanged.listen((event) {
|
||||
_playerState.value = event;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
player.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
late AudioPlayer player;
|
||||
|
||||
final _playerState = PlayerState.stopped.obs;
|
||||
get playerState => _playerState.value;
|
||||
}
|
||||
|
||||
class AudioPlayerWidget extends GetView<AudioPlayerWidgetController> {
|
||||
const AudioPlayerWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: Obx(
|
||||
() => controller.playerState == PlayerState.playing
|
||||
? IconButton(
|
||||
onPressed: () => controller.player.pause(),
|
||||
icon: const Icon(Icons.pause),
|
||||
)
|
||||
: IconButton(
|
||||
onPressed: () => controller.player.resume(),
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
),
|
||||
),
|
||||
title: const Text("Playing"),
|
||||
subtitle: Text(controller.title),
|
||||
).card().paddingAll(16).center();
|
||||
}
|
||||
|
||||
static AudioPlayerWidget create(
|
||||
{required String url, required String title}) {
|
||||
Get.lazyPut<AudioPlayerWidgetController>(
|
||||
() => AudioPlayerWidgetController(
|
||||
title: title,
|
||||
url: url,
|
||||
),
|
||||
);
|
||||
|
||||
return const AudioPlayerWidget();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue