lukas-heiligenbrunner
5fc77b4abb
cache previews in sqlite db actor page outsouce different players in seperate classes
179 lines
4.6 KiB
Dart
179 lines
4.6 KiB
Dart
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:sqflite/sqflite.dart';
|
|
|
|
import '../api/api.dart';
|
|
import '../db/database.dart';
|
|
import '../log/log.dart';
|
|
import '../platform.dart';
|
|
import '../types/video.dart';
|
|
import '../video_screen/videoscreen.dart';
|
|
|
|
class PreviewTile extends StatefulWidget {
|
|
const PreviewTile(
|
|
{Key? key, required this.dta, this.onLongPress, this.onLongPressEnd})
|
|
: super(key: key);
|
|
final VideoT dta;
|
|
final Function(Image img)? onLongPress;
|
|
final Function? onLongPressEnd;
|
|
|
|
@override
|
|
_PreviewTileState createState() => _PreviewTileState();
|
|
}
|
|
|
|
class _PreviewTileState extends State<PreviewTile> {
|
|
late Future<Image> _preview;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
_preview = loadData();
|
|
Log.d("initial load of tile");
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(PreviewTile oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
if (oldWidget.dta != widget.dta) {
|
|
setState(() {
|
|
_preview = loadData();
|
|
});
|
|
Log.i("load of tile due to change");
|
|
}
|
|
}
|
|
|
|
Future<void> insert(int id, Uint8List pic) async {
|
|
await Db().db().insert(
|
|
'previews',
|
|
{'id': id, 'thumbnail': pic},
|
|
conflictAlgorithm: ConflictAlgorithm.replace,
|
|
);
|
|
}
|
|
|
|
Future<Uint8List> _fetchThumbnail(int id) async {
|
|
final base64str =
|
|
await API.query("video", "readThumbnail", {'Movieid': id});
|
|
return base64Decode(base64str.substring(23));
|
|
}
|
|
|
|
Future<Image> loadData() async {
|
|
Uint8List data;
|
|
final id = widget.dta.id;
|
|
if (kIsWeb) {
|
|
data = await _fetchThumbnail(id);
|
|
} else {
|
|
final List<Map<String, dynamic>> prev =
|
|
await Db().db().query('previews', where: "id=$id");
|
|
|
|
if (prev.isEmpty) {
|
|
data = await _fetchThumbnail(id);
|
|
insert(id, data);
|
|
Log.d("Adding $id to db");
|
|
} else {
|
|
data = prev.first["thumbnail"] as Uint8List;
|
|
Log.d("using cached preview for $id");
|
|
}
|
|
}
|
|
|
|
final img = Image.memory(
|
|
data,
|
|
width: double.infinity,
|
|
fit: BoxFit.fitWidth,
|
|
);
|
|
|
|
// precache image to avoid loading time to render image
|
|
await precacheImage(img.image, context);
|
|
|
|
return img;
|
|
}
|
|
|
|
Widget _buildLoader() {
|
|
return Column(children: const <Widget>[
|
|
SizedBox(height: 50),
|
|
SizedBox(
|
|
width: 60,
|
|
height: 60,
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
Padding(
|
|
padding: EdgeInsets.only(top: 16),
|
|
child: Text('Awaiting result...'),
|
|
),
|
|
SizedBox(height: 50),
|
|
]);
|
|
}
|
|
|
|
Widget _buildTile(Image image) {
|
|
return ClipRRect(
|
|
borderRadius: BorderRadius.circular(20.0),
|
|
child: Stack(
|
|
children: [
|
|
Container(
|
|
child: Column(
|
|
children: [
|
|
Text(
|
|
widget.dta.title,
|
|
style: TextStyle(fontSize: isTV() ? 8 : 10.5),
|
|
overflow: TextOverflow.clip,
|
|
maxLines: 1,
|
|
),
|
|
image
|
|
],
|
|
),
|
|
color: Color(0x6a94a6ff),
|
|
),
|
|
Positioned.fill(
|
|
child: Material(
|
|
color: Colors.transparent,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.translucent,
|
|
onLongPress: () {
|
|
if (widget.onLongPress != null) widget.onLongPress!(image);
|
|
},
|
|
onLongPressEnd: (details) {
|
|
if (widget.onLongPressEnd != null) widget.onLongPressEnd!();
|
|
},
|
|
child: InkWell(
|
|
onTap: () {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => VideoScreen(metaData: widget.dta),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FutureBuilder<Image>(
|
|
future: _preview, // a previously-obtained Future<String> or null
|
|
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
|
|
if (snapshot.connectionState != ConnectionState.done) {
|
|
return _buildLoader();
|
|
}
|
|
|
|
if (snapshot.hasError) {
|
|
return Text("Error");
|
|
} else if (snapshot.hasData) {
|
|
return _buildTile(snapshot.data!);
|
|
} else {
|
|
return _buildLoader();
|
|
}
|
|
},
|
|
);
|
|
}
|
|
}
|