add a preview if longpressing preview

This commit is contained in:
lukas-heiligenbrunner 2022-08-21 22:44:12 +02:00
parent 51b4d4b38d
commit 74e2afee98
10 changed files with 161 additions and 85 deletions

View File

@ -4,6 +4,7 @@
<application <application
android:label="openmediacentermobile" android:label="openmediacentermobile"
android:name="${applicationName}" android:name="${applicationName}"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -3,12 +3,10 @@ import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:openmediacentermobile/api/token.dart'; import 'package:openmediacentermobile/api/token.dart';
import 'package:openmediacentermobile/log/log.dart';
class API { class API {
static Future<String> query( static Future<String> query(
String apinode, String action, Object payload) async { String apinode, String action, Object payload) async {
final Completer<String> cmpl = Completer();
final t = await Token.getInstance().getToken(); final t = await Token.getInstance().getToken();
if (t != null) { if (t != null) {
final resp = await http.post( final resp = await http.post(
@ -20,11 +18,9 @@ class API {
body: jsonEncode(payload), body: jsonEncode(payload),
); );
cmpl.complete(resp.body); return resp.body;
} else { } else {
cmpl.complete(""); return "";
} }
return cmpl.future;
} }
} }

View File

@ -21,7 +21,7 @@ class _LoginScreenState extends State<LoginScreen> {
Future<String> login(String password, String domain) async { Future<String> login(String password, String domain) async {
Log.i("logging in..."); Log.i("logging in...");
final compl = Completer<String>(); // final compl = Completer<String>();
final resp = await http.post( final resp = await http.post(
Uri.parse(domain + '/api/login/login'), Uri.parse(domain + '/api/login/login'),
headers: <String, String>{ headers: <String, String>{
@ -33,7 +33,9 @@ class _LoginScreenState extends State<LoginScreen> {
); );
if (resp.statusCode != 200) { if (resp.statusCode != 200) {
compl.complete(resp.body); return resp.body;
// compl.complete(resp.body);
} else { } else {
final json = jsonDecode(resp.body); final json = jsonDecode(resp.body);
final token = json["Token"]; final token = json["Token"];
@ -41,12 +43,14 @@ class _LoginScreenState extends State<LoginScreen> {
Token.getInstance().setToken(token, domain); Token.getInstance().setToken(token, domain);
LoginContext.of(context).onLoggin(true); LoginContext.of(context).onLoggin(true);
compl.complete(""); return "";
// compl.complete("");
} }
// LoginContext.of(context).onLoggin(true); // LoginContext.of(context).onLoggin(true);
return compl.future; // return compl.future;
} }
@override @override

99
lib/preview_grid.dart Normal file
View File

@ -0,0 +1,99 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:openmediacentermobile/platform.dart';
import 'package:openmediacentermobile/preview_tile.dart';
class PreviewGrid extends StatefulWidget {
const PreviewGrid({Key? key, required this.videoLoader}) : super(key: key);
final Future<List<VideoT>> Function() videoLoader;
@override
State<PreviewGrid> createState() => _PreviewGridState();
}
class _PreviewGridState extends State<PreviewGrid> {
late Future<List<VideoT>> _data;
Image? _previewImage;
@override
void initState() {
super.initState();
_data = widget.videoLoader();
}
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
return FutureBuilder<List<VideoT>>(
future: _data, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<List<VideoT>> snapshot) {
if (snapshot.hasError) {
return Text("Error");
} else if (snapshot.hasData) {
return Stack(
children: [
MasonryGridView.count(
// every tile should be at max 330 pixels long...
crossAxisCount: isTV() ? width ~/ 200 : width ~/ 275,
// crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
padding: EdgeInsets.all(5),
itemBuilder: (context, index) {
return PreviewTile(
dta: snapshot.data![index],
onLongPress: (img) {
setState(() {
_previewImage = img;
});
},
onLongPressEnd: () {
setState(() {
_previewImage = null;
});
},
);
},
),
if (_previewImage != null) ...[
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 5.0,
sigmaY: 5.0,
),
child: Container(
color: Colors.white.withOpacity(0.6),
),
),
Container(
child: Center(
child: Padding(padding: EdgeInsets.symmetric(horizontal: 50),child: ClipRRect(borderRadius: BorderRadius.circular(10.0), child: _previewImage!)),
),
),
],
],
);
} else {
return Column(children: const <Widget>[
SizedBox(
width: 60,
height: 60,
child: CircularProgressIndicator(),
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
]);
}
},
);
}
}

View File

@ -1,6 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:openmediacentermobile/videoscreen_desktop.dart' import 'package:openmediacentermobile/videoscreen_desktop.dart'
if (dart.library.html) 'package:openmediacentermobile/videoscreen_web.dart' if (dart.library.html) 'package:openmediacentermobile/videoscreen_web.dart'
@ -23,8 +22,10 @@ class VideoT {
} }
class PreviewTile extends StatefulWidget { class PreviewTile extends StatefulWidget {
const PreviewTile({Key? key, required this.dta}) : super(key: key); const PreviewTile({Key? key, required this.dta, this.onLongPress, this.onLongPressEnd}) : super(key: key);
final VideoT dta; final VideoT dta;
final Function(Image img)? onLongPress;
final Function? onLongPressEnd;
@override @override
_PreviewTileState createState() => _PreviewTileState(); _PreviewTileState createState() => _PreviewTileState();
@ -80,13 +81,29 @@ class _PreviewTileState extends State<PreviewTile> {
children: [ children: [
Container( Container(
child: Column( child: Column(
children: [Text(widget.dta.title, style: TextStyle(fontSize: isTV() ? 8 : 12)), snapshot.data!], children: [
Text(
widget.dta.title,
style: TextStyle(fontSize: isTV() ? 8 : 10.5),
overflow: TextOverflow.clip,
maxLines: 1,
), ),
color: Colors.green, snapshot.data!
],
),
color: Color(0xFF6CE56F),
), ),
Positioned.fill( Positioned.fill(
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onLongPress: () {
if (widget.onLongPress != null) widget.onLongPress!(snapshot.data!);
},
onLongPressEnd: (details) {
if (widget.onLongPressEnd != null) widget.onLongPressEnd!();
},
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
@ -99,6 +116,7 @@ class _PreviewTileState extends State<PreviewTile> {
), ),
), ),
), ),
),
], ],
), ),
); );

