add a video page and disply tiles correctly

This commit is contained in:
lukas 2022-04-15 09:16:41 +02:00
parent baed9c23d2
commit d7184f09aa
8 changed files with 327 additions and 61 deletions

View File

@ -10,7 +10,6 @@ class API {
String apinode, String action, Object payload) async { String apinode, String action, Object payload) async {
final Completer<String> cmpl = Completer(); final Completer<String> cmpl = Completer();
final t = await Token.getInstance().getToken(); final t = await Token.getInstance().getToken();
Log.d(t);
if (t != null) { if (t != null) {
final resp = await http.post( final resp = await http.post(
Uri.parse(t.domain + '/api/$apinode/$action'), Uri.parse(t.domain + '/api/$apinode/$action'),

View File

@ -31,8 +31,11 @@ class Token {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
final token = await _storage.read(key: 'jwt'); final token = await _storage.read(key: 'jwt');
final domain = await _storage.read(key: 'domain'); final domain = await _storage.read(key: 'domain');
// check if value is defined in phone store // check if value is defined in phone store
if (token != null && domain != null) { if (token != null && domain != null) {
_tokenval = token;
_domain = domain;
completer.complete(TokenT(token, domain)); completer.complete(TokenT(token, domain));
} else { } else {
Log.d("no token defined"); Log.d("no token defined");

View File

@ -60,8 +60,7 @@ class _LoginScreenState extends State<LoginScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
image: DecorationImage( image: DecorationImage(image: AssetImage('assets/images/login.png'), fit: BoxFit.cover),
image: AssetImage('assets/images/login.png'), fit: BoxFit.cover),
), ),
child: Scaffold( child: Scaffold(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@ -76,8 +75,7 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
SingleChildScrollView( SingleChildScrollView(
child: Container( child: Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.5),
top: MediaQuery.of(context).size.height * 0.5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -88,6 +86,7 @@ class _LoginScreenState extends State<LoginScreen> {
TextField( TextField(
controller: _domainTextController, controller: _domainTextController,
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
autofocus: true,
decoration: InputDecoration( decoration: InputDecoration(
fillColor: Colors.grey.shade100, fillColor: Colors.grey.shade100,
filled: true, filled: true,
@ -103,6 +102,7 @@ class _LoginScreenState extends State<LoginScreen> {
controller: _passwordTextController, controller: _passwordTextController,
style: const TextStyle(), style: const TextStyle(),
obscureText: true, obscureText: true,
autofocus: true,
decoration: InputDecoration( decoration: InputDecoration(
fillColor: Colors.grey.shade100, fillColor: Colors.grey.shade100,
filled: true, filled: true,
@ -119,8 +119,7 @@ class _LoginScreenState extends State<LoginScreen> {
children: [ children: [
const Text( const Text(
'Sign in', 'Sign in',
style: TextStyle( style: TextStyle(fontSize: 27, fontWeight: FontWeight.w700),
fontSize: 27, fontWeight: FontWeight.w700),
), ),
CircleAvatar( CircleAvatar(
radius: 30, radius: 30,
@ -128,10 +127,9 @@ class _LoginScreenState extends State<LoginScreen> {
child: IconButton( child: IconButton(
color: Colors.white, color: Colors.white,
onPressed: () { onPressed: () {
final pwd = Log.d("clickkked");
_passwordTextController.value.text; final pwd = _passwordTextController.value.text;
final domain = final domain = _domainTextController.value.text;
_domainTextController.value.text;
login(pwd, domain).then((value) { login(pwd, domain).then((value) {
if (value != "") { if (value != "") {
setState(() { setState(() {

View File

@ -1,11 +1,36 @@
import "package:dart_vlc/dart_vlc.dart";
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:openmediacentermobile/app.dart'; import 'package:openmediacentermobile/app.dart';
import 'log/log.dart'; import 'log/log.dart';
import 'login/logincontext.dart'; import 'login/logincontext.dart';
import 'platform.dart';
// main app entry point // main app entry point
void main() { void main() async {
Log.i("App init!"); Log.i("App init!");
runApp(const LoginContainer(child: App())); if (isDesktop()) {
DartVLC.initialize();
} else {
await loadDeviceInfo();
}
// RawKeyboard.instance.addListener((event) {
// if (LogicalKeyboardKey.arrowLeft == event.logicalKey) {
// FocusManager.instance.primaryFocus?.focusInDirection(TraversalDirection.left);
// } else if (LogicalKeyboardKey.arrowRight == event.logicalKey) {
// FocusManager.instance.primaryFocus?.focusInDirection(TraversalDirection.right);
// } else if (LogicalKeyboardKey.arrowDown == event.logicalKey) {
// FocusManager.instance.primaryFocus?.focusInDirection(TraversalDirection.down);
// } else if (LogicalKeyboardKey.arrowUp == event.logicalKey) {
// FocusManager.instance.primaryFocus?.focusInDirection(TraversalDirection.up);
// }
// });
runApp(Shortcuts(shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.select): ActivateIntent(),
}, child: const LoginContainer(child: App())));
// runApp(const LoginContainer(child: App()));
} }

View File

@ -1,8 +1,10 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:openmediacentermobile/videoscreen.dart';
import 'api/api.dart'; import 'api/api.dart';
import 'platform.dart';
class VideoT { class VideoT {
int id; int id;
@ -12,8 +14,7 @@ class VideoT {
VideoT(this.title, this.id, this.Ratio); VideoT(this.title, this.id, this.Ratio);
factory VideoT.fromJson(dynamic json) { factory VideoT.fromJson(dynamic json) {
return VideoT(json['MovieName'] as String, json['MovieId'] as int, return VideoT(json['MovieName'] as String, json['MovieId'] as int, (json['Ratio'] as num).toDouble());
(json['Ratio'] as num).toDouble());
} }
} }
@ -26,31 +27,82 @@ class PreviewTile extends StatefulWidget {
} }
class _PreviewTileState extends State<PreviewTile> { class _PreviewTileState extends State<PreviewTile> {
String prev = ""; late Future<Image> _preview;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
API.query("video", "readThumbnail", {'Movieid': widget.dta.id}).then( _preview = loadData();
(value) { }
setState(() {
prev = value.substring(23); Future<Image> loadData() async {
}); final data = await API.query("video", "readThumbnail", {'Movieid': widget.dta.id});
});
final img = Image.memory(
base64Decode(data.substring(23)),
width: double.infinity,
fit: BoxFit.fitWidth,
);
// precache image to avoid loading time to render image
await precacheImage(img.image, context);
return img;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InkWell( return FutureBuilder<Image>(
child: Column( future: _preview, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
if (snapshot.hasError) {
return Text("Error");
} else if (snapshot.hasData) {
return ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Stack(
children: [ children: [
Text(widget.dta.title), Container(
prev != "" child: Column(
? Image.memory(base64Decode(prev)) children: [Text(widget.dta.title, style: TextStyle(fontSize: isTV() ? 8 : 12)), snapshot.data!],
: const CircularProgressIndicator() ),
color: Colors.green,
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoScreen(videoID: widget.dta.id),
),
);
},
),
),
),
], ],
), ),
); );
} else {
return Column(children: const <Widget>[
SizedBox(height: 100),
SizedBox(
width: 60,
height: 60,
child: CircularProgressIndicator(),
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
),
SizedBox(height: 100),
]);
}
},
);
} }
} }

View File

@ -4,7 +4,9 @@ import 'package:flutter/material.dart';
import 'package:openmediacentermobile/api/api.dart'; import 'package:openmediacentermobile/api/api.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);
@ -16,36 +18,59 @@ class VideoFeed extends StatefulWidget {
} }
class VideoFeedState extends State<VideoFeed> { class VideoFeedState extends State<VideoFeed> {
List<VideoT> _vids = []; late Future<List<VideoT>> _data;
Future<List<VideoT>> loadData() async {
final data = await API.query("video", "getMovies", {'Tag': 1, 'Sort': 0});
final d = jsonDecode(data);
List<VideoT> dta = (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList();
return dta;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
API.query("video", "getMovies", {'Tag': 1, 'Sort': 0}).then((value) { _data = loadData();
final d = jsonDecode(value);
List<VideoT> dta =
(d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList();
setState(() {
_vids = dta;
});
});
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GridView.builder( double width = MediaQuery.of(context).size.width;
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( Log.d(width);
crossAxisCount: 2,
childAspectRatio: MediaQuery.of(context).size.width / return FutureBuilder<List<VideoT>>(
MediaQuery.of(context).size.height, future: _data, // a previously-obtained Future<String> or null
crossAxisSpacing: 10), builder: (BuildContext context, AsyncSnapshot<List<VideoT>> snapshot) {
itemCount: _vids.length, 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) { itemBuilder: (context, index) {
Log.d("item $index built!"); return PreviewTile(dta: snapshot.data![index]);
return PreviewTile(dta: _vids[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

@ -8,6 +8,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.8.2" version: "2.8.2"
audio_video_progress_bar:
dependency: transitive
description:
name: audio_video_progress_bar
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -50,6 +57,62 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
dart_vlc:
dependency: "direct main"
description:
name: dart_vlc
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.9"
dart_vlc_ffi:
dependency: transitive
description:
name: dart_vlc_ffi
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5+1"
device_info_plus:
dependency: "direct main"
description:
name: device_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.3"
device_info_plus_linux:
dependency: transitive
description:
name: device_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
device_info_plus_macos:
dependency: transitive
description:
name: device_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.3"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0+1"
device_info_plus_web:
dependency: transitive
description:
name: device_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
device_info_plus_windows:
dependency: transitive
description:
name: device_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -57,6 +120,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -111,6 +188,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "1.1.2"
flutter_staggered_grid_view:
dependency: "direct main"
description:
name: flutter_staggered_grid_view
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -141,7 +225,7 @@ packages:
name: js name: js
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.3" version: "0.6.4"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@ -169,7 +253,7 @@ packages:
name: material_color_utilities name: material_color_utilities
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.1.4"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -183,7 +267,63 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.8.1"
path_provider:
dependency: transitive
description:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.12"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -191,6 +331,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.2" version: "2.0.2"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.4"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -202,7 +349,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "1.8.2"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -237,7 +384,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.8" version: "0.4.9"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -251,7 +398,21 @@ packages:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+1"
sdks: sdks:
dart: ">=2.15.0 <3.0.0" dart: ">=2.16.0-100.0.dev <3.0.0"
flutter: ">=2.0.0" flutter: ">=2.8.0"

View File

@ -37,6 +37,9 @@ dependencies:
flutter_secure_storage: ^5.0.2 flutter_secure_storage: ^5.0.2
logger: ^1.1.0 logger: ^1.1.0
http: ^0.13.4 http: ^0.13.4
flutter_staggered_grid_view: ^0.6.1
dart_vlc: ^0.1.9
device_info_plus: ^3.2.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: