linux build
cache previews in sqlite db actor page outsouce different players in seperate classes
This commit is contained in:
		@@ -14,6 +14,19 @@ flutter_build_android: #Job name
 | 
				
			|||||||
    paths:
 | 
					    paths:
 | 
				
			||||||
      - build/app/outputs/apk/release/app-release.apk
 | 
					      - build/app/outputs/apk/release/app-release.apk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					linux_build:
 | 
				
			||||||
 | 
					  stage: build
 | 
				
			||||||
 | 
					  script:
 | 
				
			||||||
 | 
					    - apt-get update
 | 
				
			||||||
 | 
					    - apt-get install -y --no-install-recommends cmake ninja-build clang build-essential pkg-config libgtk-3-dev liblzma-dev lcov
 | 
				
			||||||
 | 
					    - flutter config --enable-linux-desktop
 | 
				
			||||||
 | 
					    - flutter packages get
 | 
				
			||||||
 | 
					    - flutter build linux
 | 
				
			||||||
 | 
					  artifacts:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - build/linux/x64/release/bundle/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
flutter_lint:
 | 
					flutter_lint:
 | 
				
			||||||
  stage: build
 | 
					  stage: build
 | 
				
			||||||
  script:
 | 
					  script:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,6 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:openmediacentermobile/navigation/settings_screen.dart';
 | 
				
			||||||
 | 
					import 'navigation/actor_screen.dart';
 | 
				
			||||||
import 'navigation/categorie_screen.dart';
 | 
					import 'navigation/categorie_screen.dart';
 | 
				
			||||||
import 'navigation/shufflescreen.dart';
 | 
					import 'navigation/shufflescreen.dart';
 | 
				
			||||||
import 'navigation/video_feed.dart';
 | 
					import 'navigation/video_feed.dart';
 | 
				
			||||||