View File

@ -51,18 +51,23 @@ class _ShuffleScreenState extends State<ShuffleScreen> {
crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330, crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330,
mainAxisSpacing: 4, mainAxisSpacing: 4,
crossAxisSpacing: 4, crossAxisSpacing: 4,
padding: EdgeInsets.all(5),
itemCount: 4, itemCount: 4,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return PreviewTile(dta: snapshot.data![index]); return PreviewTile(dta: snapshot.data![index]);
}, },
), ),
const SizedBox(height: 25,), const SizedBox(
TextButton.icon(onPressed: () { height: 25,
),
TextButton.icon(
onPressed: () {
setState(() { setState(() {
_data = loadData(); _data = loadData();
}); });
},
}, icon: const Icon(Icons.update), label: const Text("Shuffle")) icon: const Icon(Icons.update),
label: const Text("Shuffle"))
]); ]);
} else { } else {
return Column(children: const <Widget>[ return Column(children: const <Widget>[

View File

@ -2,11 +2,10 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:openmediacentermobile/api/api.dart'; import 'package:openmediacentermobile/api/api.dart';
import 'package:openmediacentermobile/preview_grid.dart';
import 'log/log.dart'; import 'log/log.dart';
import 'platform.dart';
import 'preview_tile.dart'; import 'preview_tile.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
class VideoFeed extends StatefulWidget { class VideoFeed extends StatefulWidget {
const VideoFeed({Key? key}) : super(key: key); const VideoFeed({Key? key}) : super(key: key);
@ -18,7 +17,6 @@ class VideoFeed extends StatefulWidget {
} }
class VideoFeedState extends State<VideoFeed> { class VideoFeedState extends State<VideoFeed> {
late Future<List<VideoT>> _data;
Future<List<VideoT>> loadData() async { Future<List<VideoT>> loadData() async {
final data = await API.query("video", "getMovies", {'Tag': 1, 'Sort': 0}); final data = await API.query("video", "getMovies", {'Tag': 1, 'Sort': 0});
@ -30,47 +28,11 @@ class VideoFeedState extends State<VideoFeed> {
return dta; return dta;
} }
@override
void initState() {
super.initState();
_data = loadData();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width; double width = MediaQuery.of(context).size.width;
Log.d(width); Log.d(width);
return FutureBuilder<List<VideoT>>( return PreviewGrid(videoLoader: () => loadData(),);
future: _data, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<List<VideoT>> snapshot) {
if (snapshot.hasError) {
return Text("Error");
} else if (snapshot.hasData) {
return MasonryGridView.count(
// every tile should be at max 330 pixels long...
crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
itemBuilder: (context, index) {
return PreviewTile(dta: snapshot.data![index]);
},
);
} else {
return Column(children: const <Widget>[
SizedBox(
width: 60,
height: 60,
child: CircularProgressIndicator(),
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
]);
}
},
);
} }
} }

View File

@ -53,6 +53,10 @@ class _VideoScreenState extends State<VideoScreen> {
videoPlayerController: _controller, videoPlayerController: _controller,
autoPlay: true, autoPlay: true,
looping: true, looping: true,
allowFullScreen: true,
allowMuting: true,
allowPlaybackSpeedChanging: true,
zoomAndPan: true
); );
setState(() {}); setState(() {});

View File

@ -56,7 +56,7 @@ packages:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.15.0" version: "1.16.0"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
@ -133,7 +133,7 @@ packages:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.3.0"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
@ -526,5 +526,5 @@ packages:
source: hosted source: hosted
version: "0.2.0+1" version: "0.2.0+1"
sdks: sdks:
dart: ">=2.16.0-100.0.dev <3.0.0" dart: ">=2.17.0-0 <3.0.0"
flutter: ">=2.8.0" flutter: ">=2.8.0"

View File

@ -12,19 +12,6 @@ import 'package:openmediacentermobile/main.dart';
void main() { void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async { testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
}); });
} }