@@ -15,7 +17,7 @@ class DrawerPage extends StatefulWidget {
 | 
				
			|||||||
  _DrawerPageState createState() => _DrawerPageState();
 | 
					  _DrawerPageState createState() => _DrawerPageState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum Section { HOME, SHUFFLE, LOGOUT, CATEGORIE }
 | 
					enum Section { HOME, SHUFFLE, LOGOUT, CATEGORIE, ACTOR }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _DrawerPageState extends State<DrawerPage> {
 | 
					class _DrawerPageState extends State<DrawerPage> {
 | 
				
			||||||
  Section _sec = Section.HOME;
 | 
					  Section _sec = Section.HOME;
 | 
				
			||||||
@@ -37,7 +39,7 @@ class _DrawerPageState extends State<DrawerPage> {
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      case Section.LOGOUT:
 | 
					      case Section.LOGOUT:
 | 
				
			||||||
        body = const Text("also todo");
 | 
					        body = SettingsScreen();
 | 
				
			||||||
        title = "Settings";
 | 
					        title = "Settings";
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,6 +47,11 @@ class _DrawerPageState extends State<DrawerPage> {
 | 
				
			|||||||
        body = CategorieScreen();
 | 
					        body = CategorieScreen();
 | 
				
			||||||
        title = "Categories";
 | 
					        title = "Categories";
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case Section.ACTOR:
 | 
				
			||||||
 | 
					        body = ActorScreen();
 | 
				
			||||||
 | 
					        title = "Actors";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final loginCtx = LoginContext.of(context);
 | 
					    final loginCtx = LoginContext.of(context);
 | 
				
			||||||
@@ -94,6 +101,16 @@ class _DrawerPageState extends State<DrawerPage> {
 | 
				
			|||||||
              Navigator.pop(context);
 | 
					              Navigator.pop(context);
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
 | 
					          ListTile(
 | 
				
			||||||
 | 
					            title: const Text('Actors'),
 | 
				
			||||||
 | 
					            leading: const Icon(Icons.people),
 | 
				
			||||||
 | 
					            onTap: () {
 | 
				
			||||||
 | 
					              setState(() {
 | 
				
			||||||
 | 
					                _sec = Section.ACTOR;
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					              Navigator.pop(context);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
          ListTile(
 | 
					          ListTile(
 | 
				
			||||||
            title: const Text('Settings'),
 | 
					            title: const Text('Settings'),
 | 
				
			||||||
            leading: const Icon(Icons.settings),
 | 
					            leading: const Icon(Icons.settings),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										55
									
								
								lib/db/database.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								lib/db/database.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
 | 
					import 'package:path/path.dart';
 | 
				
			||||||
 | 
					import 'package:sqflite/sqflite.dart';
 | 
				
			||||||
 | 
					import 'package:sqflite_common_ffi/sqflite_ffi.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../log/log.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Db {
 | 
				
			||||||
 | 
					  late Database _db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void init() async {
 | 
				
			||||||
 | 
					    if (kIsWeb) {
 | 
				
			||||||
 | 
					      Log.i("Database on web is not supported");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    String dbpath = 'previews.db';
 | 
				
			||||||
 | 
					    if (defaultTargetPlatform == TargetPlatform.android ||
 | 
				
			||||||
 | 
					        defaultTargetPlatform == TargetPlatform.iOS) {
 | 
				
			||||||
 | 
					      dbpath = join(await getDatabasesPath(), dbpath);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // Initialize FFI
 | 
				
			||||||
 | 
					      sqfliteFfiInit();
 | 
				
			||||||
 | 
					      // Change the default factory
 | 
				
			||||||
 | 
					      databaseFactory = databaseFactoryFfi;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _db = await openDatabase(
 | 
				
			||||||
 | 
					      // Set the path to the database. Note: Using the `join` function from the
 | 
				
			||||||
 | 
					      // `path` package is best practice to ensure the path is correctly
 | 
				
			||||||
 | 
					      // constructed for each platform.
 | 
				
			||||||
 | 
					      join(await getDatabasesPath(), 'previews.db'),
 | 
				
			||||||
 | 
					      onCreate: (db, version) {
 | 
				
			||||||
 | 
					        // Run the CREATE TABLE statement on the database.
 | 
				
			||||||
 | 
					        return db.execute(
 | 
				
			||||||
 | 
					          'CREATE TABLE previews(id INTEGER PRIMARY KEY, thumbnail BLOB)',
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      // Set the version. This executes the onCreate function and provides a
 | 
				
			||||||
 | 
					      // path to perform database upgrades and downgrades.
 | 
				
			||||||
 | 
					      version: 1,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Database db() {
 | 
				
			||||||
 | 
					    return _db;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static final Db _singleton = Db._internal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  factory Db() {
 | 
				
			||||||
 | 
					    return _singleton;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Db._internal();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
 | 
				
			|||||||
import 'package:flutter/services.dart';
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/app.dart';
 | 
					import 'package:openmediacentermobile/app.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'db/database.dart';
 | 
				
			||||||
import 'log/log.dart';
 | 
					import 'log/log.dart';
 | 
				
			||||||
import 'login/logincontext.dart';
 | 
					import 'login/logincontext.dart';
 | 
				
			||||||
import 'platform.dart';
 | 
					import 'platform.dart';
 | 
				
			||||||
@@ -15,6 +16,8 @@ void main() async {
 | 
				
			|||||||
    await loadDeviceInfo();
 | 
					    await loadDeviceInfo();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Db().init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // RawKeyboard.instance.addListener((event) {
 | 
					  // RawKeyboard.instance.addListener((event) {
 | 
				
			||||||
  //   if (LogicalKeyboardKey.arrowLeft == event.logicalKey) {
 | 
					  //   if (LogicalKeyboardKey.arrowLeft == event.logicalKey) {
 | 
				
			||||||
  //     FocusManager.instance.primaryFocus?.focusInDirection(TraversalDirection.left);
 | 
					  //     FocusManager.instance.primaryFocus?.focusInDirection(TraversalDirection.left);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										65
									
								
								lib/navigation/actor_screen.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								lib/navigation/actor_screen.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:openmediacentermobile/types/actor.dart';
 | 
				
			||||||
 | 
					import 'package:openmediacentermobile/preview/actor_tile.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../api/api.dart';
 | 
				
			||||||
 | 
					import '../screen_loading.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ActorScreen extends StatefulWidget {
 | 
				
			||||||
 | 
					  const ActorScreen({Key? key}) : super(key: key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  State<ActorScreen> createState() => _ActorScreenState();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _ActorScreenState extends State<ActorScreen> {
 | 
				
			||||||
 | 
					  late Future<List<Actor>> _categories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<List<Actor>> loadVideoData() async {
 | 
				
			||||||
 | 
					    final data = await API.query("actor", "getAllActors", {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final d = (jsonDecode(data) ?? []) as List<dynamic>;
 | 
				
			||||||
 | 
					    final actors = d.map((e) => Actor.fromJson(e)).toList(growable: false);
 | 
				
			||||||
 | 
					    return actors;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState() {
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					    _categories = loadVideoData();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return FutureBuilder(
 | 
				
			||||||
 | 
					      future: _categories,
 | 
				
			||||||
 | 
					      builder: (context, AsyncSnapshot<List<Actor>> snapshot) {
 | 
				
			||||||
 | 
					        if (snapshot.connectionState != ConnectionState.done) {
 | 
				
			||||||
 | 
					          return ScreenLoading();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (snapshot.hasError) {
 | 
				
			||||||
 | 
					          return Text("Error");
 | 
				
			||||||
 | 
					        } else if (snapshot.hasData) {
 | 
				
			||||||
 | 
					          return Padding(
 | 
				
			||||||
 | 
					            padding: EdgeInsets.all(5),
 | 
				
			||||||
 | 
					            child: SingleChildScrollView(
 | 
				
			||||||
 | 
					              child: Wrap(
 | 
				
			||||||
 | 
					                spacing: 5,
 | 
				
			||||||
 | 
					                runSpacing: 5,
 | 
				
			||||||
 | 
					                alignment: WrapAlignment.start,
 | 
				
			||||||
 | 
					                children: snapshot.data!
 | 
				
			||||||
 | 
					                    .map((e) => ActorTile(actor: e))
 | 
				
			||||||
 | 
					                    .toList(growable: false),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return ScreenLoading();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import '../navigation/video_feed.dart';
 | 
					import 'package:openmediacentermobile/preview/tag_tile.dart';
 | 
				
			||||||
import '../screen_loading.dart';
 | 
					import '../screen_loading.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../api/api.dart';
 | 
					import '../api/api.dart';
 | 
				
			||||||
@@ -45,33 +45,18 @@ class _CategorieScreenState extends State<CategorieScreen> {
 | 
				
			|||||||
        } else if (snapshot.hasData) {
 | 
					        } else if (snapshot.hasData) {
 | 
				
			||||||
          return Padding(
 | 
					          return Padding(
 | 
				
			||||||
            padding: EdgeInsets.all(5),
 | 
					            padding: EdgeInsets.all(5),
 | 
				
			||||||
 | 
					            child: SingleChildScrollView(
 | 
				
			||||||
              child: Wrap(
 | 
					              child: Wrap(
 | 
				
			||||||
                spacing: 5,
 | 
					                spacing: 5,
 | 
				
			||||||
                runSpacing: 5,
 | 
					                runSpacing: 5,
 | 
				
			||||||
                alignment: WrapAlignment.start,
 | 
					                alignment: WrapAlignment.start,
 | 
				
			||||||
                children: snapshot.data!
 | 
					                children: snapshot.data!
 | 
				
			||||||
                  .map((e) => ElevatedButton(
 | 
					                    .map((e) => TagTile(
 | 
				
			||||||
                        onPressed: () {
 | 
					                          tag: e,
 | 
				
			||||||
                          Navigator.push(
 | 
					 | 
				
			||||||
                            context,
 | 
					 | 
				
			||||||
                            MaterialPageRoute(
 | 
					 | 
				
			||||||
                              builder: (context) => Scaffold(
 | 
					 | 
				
			||||||
                                appBar: AppBar(title: Text(e.tagName)),
 | 
					 | 
				
			||||||
                                body: VideoFeed(tag: e),
 | 
					 | 
				
			||||||
                              ),
 | 
					 | 
				
			||||||
                            ),
 | 
					 | 
				
			||||||
                          );
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        style: ElevatedButton.styleFrom(
 | 
					 | 
				
			||||||
                            primary: Color(0x6a94a6ff)),
 | 
					 | 
				
			||||||
                        child: SizedBox(
 | 
					 | 
				
			||||||
                          child: Center(child: Text(e.tagName)),
 | 
					 | 
				
			||||||
                          height: 100,
 | 
					 | 
				
			||||||
                          width: 100,
 | 
					 | 
				
			||||||
                        ),
 | 
					 | 
				
			||||||
                        ))
 | 
					                        ))
 | 
				
			||||||
                    .toList(growable: false),
 | 
					                    .toList(growable: false),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          return ScreenLoading();
 | 
					          return ScreenLoading();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								lib/navigation/settings_screen.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lib/navigation/settings_screen.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../db/database.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SettingsScreen extends StatefulWidget {
 | 
				
			||||||
 | 
					  const SettingsScreen({Key? key}) : super(key: key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  State<SettingsScreen> createState() => _SettingsScreenState();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			||||||
 | 
					  int dbsize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState() {
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					    loadDBSize();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void loadDBSize() async {
 | 
				
			||||||
 | 
					    final int cnt = (await Db().db().rawQuery("pragma page_count;"))[0]
 | 
				
			||||||
 | 
					        ["page_count"] as int;
 | 
				
			||||||
 | 
					    final int pagesize =
 | 
				
			||||||
 | 
					        (await Db().db().rawQuery("pragma page_size;"))[0]["page_size"] as int;
 | 
				
			||||||
 | 
					    setState(() {
 | 
				
			||||||
 | 
					      dbsize = cnt * pagesize;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return Column(
 | 
				
			||||||
 | 
					      children: [
 | 
				
			||||||
 | 
					        ElevatedButton(
 | 
				
			||||||
 | 
					            onPressed: () async {
 | 
				
			||||||
 | 
					              await Db().db().delete("previews");
 | 
				
			||||||
 | 
					              // shrink the db file size
 | 
				
			||||||
 | 
					              await Db().db().execute("VACUUM");
 | 
				
			||||||
 | 
					              loadDBSize();
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            child: const Text("Delete cache!")),
 | 
				
			||||||
 | 
					        Text("db size: ${dbsize / 1024} kb")
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
import 'dart:math';
 | 
					import 'dart:math';
 | 
				
			||||||
 | 
					 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/preview/preview_grid.dart';
 | 
					 | 
				
			||||||
import '../preview/preview_tile.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../preview/preview_grid.dart';
 | 
				
			||||||
import '../api/api.dart';
 | 
					import '../api/api.dart';
 | 
				
			||||||
import '../platform.dart';
 | 
					import '../platform.dart';
 | 
				
			||||||
 | 
					import '../types/video.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ShuffleScreen extends StatefulWidget {
 | 
					class ShuffleScreen extends StatefulWidget {
 | 
				
			||||||
  const ShuffleScreen({Key? key}) : super(key: key);
 | 
					  const ShuffleScreen({Key? key}) : super(key: key);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/api/api.dart';
 | 
					 | 
				
			||||||
import 'package:openmediacentermobile/preview/preview_grid.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../api/api.dart';
 | 
				
			||||||
import '../log/log.dart';
 | 
					import '../log/log.dart';
 | 
				
			||||||
import '../preview/preview_tile.dart';
 | 
					import '../preview/preview_grid.dart';
 | 
				
			||||||
import '../types/tag.dart';
 | 
					import '../types/tag.dart';
 | 
				
			||||||
 | 
					import '../types/video.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VideoFeed extends StatefulWidget {
 | 
					class VideoFeed extends StatefulWidget {
 | 
				
			||||||
  const VideoFeed({Key? key, this.tag}) : super(key: key);
 | 
					  const VideoFeed({Key? key, this.tag}) : super(key: key);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								lib/preview/actor_feed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/preview/actor_feed.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../api/api.dart';
 | 
				
			||||||
 | 
					import 'preview_grid.dart';
 | 
				
			||||||
 | 
					import '../types/actor.dart';
 | 
				
			||||||
 | 
					import '../types/video.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ActorFeed extends StatefulWidget {
 | 
				
			||||||
 | 
					  const ActorFeed({Key? key, required this.actor}) : super(key: key);
 | 
				
			||||||
 | 
					  final Actor actor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  State<ActorFeed> createState() => _ActorFeedState();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _ActorFeedState extends State<ActorFeed> {
 | 
				
			||||||
 | 
					  Future<List<VideoT>> loadData() async {
 | 
				
			||||||
 | 
					    final data = await API
 | 
				
			||||||
 | 
					        .query("actor", "getActorInfo", {'ActorId': widget.actor.actorId});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final d = jsonDecode(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    List<VideoT> dta =
 | 
				
			||||||
 | 
					        (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return dta;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return PreviewGrid(
 | 
				
			||||||
 | 
					      videoLoader: () => loadData(),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:openmediacentermobile/preview/actor_feed.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../platform.dart';
 | 
					import '../platform.dart';
 | 
				
			||||||
import '../types/actor.dart';
 | 
					import '../types/actor.dart';
 | 
				
			||||||
@@ -27,9 +28,16 @@ class _ActorTileState extends State<ActorTile> {
 | 
				
			|||||||
                  overflow: TextOverflow.clip,
 | 
					                  overflow: TextOverflow.clip,
 | 
				
			||||||
                  maxLines: 1,
 | 
					                  maxLines: 1,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 | 
					                // todo implement case where we have really an picture
 | 
				
			||||||
                SizedBox(
 | 
					                SizedBox(
 | 
				
			||||||
                  height: 100,
 | 
					                  height: 100,
 | 
				
			||||||
                  width: 100,
 | 
					                  width: 100,
 | 
				
			||||||
 | 
					                  child: Center(
 | 
				
			||||||
 | 
					                    child: Icon(
 | 
				
			||||||
 | 
					                      Icons.person_outline,
 | 
				
			||||||
 | 
					                      size: 56,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
@@ -44,13 +52,15 @@ class _ActorTileState extends State<ActorTile> {
 | 
				
			|||||||
                onLongPressEnd: (details) {},
 | 
					                onLongPressEnd: (details) {},
 | 
				
			||||||
                child: InkWell(
 | 
					                child: InkWell(
 | 
				
			||||||
                  onTap: () {
 | 
					                  onTap: () {
 | 
				
			||||||
                    // Navigator.push(
 | 
					                    Navigator.push(
 | 
				
			||||||
                    //   context,
 | 
					                      context,
 | 
				
			||||||
                    //   MaterialPageRoute(
 | 
					                      MaterialPageRoute(
 | 
				
			||||||
                    //     builder: (context) =>
 | 
					                        builder: (context) => Scaffold(
 | 
				
			||||||
                    //         VideoScreen(metaData: widget.dta),
 | 
					                          appBar: AppBar(title: Text(widget.actor.name)),
 | 
				
			||||||
                    //   ),
 | 
					                          body: ActorFeed(actor: widget.actor),
 | 
				
			||||||
                    // );
 | 
					                        ),
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
                  },
 | 
					                  },
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
@@ -2,9 +2,11 @@ import 'dart:ui';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
 | 
					import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/platform.dart';
 | 
					
 | 
				
			||||||
import 'package:openmediacentermobile/preview/preview_tile.dart';
 | 
					import '../platform.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/screen_loading.dart';
 | 
					import '../screen_loading.dart';
 | 
				
			||||||
 | 
					import '../types/video.dart';
 | 
				
			||||||
 | 
					import 'preview_tile.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PreviewGrid extends StatefulWidget {
 | 
					class PreviewGrid extends StatefulWidget {
 | 
				
			||||||
  const PreviewGrid(
 | 
					  const PreviewGrid(
 | 
				
			||||||
@@ -70,7 +72,8 @@ class _PreviewGridState extends State<PreviewGrid> {
 | 
				
			|||||||
        Column(
 | 
					        Column(
 | 
				
			||||||
          children: [
 | 
					          children: [
 | 
				
			||||||
            if (widget.headerBuilder != null) widget.headerBuilder!(this),
 | 
					            if (widget.headerBuilder != null) widget.headerBuilder!(this),
 | 
				
			||||||
            Expanded(
 | 
					            data.length > 0
 | 
				
			||||||
 | 
					                ? Expanded(
 | 
				
			||||||
                    child: MasonryGridView.count(
 | 
					                    child: MasonryGridView.count(
 | 
				
			||||||
                      // every tile should be at max 330 pixels long...
 | 
					                      // every tile should be at max 330 pixels long...
 | 
				
			||||||
                      crossAxisCount: isTV() ? width ~/ 200 : width ~/ 275,
 | 
					                      crossAxisCount: isTV() ? width ~/ 200 : width ~/ 275,
 | 
				
			||||||
@@ -95,6 +98,18 @@ class _PreviewGridState extends State<PreviewGrid> {
 | 
				
			|||||||
                        );
 | 
					                        );
 | 
				
			||||||
                      },
 | 
					                      },
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					                : Center(
 | 
				
			||||||
 | 
					                    child: Column(
 | 
				
			||||||
 | 
					                      mainAxisAlignment: MainAxisAlignment.center,
 | 
				
			||||||
 | 
					                      children: [
 | 
				
			||||||
 | 
					                        SizedBox(
 | 
				
			||||||
 | 
					                          height: 32,
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                        Icon(Icons.warning_amber, size: 52),
 | 
				
			||||||
 | 
					                        Text("no item available")
 | 
				
			||||||
 | 
					                      ],
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
            if (widget.footerBuilder != null) widget.footerBuilder!(this),
 | 
					            if (widget.footerBuilder != null) widget.footerBuilder!(this),
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,26 +1,16 @@
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					import 'dart:typed_data';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/video_screen/videoscreen_desktop.dart'
 | 
					import 'package:sqflite/sqflite.dart';
 | 
				
			||||||
    if (dart.library.html) 'package:openmediacentermobile/video_screen/videoscreen_web.dart'
 | 
					 | 
				
			||||||
    if (dart.library.io) 'package:openmediacentermobile/video_screen/videoscreen_desktop.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../api/api.dart';
 | 
					import '../api/api.dart';
 | 
				
			||||||
 | 
					import '../db/database.dart';
 | 
				
			||||||
 | 
					import '../log/log.dart';
 | 
				
			||||||
import '../platform.dart';
 | 
					import '../platform.dart';
 | 
				
			||||||
 | 
					import '../types/video.dart';
 | 
				
			||||||
// todo put this type in sperate class!
 | 
					import '../video_screen/videoscreen.dart';
 | 
				
			||||||
class VideoT {
 | 
					 | 
				
			||||||
  int id;
 | 
					 | 
				
			||||||
  String title;
 | 
					 | 
				
			||||||
  double ratio;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  VideoT(this.title, this.id, this.ratio);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  factory VideoT.fromJson(dynamic json) {
 | 
					 | 
				
			||||||
    return VideoT(json['MovieName'] as String, json['MovieId'] as int,
 | 
					 | 
				
			||||||
        (json['Ratio'] as num).toDouble());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PreviewTile extends StatefulWidget {
 | 
					class PreviewTile extends StatefulWidget {
 | 
				
			||||||
  const PreviewTile(
 | 
					  const PreviewTile(
 | 
				
			||||||
@@ -42,6 +32,7 @@ class _PreviewTileState extends State<PreviewTile> {
 | 
				
			|||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _preview = loadData();
 | 
					    _preview = loadData();
 | 
				
			||||||
 | 
					    Log.d("initial load of tile");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
@@ -52,15 +43,45 @@ class _PreviewTileState extends State<PreviewTile> {
 | 
				
			|||||||
      setState(() {
 | 
					      setState(() {
 | 
				
			||||||
        _preview = loadData();
 | 
					        _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 {
 | 
					  Future<Image> loadData() async {
 | 
				
			||||||
    final data =
 | 
					    Uint8List data;
 | 
				
			||||||
        await API.query("video", "readThumbnail", {'Movieid': widget.dta.id});
 | 
					    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(
 | 
					    final img = Image.memory(
 | 
				
			||||||
      base64Decode(data.substring(23)),
 | 
					      data,
 | 
				
			||||||
      width: double.infinity,
 | 
					      width: double.infinity,
 | 
				
			||||||
      fit: BoxFit.fitWidth,
 | 
					      fit: BoxFit.fitWidth,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -87,18 +108,7 @@ class _PreviewTileState extends State<PreviewTile> {
 | 
				
			|||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  Widget _buildTile(Image image) {
 | 
				
			||||||
  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 ClipRRect(
 | 
					    return ClipRRect(
 | 
				
			||||||
      borderRadius: BorderRadius.circular(20.0),
 | 
					      borderRadius: BorderRadius.circular(20.0),
 | 
				
			||||||
      child: Stack(
 | 
					      child: Stack(
 | 
				
			||||||
@@ -112,7 +122,7 @@ class _PreviewTileState extends State<PreviewTile> {
 | 
				
			|||||||
                  overflow: TextOverflow.clip,
 | 
					                  overflow: TextOverflow.clip,
 | 
				
			||||||
                  maxLines: 1,
 | 
					                  maxLines: 1,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                      snapshot.data!
 | 
					                image
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            color: Color(0x6a94a6ff),
 | 
					            color: Color(0x6a94a6ff),
 | 
				
			||||||
@@ -123,20 +133,17 @@ class _PreviewTileState extends State<PreviewTile> {
 | 
				
			|||||||
              child: GestureDetector(
 | 
					              child: GestureDetector(
 | 
				
			||||||
                behavior: HitTestBehavior.translucent,
 | 
					                behavior: HitTestBehavior.translucent,
 | 
				
			||||||
                onLongPress: () {
 | 
					                onLongPress: () {
 | 
				
			||||||
                        if (widget.onLongPress != null)
 | 
					                  if (widget.onLongPress != null) widget.onLongPress!(image);
 | 
				
			||||||
                          widget.onLongPress!(snapshot.data!);
 | 
					 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                onLongPressEnd: (details) {
 | 
					                onLongPressEnd: (details) {
 | 
				
			||||||
                        if (widget.onLongPressEnd != null)
 | 
					                  if (widget.onLongPressEnd != null) widget.onLongPressEnd!();
 | 
				
			||||||
                          widget.onLongPressEnd!();
 | 
					 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                child: InkWell(
 | 
					                child: InkWell(
 | 
				
			||||||
                  onTap: () {
 | 
					                  onTap: () {
 | 
				
			||||||
                    Navigator.push(
 | 
					                    Navigator.push(
 | 
				
			||||||
                      context,
 | 
					                      context,
 | 
				
			||||||
                      MaterialPageRoute(
 | 
					                      MaterialPageRoute(
 | 
				
			||||||
                              builder: (context) =>
 | 
					                        builder: (context) => VideoScreen(metaData: widget.dta),
 | 
				
			||||||
                                  VideoScreen(metaData: widget.dta),
 | 
					 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                  },
 | 
					                  },
 | 
				
			||||||
@@ -147,6 +154,21 @@ class _PreviewTileState extends State<PreviewTile> {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @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 {
 | 
					        } else {
 | 
				
			||||||
          return _buildLoader();
 | 
					          return _buildLoader();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								lib/preview/tag_tile.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/preview/tag_tile.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import '../types/tag.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../navigation/video_feed.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TagTile extends StatelessWidget {
 | 
				
			||||||
 | 
					  const TagTile({Key? key, required this.tag}) : super(key: key);
 | 
				
			||||||
 | 
					  final Tag tag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return ElevatedButton(
 | 
				
			||||||
 | 
					      onPressed: () {
 | 
				
			||||||
 | 
					        Navigator.push(
 | 
				
			||||||
 | 
					          context,
 | 
				
			||||||
 | 
					          MaterialPageRoute(
 | 
				
			||||||
 | 
					            builder: (context) => Scaffold(
 | 
				
			||||||
 | 
					              appBar: AppBar(title: Text(tag.tagName)),
 | 
				
			||||||
 | 
					              body: VideoFeed(tag: tag),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      style: ElevatedButton.styleFrom(primary: Color(0x6a94a6ff)),
 | 
				
			||||||
 | 
					      child: SizedBox(
 | 
				
			||||||
 | 
					        child: Center(child: Text(tag.tagName)),
 | 
				
			||||||
 | 
					        height: 100,
 | 
				
			||||||
 | 
					        width: 100,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								lib/types/video.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/types/video.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					class VideoT {
 | 
				
			||||||
 | 
					  int id;
 | 
				
			||||||
 | 
					  String title;
 | 
				
			||||||
 | 
					  double ratio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  VideoT(this.title, this.id, this.ratio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  factory VideoT.fromJson(dynamic json) {
 | 
				
			||||||
 | 
					    return VideoT(json['MovieName'] as String, json['MovieId'] as int,
 | 
				
			||||||
 | 
					        (json['Ratio'] as num).toDouble());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,21 +2,22 @@ import 'dart:convert';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/screen_loading.dart';
 | 
					import 'package:openmediacentermobile/screen_loading.dart';
 | 
				
			||||||
 | 
					import 'package:openmediacentermobile/preview/tag_tile.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/types/video_data.dart';
 | 
					import 'package:openmediacentermobile/types/video_data.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/video_screen/actor_tile.dart';
 | 
					import 'package:openmediacentermobile/preview/actor_tile.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../api/api.dart';
 | 
					import '../api/api.dart';
 | 
				
			||||||
import '../types/actor.dart';
 | 
					import '../types/actor.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActorView extends StatefulWidget {
 | 
					class InfoView extends StatefulWidget {
 | 
				
			||||||
  const ActorView({Key? key, required this.vdata}) : super(key: key);
 | 
					  const InfoView({Key? key, required this.vdata}) : super(key: key);
 | 
				
			||||||
  final VideoData vdata;
 | 
					  final VideoData vdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<ActorView> createState() => _ActorViewState();
 | 
					  State<InfoView> createState() => _InfoViewState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _ActorViewState extends State<ActorView> {
 | 
					class _InfoViewState extends State<InfoView> {
 | 
				
			||||||
  late Future<List<Actor>> _data;
 | 
					  late Future<List<Actor>> _data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
@@ -66,7 +67,7 @@ class _ActorViewState extends State<ActorView> {
 | 
				
			|||||||
                    Text("Tags:"),
 | 
					                    Text("Tags:"),
 | 
				
			||||||
                    Row(
 | 
					                    Row(
 | 
				
			||||||
                      children: widget.vdata.tags
 | 
					                      children: widget.vdata.tags
 | 
				
			||||||
                          .map((e) => Text(e.tagName))
 | 
					                          .map((e) => TagTile(tag: e))
 | 
				
			||||||
                          .toList(growable: false),
 | 
					                          .toList(growable: false),
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                  ]));
 | 
					                  ]));
 | 
				
			||||||
							
								
								
									
										165
									
								
								lib/video_screen/videoscreen.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								lib/video_screen/videoscreen.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					import 'dart:async';
 | 
				
			||||||
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import '../api/api.dart';
 | 
				
			||||||
 | 
					import '../api/token.dart';
 | 
				
			||||||
 | 
					import '../platform.dart';
 | 
				
			||||||
 | 
					import '../screen_loading.dart';
 | 
				
			||||||
 | 
					import '../types/video.dart';
 | 
				
			||||||
 | 
					import '../types/video_data.dart';
 | 
				
			||||||
 | 
					import 'info_view.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'videoscreen_desktop.dart'
 | 
				
			||||||
 | 
					    if (dart.library.html) 'videoscreen_mobile.dart';
 | 
				
			||||||
 | 
					import 'videoscreen_mobile.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VideoScreen extends StatefulWidget {
 | 
				
			||||||
 | 
					  const VideoScreen({Key? key, required this.metaData}) : super(key: key);
 | 
				
			||||||
 | 
					  final VideoT metaData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  State<VideoScreen> createState() => _VideoScreenState();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _VideoScreenState extends State<VideoScreen> {
 | 
				
			||||||
 | 
					  bool _appBarVisible = true;
 | 
				
			||||||
 | 
					  Timer? _appBarTimer;
 | 
				
			||||||
 | 
					  late Future<VideoData> _videoData;
 | 
				
			||||||
 | 
					  PageController _controller = PageController(
 | 
				
			||||||
 | 
					    initialPage: 0,
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String url = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<VideoData> loadVideoData() async {
 | 
				
			||||||
 | 
					    final data =
 | 
				
			||||||
 | 
					        await API.query("video", "loadVideo", {'MovieId': widget.metaData.id});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final d = jsonDecode(data);
 | 
				
			||||||
 | 
					    final video = VideoData.fromJson(d);
 | 
				
			||||||
 | 
					    return video;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void initPlayer() async {
 | 
				
			||||||
 | 
					    final videodata = await _videoData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final token = await Token.getInstance().getToken();
 | 
				
			||||||
 | 
					    if (token == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final baseurl = token.domain;
 | 
				
			||||||
 | 
					    // todo not static middle path
 | 
				
			||||||
 | 
					    final path = baseurl + "/videos/vids/" + videodata.movieUrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    url = path;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState() {
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					    _videoData = loadVideoData();
 | 
				
			||||||
 | 
					    initPlayer();
 | 
				
			||||||
 | 
					    _setAppBarTimer();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    _controller.dispose();
 | 
				
			||||||
 | 
					    _appBarTimer?.cancel();
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void _setAppBarTimer() {
 | 
				
			||||||
 | 
					    _appBarTimer?.cancel();
 | 
				
			||||||
 | 
					    _appBarTimer = Timer(
 | 
				
			||||||
 | 
					      Duration(seconds: 3),
 | 
				
			||||||
 | 
					      () {
 | 
				
			||||||
 | 
					        setState(() {
 | 
				
			||||||
 | 
					          _appBarVisible = false;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return Scaffold(
 | 
				
			||||||
 | 
					      body: FutureBuilder(
 | 
				
			||||||
 | 
					        future: _videoData,
 | 
				
			||||||
 | 
					        builder: (context, AsyncSnapshot<VideoData> snapshot) {
 | 
				
			||||||
 | 
					          if (snapshot.hasError) {
 | 
				
			||||||
 | 
					            return Text("Error");
 | 
				
			||||||
 | 
					          } else if (snapshot.hasData) {
 | 
				
			||||||
 | 
					            return MouseRegion(
 | 
				
			||||||
 | 
					              onHover: (PointerEvent event) async {
 | 
				
			||||||
 | 
					                if (isDesktop()) {
 | 
				
			||||||
 | 
					                  if (event.delta.dx != 0 || event.delta.dy != 0) {
 | 
				
			||||||
 | 
					                    setState(() {
 | 
				
			||||||
 | 
					                      _appBarVisible = true;
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    _setAppBarTimer();
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              child: GestureDetector(
 | 
				
			||||||
 | 
					                onPanDown: (details) async {
 | 
				
			||||||
 | 
					                  if (_appBarVisible) {
 | 
				
			||||||
 | 
					                    await Future.delayed(Duration(milliseconds: 100));
 | 
				
			||||||
 | 
					                    setState(() {
 | 
				
			||||||
 | 
					                      _appBarVisible = false;
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                  } else {
 | 
				
			||||||
 | 
					                    if (!isDesktop()) {
 | 
				
			||||||
 | 
					                      setState(() {
 | 
				
			||||||
 | 
					                        _appBarVisible = true;
 | 
				
			||||||
 | 
					                      });
 | 
				
			||||||
 | 
					                      _setAppBarTimer();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                behavior: HitTestBehavior.opaque,
 | 
				
			||||||
 | 
					                child: Stack(children: [
 | 
				
			||||||
 | 
					                  PageView(
 | 
				
			||||||
 | 
					                      scrollDirection: Axis.vertical,
 | 
				
			||||||
 | 
					                      controller: _controller,
 | 
				
			||||||
 | 
					                      children: [
 | 
				
			||||||
 | 
					                        Center(
 | 
				
			||||||
 | 
					                            child: isDesktop()
 | 
				
			||||||
 | 
					                                ? VideoScreenDesktop(
 | 
				
			||||||
 | 
					                                    url: url,
 | 
				
			||||||
 | 
					                                  )
 | 
				
			||||||
 | 
					                                : VideoScreenMobile(
 | 
				
			||||||
 | 
					                                    url: url,
 | 
				
			||||||
 | 
					                                  )),
 | 
				
			||||||
 | 
					                        InfoView(
 | 
				
			||||||
 | 
					                          vdata: snapshot.data!,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                      ]),
 | 
				
			||||||
 | 
					                  if (_appBarVisible)
 | 
				
			||||||
 | 
					                    new Positioned(
 | 
				
			||||||
 | 
					                      top: 0.0,
 | 
				
			||||||
 | 
					                      left: 0.0,
 | 
				
			||||||
 | 
					                      right: 0.0,
 | 
				
			||||||
 | 
					                      child: AppBar(
 | 
				
			||||||
 | 
					                        title: Text(widget.metaData.title),
 | 
				
			||||||
 | 
					                        leading: new IconButton(
 | 
				
			||||||
 | 
					                          icon: new Icon(Icons.arrow_back_ios,
 | 
				
			||||||
 | 
					                              color: Colors.grey),
 | 
				
			||||||
 | 
					                          onPressed: () => Navigator.of(context).pop(),
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                        backgroundColor:
 | 
				
			||||||
 | 
					                            Theme.of(context).primaryColor.withOpacity(0.3),
 | 
				
			||||||
 | 
					                        elevation: 0.0,
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ]),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            return ScreenLoading();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,198 +1,22 @@
 | 
				
			|||||||
import 'dart:async';
 | 
					 | 
				
			||||||
import 'dart:convert';
 | 
					 | 
				
			||||||
import 'dart:math';
 | 
					import 'dart:math';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:chewie/chewie.dart';
 | 
					import 'package:dart_vlc/dart_vlc.dart';
 | 
				
			||||||
import "package:dart_vlc/dart_vlc.dart";
 | 
					 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter/services.dart';
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
import 'package:openmediacentermobile/preview/preview_tile.dart';
 | 
					 | 
				
			||||||
import 'package:openmediacentermobile/screen_loading.dart';
 | 
					 | 
				
			||||||
import 'package:openmediacentermobile/video_screen/actor_view.dart';
 | 
					 | 
				
			||||||
import 'package:video_player/video_player.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../api/api.dart';
 | 
					class VideoScreenDesktop extends StatefulWidget {
 | 
				
			||||||
import '../api/token.dart';
 | 
					  const VideoScreenDesktop({Key? key, required this.url}) : super(key: key);
 | 
				
			||||||
import '../platform.dart';
 | 
					  final String url;
 | 
				
			||||||
import '../types/video_data.dart';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class VideoScreen extends StatefulWidget {
 | 
					 | 
				
			||||||
  const VideoScreen({Key? key, required this.metaData}) : super(key: key);
 | 
					 | 
				
			||||||
  final VideoT metaData;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<VideoScreen> createState() => _VideoScreenState();
 | 
					  State<VideoScreenDesktop> createState() => _VideoScreenDesktopState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _VideoScreenState extends State<VideoScreen> {
 | 
					class _VideoScreenDesktopState extends State<VideoScreenDesktop> {
 | 
				
			||||||
  Player? _player =
 | 
					  Player _player = Player(id: Random().nextInt(0x7fffffff));
 | 
				
			||||||
      isDesktop() ? Player(id: Random().nextInt(0x7fffffff)) : null;
 | 
					 | 
				
			||||||
  ChewieController? _chewieController;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool _appBarVisible = true;
 | 
					 | 
				
			||||||
  Timer? _appBarTimer;
 | 
					 | 
				
			||||||
  late Future<VideoData> _videoData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Future<VideoData> loadVideoData() async {
 | 
					 | 
				
			||||||
    final data =
 | 
					 | 
				
			||||||
        await API.query("video", "loadVideo", {'MovieId': widget.metaData.id});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    final d = jsonDecode(data);
 | 
					 | 
				
			||||||
    final video = VideoData.fromJson(d);
 | 
					 | 
				
			||||||
    return video;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void initPlayer() async {
 | 
					 | 
				
			||||||
    final videodata = await _videoData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    final token = await Token.getInstance().getToken();
 | 
					 | 
				
			||||||
    if (token == null) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    final baseurl = token.domain;
 | 
					 | 
				
			||||||
    // todo not static middle path
 | 
					 | 
				
			||||||
    final path = baseurl + "/videos/vids/" + videodata.movieUrl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (isDesktop()) {
 | 
					 | 
				
			||||||
      final media2 = Media.network(path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      _player?.open(
 | 
					 | 
				
			||||||
        media2,
 | 
					 | 
				
			||||||
        autoStart: true, // default
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      final VideoPlayerController _controller =
 | 
					 | 
				
			||||||
          VideoPlayerController.network(path);
 | 
					 | 
				
			||||||
      await _controller.initialize();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      _chewieController = ChewieController(
 | 
					 | 
				
			||||||
          videoPlayerController: _controller,
 | 
					 | 
				
			||||||
          autoPlay: true,
 | 
					 | 
				
			||||||
          looping: true,
 | 
					 | 
				
			||||||
          allowFullScreen: true,
 | 
					 | 
				
			||||||
          allowMuting: true,
 | 
					 | 
				
			||||||
          allowPlaybackSpeedChanging: true,
 | 
					 | 
				
			||||||
          zoomAndPan: true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      setState(() {});
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  void initState() {
 | 
					 | 
				
			||||||
    super.initState();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _videoData = loadVideoData();
 | 
					 | 
				
			||||||
    initPlayer();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (isDesktop()) {
 | 
					 | 
				
			||||||
      RawKeyboard.instance.addListener((value) {
 | 
					 | 
				
			||||||
        if (value.logicalKey == LogicalKeyboardKey.arrowRight) {
 | 
					 | 
				
			||||||
          _player
 | 
					 | 
				
			||||||
              ?.seek(_player!.position.position! + const Duration(seconds: 5));
 | 
					 | 
				
			||||||
        } else if (value.logicalKey == LogicalKeyboardKey.arrowLeft) {
 | 
					 | 
				
			||||||
          _player
 | 
					 | 
				
			||||||
              ?.seek(_player!.position.position! + const Duration(seconds: -5));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _setAppBarTimer();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  void dispose() {
 | 
					 | 
				
			||||||
    if (isDesktop()) {
 | 
					 | 
				
			||||||
      _player?.dispose();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      _chewieController?.videoPlayerController.dispose();
 | 
					 | 
				
			||||||
      _chewieController?.dispose();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    _controller.dispose();
 | 
					 | 
				
			||||||
    _appBarTimer?.cancel();
 | 
					 | 
				
			||||||
    super.dispose();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void _setAppBarTimer() {
 | 
					 | 
				
			||||||
    _appBarTimer?.cancel();
 | 
					 | 
				
			||||||
    _appBarTimer = Timer(
 | 
					 | 
				
			||||||
      Duration(seconds: 3),
 | 
					 | 
				
			||||||
      () {
 | 
					 | 
				
			||||||
        setState(() {
 | 
					 | 
				
			||||||
          _appBarVisible = false;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PageController _controller = PageController(
 | 
					 | 
				
			||||||
    initialPage: 0,
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return Scaffold(
 | 
					 | 
				
			||||||
      body: FutureBuilder(
 | 
					 | 
				
			||||||
        future: _videoData,
 | 
					 | 
				
			||||||
        builder: (context, AsyncSnapshot<VideoData> snapshot) {
 | 
					 | 
				
			||||||
          if (snapshot.hasError) {
 | 
					 | 
				
			||||||
            return Text("Error");
 | 
					 | 
				
			||||||
          } else if (snapshot.hasData) {
 | 
					 | 
				
			||||||
            return MouseRegion(
 | 
					 | 
				
			||||||
              onHover: (PointerEvent event) async {
 | 
					 | 
				
			||||||
                if (event.delta.dx != 0 || event.delta.dy != 0) {
 | 
					 | 
				
			||||||
                  if (_appBarVisible) {
 | 
					 | 
				
			||||||
                    await Future.delayed(Duration(milliseconds: 100));
 | 
					 | 
				
			||||||
                    setState(() {
 | 
					 | 
				
			||||||
                      _appBarVisible = false;
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                  } else {
 | 
					 | 
				
			||||||
                    setState(() {
 | 
					 | 
				
			||||||
                      _appBarVisible = true;
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                    _setAppBarTimer();
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              child: Stack(children: [
 | 
					 | 
				
			||||||
                PageView(
 | 
					 | 
				
			||||||
                    scrollDirection: Axis.vertical,
 | 
					 | 
				
			||||||
                    controller: _controller,
 | 
					 | 
				
			||||||
                    children: [
 | 
					 | 
				
			||||||
                      Center(
 | 
					 | 
				
			||||||
                          child:
 | 
					 | 
				
			||||||
                              isDesktop() ? videoDesktop() : videoNotDesktop()),
 | 
					 | 
				
			||||||
                      ActorView(
 | 
					 | 
				
			||||||
                        vdata: snapshot.data!,
 | 
					 | 
				
			||||||
                      )
 | 
					 | 
				
			||||||
                    ]),
 | 
					 | 
				
			||||||
                if (_appBarVisible)
 | 
					 | 
				
			||||||
                  new Positioned(
 | 
					 | 
				
			||||||
                    top: 0.0,
 | 
					 | 
				
			||||||
                    left: 0.0,
 | 
					 | 
				
			||||||
                    right: 0.0,
 | 
					 | 
				
			||||||
                    child: AppBar(
 | 
					 | 
				
			||||||
                      title: Text(widget.metaData.title),
 | 
					 | 
				
			||||||
                      leading: new IconButton(
 | 
					 | 
				
			||||||
                        icon:
 | 
					 | 
				
			||||||
                            new Icon(Icons.arrow_back_ios, color: Colors.grey),
 | 
					 | 
				
			||||||
                        onPressed: () => Navigator.of(context).pop(),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                      backgroundColor:
 | 
					 | 
				
			||||||
                          Theme.of(context).primaryColor.withOpacity(0.3),
 | 
					 | 
				
			||||||
                      elevation: 0.0,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                  ),
 | 
					 | 
				
			||||||
              ]),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            return ScreenLoading();
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Widget videoDesktop() {
 | 
					 | 
				
			||||||
    return Video(
 | 
					    return Video(
 | 
				
			||||||
      player: _player,
 | 
					      player: _player,
 | 
				
			||||||
      scale: 1.0, // default
 | 
					      scale: 1.0, // default
 | 
				
			||||||
@@ -201,16 +25,29 @@ class _VideoScreenState extends State<VideoScreen> {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Widget videoNotDesktop() {
 | 
					  @override
 | 
				
			||||||
    if (_chewieController == null) {
 | 
					  void initState() {
 | 
				
			||||||
      return Column(
 | 
					    super.initState();
 | 
				
			||||||
        crossAxisAlignment: CrossAxisAlignment.center,
 | 
					
 | 
				
			||||||
        mainAxisAlignment: MainAxisAlignment.center,
 | 
					    final media2 = Media.network(widget.url);
 | 
				
			||||||
        children: const [CircularProgressIndicator(), Text("loading...")],
 | 
					
 | 
				
			||||||
 | 
					    _player.open(
 | 
				
			||||||
 | 
					      media2,
 | 
				
			||||||
 | 
					      autoStart: true, // default
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RawKeyboard.instance.addListener((value) {
 | 
				
			||||||
 | 
					      if (value.logicalKey == LogicalKeyboardKey.arrowRight) {
 | 
				
			||||||
 | 
					        _player.seek(_player.position.position! + const Duration(seconds: 5));
 | 
				
			||||||
 | 
					      } else if (value.logicalKey == LogicalKeyboardKey.arrowLeft) {
 | 
				
			||||||
 | 
					        _player.seek(_player.position.position! + const Duration(seconds: -5));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    return Chewie(
 | 
					    });
 | 
				
			||||||
      controller: _chewieController!,
 | 
					  }
 | 
				
			||||||
    );
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
 | 
					    _player.dispose();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										59
									
								
								lib/video_screen/videoscreen_mobile.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								lib/video_screen/videoscreen_mobile.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					import 'package:chewie/chewie.dart';
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:video_player/video_player.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VideoScreenMobile extends StatefulWidget {
 | 
				
			||||||
 | 
					  const VideoScreenMobile({Key? key, required this.url}) : super(key: key);
 | 
				
			||||||
 | 
					  final String url;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  State<VideoScreenMobile> createState() => _VideoScreenMobileState();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _VideoScreenMobileState extends State<VideoScreenMobile> {
 | 
				
			||||||
 | 
					  ChewieController? _chewieController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    if (_chewieController == null) {
 | 
				
			||||||
 | 
					      return Column(
 | 
				
			||||||
 | 
					        crossAxisAlignment: CrossAxisAlignment.center,
 | 
				
			||||||
 | 
					        mainAxisAlignment: MainAxisAlignment.center,
 | 
				
			||||||
 | 
					        children: const [CircularProgressIndicator(), Text("loading...")],
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return Chewie(
 | 
				
			||||||
 | 
					      controller: _chewieController!,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
 | 
					    _chewieController?.videoPlayerController.dispose();
 | 
				
			||||||
 | 
					    _chewieController?.dispose();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState() {
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					    _init();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void _init() async {
 | 
				
			||||||
 | 
					    final VideoPlayerController _controller =
 | 
				
			||||||
 | 
					        VideoPlayerController.network(widget.url);
 | 
				
			||||||
 | 
					    await _controller.initialize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _chewieController = ChewieController(
 | 
				
			||||||
 | 
					        videoPlayerController: _controller,
 | 
				
			||||||
 | 
					        autoPlay: true,
 | 
				
			||||||
 | 
					        looping: true,
 | 
				
			||||||
 | 
					        allowFullScreen: true,
 | 
				
			||||||
 | 
					        allowMuting: true,
 | 
				
			||||||
 | 
					        allowPlaybackSpeedChanging: true,
 | 
				
			||||||
 | 
					        zoomAndPan: true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setState(() {});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,52 +0,0 @@
 | 
				
			|||||||
import 'dart:convert';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import '../api/api.dart';
 | 
					 | 
				
			||||||
import '../api/token.dart';
 | 
					 | 
				
			||||||
import '../log/log.dart';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class VideoScreen extends StatefulWidget {
 | 
					 | 
				
			||||||
  const VideoScreen({Key? key, required this.videoID}) : super(key: key);
 | 
					 | 
				
			||||||
  final int videoID;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  State<VideoScreen> createState() => _VideoScreenState();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class _VideoScreenState extends State<VideoScreen> {
 | 
					 | 
				
			||||||
  void loadData() async {
 | 
					 | 
				
			||||||
    final data =
 | 
					 | 
				
			||||||
        await API.query("video", "loadVideo", {'MovieId': widget.videoID});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    final d = jsonDecode(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    final url = d["MovieUrl"];
 | 
					 | 
				
			||||||
    final token = await Token.getInstance().getToken();
 | 
					 | 
				
			||||||
    if (token == null) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    final baseurl = token.domain;
 | 
					 | 
				
			||||||
    // todo not static middle path
 | 
					 | 
				
			||||||
    final String path = baseurl + "/videos/vids/" + url;
 | 
					 | 
				
			||||||
    Log.d(path);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  void initState() {
 | 
					 | 
				
			||||||
    super.initState();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    loadData();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // todo hide appbar after some seonds
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					 | 
				
			||||||
    return Scaffold(
 | 
					 | 
				
			||||||
      appBar: AppBar(
 | 
					 | 
				
			||||||
        title: const Text('Second Route'),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
      body: const Center(child: Text("Todo to implement")),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										39
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								pubspec.lock
									
									
									
									
									
								
							@@ -290,7 +290,7 @@ packages:
 | 
				
			|||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.0.0"
 | 
					    version: "1.0.0"
 | 
				
			||||||
  path:
 | 
					  path:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: path
 | 
					      name: path
 | 
				
			||||||
      url: "https://pub.dartlang.org"
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
@@ -385,6 +385,34 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dartlang.org"
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.8.2"
 | 
					    version: "1.8.2"
 | 
				
			||||||
 | 
					  sqflite:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqflite
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.0.3+1"
 | 
				
			||||||
 | 
					  sqflite_common:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqflite_common
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.2.1+1"
 | 
				
			||||||
 | 
					  sqflite_common_ffi:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqflite_common_ffi
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.1.1+1"
 | 
				
			||||||
 | 
					  sqlite3:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqlite3
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.7.0"
 | 
				
			||||||
  stack_trace:
 | 
					  stack_trace:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -406,6 +434,13 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dartlang.org"
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.1.0"
 | 
					    version: "1.1.0"
 | 
				
			||||||
 | 
					  synchronized:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: synchronized
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "3.0.0+2"
 | 
				
			||||||
  term_glyph:
 | 
					  term_glyph:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -527,4 +562,4 @@ packages:
 | 
				
			|||||||
    version: "0.2.0+1"
 | 
					    version: "0.2.0+1"
 | 
				
			||||||
sdks:
 | 
					sdks:
 | 
				
			||||||
  dart: ">=2.17.0-206.0.dev <3.0.0"
 | 
					  dart: ">=2.17.0-206.0.dev <3.0.0"
 | 
				
			||||||
  flutter: ">=2.8.0"
 | 
					  flutter: ">=3.0.0"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,9 @@ dependencies:
 | 
				
			|||||||
  device_info_plus: ^3.2.3
 | 
					  device_info_plus: ^3.2.3
 | 
				
			||||||
  video_player: ^2.3.0
 | 
					  video_player: ^2.3.0
 | 
				
			||||||
  chewie: ^1.3.2
 | 
					  chewie: ^1.3.2
 | 
				
			||||||
 | 
					  sqflite: ^2.0.3+1
 | 
				
			||||||
 | 
					  path: ^1.8.1
 | 
				
			||||||
 | 
					  sqflite_common_ffi: ^2.1.1+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dev_dependencies:
 | 
					dev_dependencies:
 | 
				
			||||||
  flutter_test:
 | 
					  flutter_test:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user