Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
eff1ea0812 | |||
6f6fbb3897 |
26
.metadata
26
.metadata
@ -1,30 +1,10 @@
|
|||||||
# This file tracks properties of this Flutter project.
|
# This file tracks properties of this Flutter project.
|
||||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
#
|
#
|
||||||
# This file should be version controlled.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: f92f44110e87bad5ff168335c36da6f6053036e6
|
revision: 37de8a2a9ad217ec9d731f8af0bd7c83e8f4980c
|
||||||
channel: stable
|
channel: master
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
|
|
||||||
# Tracks metadata for the flutter migrate command
|
|
||||||
migration:
|
|
||||||
platforms:
|
|
||||||
- platform: root
|
|
||||||
create_revision: f92f44110e87bad5ff168335c36da6f6053036e6
|
|
||||||
base_revision: f92f44110e87bad5ff168335c36da6f6053036e6
|
|
||||||
- platform: web
|
|
||||||
create_revision: f92f44110e87bad5ff168335c36da6f6053036e6
|
|
||||||
base_revision: f92f44110e87bad5ff168335c36da6f6053036e6
|
|
||||||
|
|
||||||
# User provided section
|
|
||||||
|
|
||||||
# List of Local paths (relative to this file) that should be
|
|
||||||
# ignored by the migrate tool.
|
|
||||||
#
|
|
||||||
# Files that are not part of the templates will be ignored by default.
|
|
||||||
unmanaged_files:
|
|
||||||
- 'lib/main.dart'
|
|
||||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
|
||||||
|
@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
import 'token.dart';
|
import 'token.dart';
|
||||||
|
|
||||||
class TokenException implements Exception {
|
class TokenException implements Exception {
|
||||||
@ -12,7 +11,7 @@ class TokenException implements Exception {
|
|||||||
class API {
|
class API {
|
||||||
static Future<String> query(
|
static Future<String> query(
|
||||||
String apinode, String action, Object payload) async {
|
String apinode, String action, Object payload) async {
|
||||||
final t = await getToken();
|
final t = await Token.getInstance().getToken();
|
||||||
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'),
|
||||||
|
@ -1,19 +1,66 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:openmediacentermobile/db/settings_db.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
|
||||||
|
import '../log/log.dart';
|
||||||
|
|
||||||
class TokenT {
|
class TokenT {
|
||||||
String token;
|
String token;
|
||||||
String domain;
|
String domain;
|
||||||
|
String videoPath;
|
||||||
|
String tvPath;
|
||||||
|
|
||||||
TokenT(this.token, this.domain);
|
TokenT(this.token, this.domain, this.videoPath, this.tvPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<TokenT?> getToken() async {
|
class Token {
|
||||||
final settings = await SettingsDB.getInstance().getSettings();
|
static final Token _token = Token._();
|
||||||
if (settings.token == "" || settings.domain == "") {
|
final _storage = const FlutterSecureStorage();
|
||||||
return null;
|
|
||||||
} else {
|
String _tokenval = "";
|
||||||
return TokenT(settings.token, settings.domain);
|
String _domain = "";
|
||||||
|
String _vPath = "";
|
||||||
|
String _tvPath = "";
|
||||||
|
|
||||||
|
static Token getInstance() {
|
||||||
|
return _token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<TokenT?> getToken() async {
|
||||||
|
if (_tokenval == "" || _domain == "" || _vPath == "") {
|
||||||
|
Log.d("reading token store");
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final token = await _storage.read(key: 'jwt');
|
||||||
|
final domain = await _storage.read(key: 'domain');
|
||||||
|
// todo paths should be loaded on each app start
|
||||||
|
final vPath = await _storage.read(key: 'videoPath');
|
||||||
|
final tvPath = await _storage.read(key: 'tvPath');
|
||||||
|
|
||||||
|
// check if value is defined in phone store
|
||||||
|
if (token != null && domain != null && vPath != null) {
|
||||||
|
_tokenval = token;
|
||||||
|
_domain = domain;
|
||||||
|
return TokenT(token, domain, vPath, tvPath ?? "");
|
||||||
|
} else {
|
||||||
|
Log.d("no token defined");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return TokenT(_tokenval, _domain, _vPath, _tvPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setToken(String token, String domain, String videoPath, String tvPath) {
|
||||||
|
_tokenval = token;
|
||||||
|
_domain = domain;
|
||||||
|
_vPath = videoPath;
|
||||||
|
_tvPath = tvPath;
|
||||||
|
_storage.write(key: 'jwt', value: token);
|
||||||
|
_storage.write(key: 'domain', value: domain);
|
||||||
|
_storage.write(key: 'videoPath', value: videoPath);
|
||||||
|
_storage.write(key: 'tvPath', value: tvPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token._();
|
||||||
}
|
}
|
||||||
|
12
lib/app.dart
12
lib/app.dart
@ -3,6 +3,7 @@ import 'dart:ui';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:openmediacentermobile/log/log.dart';
|
import 'package:openmediacentermobile/log/log.dart';
|
||||||
import 'package:openmediacentermobile/login/login_screen.dart';
|
import 'package:openmediacentermobile/login/login_screen.dart';
|
||||||
|
import 'package:openmediacentermobile/utils/feature_context.dart';
|
||||||
|
|
||||||
import 'drawer/drawer_page.dart';
|
import 'drawer/drawer_page.dart';
|
||||||
import 'login/login_context.dart';
|
import 'login/login_context.dart';
|
||||||
@ -21,20 +22,21 @@ class App extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var loginCtx = LoginContext.of(context);
|
final loginCtx = LoginContext.of(context);
|
||||||
|
|
||||||
Log.d("We are logged in: ${loginCtx.loggedIn}");
|
Log.d("We are logged in: ${loginCtx.loggedIn}");
|
||||||
|
|
||||||
if (!loginCtx.loggedIn) {
|
if (!loginCtx.loggedIn) {
|
||||||
return const MaterialApp(home: LoginScreen());
|
return const MaterialApp(home: LoginScreen());
|
||||||
} else {
|
} else {
|
||||||
return MaterialApp(
|
return FeatureContainer(
|
||||||
theme: ThemeData(
|
child: MaterialApp(
|
||||||
appBarTheme: AppBarTheme(backgroundColor: Color(0xff0d0d0d))),
|
|
||||||
scrollBehavior: AppScrollBehavior(),
|
scrollBehavior: AppScrollBehavior(),
|
||||||
home: DrawerPage(
|
home: DrawerPage(
|
||||||
title: 'OpenMediaCenter',
|
title: 'OpenMediaCenter',
|
||||||
));
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,47 +1,39 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:sqflite/sqflite.dart';
|
import 'package:sqflite/sqflite.dart';
|
||||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart' as nativeffi;
|
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||||
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart' as webffi;
|
|
||||||
|
|
||||||
import '../log/log.dart';
|
import '../log/log.dart';
|
||||||
|
|
||||||
class Db {
|
class Db {
|
||||||
late Database _db;
|
late Database _db;
|
||||||
|
|
||||||
Future<void> init() async {
|
void init() async {
|
||||||
|
if (kIsWeb) {
|
||||||
|
Log.i("Database on web is not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
String dbpath = 'previews.db';
|
String dbpath = 'previews.db';
|
||||||
if (defaultTargetPlatform == TargetPlatform.android ||
|
if (defaultTargetPlatform == TargetPlatform.android ||
|
||||||
defaultTargetPlatform == TargetPlatform.iOS) {
|
defaultTargetPlatform == TargetPlatform.iOS) {
|
||||||
dbpath = join(await getDatabasesPath(), dbpath);
|
dbpath = join(await getDatabasesPath(), dbpath);
|
||||||
} else if(kIsWeb) {
|
|
||||||
databaseFactory = webffi.databaseFactoryFfiWeb;
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
||||||
// Initialize FFI
|
// Initialize FFI
|
||||||
nativeffi.sqfliteFfiInit();
|
sqfliteFfiInit();
|
||||||
// Change the default factory
|
// Change the default factory
|
||||||
databaseFactory = nativeffi.databaseFactoryFfi;
|
databaseFactory = databaseFactoryFfi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_db = await openDatabase(
|
_db = await openDatabase(
|
||||||
dbpath,
|
dbpath,
|
||||||
onCreate: (db, version) {
|
onCreate: (db, version) {
|
||||||
final batch = db.batch();
|
return db.execute(
|
||||||
batch.execute(
|
'CREATE TABLE previews(id INTEGER PRIMARY KEY, thumbnail BLOB)',
|
||||||
'CREATE TABLE previews(id INTEGER PRIMARY KEY, thumbnail BLOB);',
|
|
||||||
);
|
);
|
||||||
batch.execute(
|
|
||||||
'CREATE TABLE settings(domain TEXT, token TEXT, videopath TEXT, tilewidth INTEGER);',
|
|
||||||
);
|
|
||||||
batch.insert("settings",
|
|
||||||
{"domain": "", "token": "", "videopath": "", "tilewidth": 0});
|
|
||||||
return batch.commit();
|
|
||||||
},
|
},
|
||||||
// Set the version. This executes the onCreate function and provides a
|
// Set the version. This executes the onCreate function and provides a
|
||||||
// path to perform database upgrades and downgrades.
|
// path to perform database upgrades and downgrades.
|
||||||
version: 2,
|
version: 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,16 +46,10 @@ class Db {
|
|||||||
|
|
||||||
/// get db size in bytes
|
/// get db size in bytes
|
||||||
Future<int> getDbSize() async {
|
Future<int> getDbSize() async {
|
||||||
final batch = _db.batch();
|
final int cnt = (await Db().db().rawQuery("pragma page_count;"))[0]
|
||||||
batch.rawQuery("pragma page_count;");
|
["page_count"] as int;
|
||||||
batch.rawQuery("pragma page_size;");
|
|
||||||
final result = (await batch.commit(noResult: false));
|
|
||||||
print(result);
|
|
||||||
|
|
||||||
final int cnt =
|
|
||||||
((result[0] as List<Map<String, dynamic>>)[0]["page_count"] as int);
|
|
||||||
final int pagesize =
|
final int pagesize =
|
||||||
(result[1] as List<Map<String, dynamic>>)[0]["page_size"] as int;
|
(await Db().db().rawQuery("pragma page_size;"))[0]["page_size"] as int;
|
||||||
return cnt * pagesize;
|
return cnt * pagesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
import 'database.dart';
|
|
||||||
|
|
||||||
class SettingsT {
|
|
||||||
String domain;
|
|
||||||
String token;
|
|
||||||
String videopath;
|
|
||||||
int tilewidth;
|
|
||||||
|
|
||||||
SettingsT(this.domain, this.token, this.videopath, this.tilewidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
class SettingsDB {
|
|
||||||
static final SettingsDB _instance = SettingsDB._();
|
|
||||||
|
|
||||||
SettingsT _settings = SettingsT("", "", "", 0);
|
|
||||||
bool _initialized = false;
|
|
||||||
|
|
||||||
Future<SettingsT> getSettings() async {
|
|
||||||
if (!_initialized) {
|
|
||||||
final result = (await Db().db().query("settings",
|
|
||||||
where: "1",
|
|
||||||
columns: ["domain", "token", "videopath", "tilewidth"]))
|
|
||||||
.first;
|
|
||||||
|
|
||||||
_settings = SettingsT(
|
|
||||||
result["domain"] as String,
|
|
||||||
result["token"] as String,
|
|
||||||
result["videopath"] as String,
|
|
||||||
result["tilewidth"] as int);
|
|
||||||
}
|
|
||||||
return _settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> setSettings(SettingsT settings) async {
|
|
||||||
await Db().db().update(
|
|
||||||
"settings",
|
|
||||||
{
|
|
||||||
"domain": settings.domain,
|
|
||||||
"token": settings.token,
|
|
||||||
"videopath": settings.videopath,
|
|
||||||
"tilewidth": settings.tilewidth
|
|
||||||
},
|
|
||||||
where: "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
static SettingsDB getInstance() {
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDB._();
|
|
||||||
}
|
|
@ -32,8 +32,6 @@ class _AddActorDialogState extends State<AddActorDialog> {
|
|||||||
return Text("Error");
|
return Text("Error");
|
||||||
} else if (snapshot.hasData) {
|
} else if (snapshot.hasData) {
|
||||||
final data = snapshot.data! as List<Actor>;
|
final data = snapshot.data! as List<Actor>;
|
||||||
data.sort((a, b) =>
|
|
||||||
a.name.toLowerCase().compareTo(b.name.toLowerCase()));
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: data
|
children: data
|
||||||
|
@ -32,10 +32,6 @@ class _AddTagDialogState extends State<AddTagDialog> {
|
|||||||
return Text("Error");
|
return Text("Error");
|
||||||
} else if (snapshot.hasData) {
|
} else if (snapshot.hasData) {
|
||||||
final data = snapshot.data! as List<Tag>;
|
final data = snapshot.data! as List<Tag>;
|
||||||
data.sort(
|
|
||||||
(a, b) =>
|
|
||||||
a.tagName.toLowerCase().compareTo(b.tagName.toLowerCase()),
|
|
||||||
);
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: data
|
children: data
|
||||||
|
@ -3,6 +3,7 @@ import 'package:openmediacentermobile/navigation/settings_screen.dart';
|
|||||||
import '../navigation/actor_screen.dart';
|
import '../navigation/actor_screen.dart';
|
||||||
import '../navigation/categorie_screen.dart';
|
import '../navigation/categorie_screen.dart';
|
||||||
import '../navigation/shuffle_screen.dart';
|
import '../navigation/shuffle_screen.dart';
|
||||||
|
import '../navigation/tv_show_screen.dart';
|
||||||
import '../navigation/video_feed.dart';
|
import '../navigation/video_feed.dart';
|
||||||
import 'drawer_context.dart';
|
import 'drawer_context.dart';
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ class DrawerPage extends StatefulWidget {
|
|||||||
_DrawerPageState createState() => _DrawerPageState();
|
_DrawerPageState createState() => _DrawerPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Section { HOME, SHUFFLE, SETTING, CATEGORIE, ACTOR }
|
enum Section { HOME, SHUFFLE, SETTING, CATEGORIE, ACTOR, TVSHOW }
|
||||||
|
|
||||||
class _DrawerPageState extends State<DrawerPage> {
|
class _DrawerPageState extends State<DrawerPage> {
|
||||||
Section _sec = Section.HOME;
|
Section _sec = Section.HOME;
|
||||||
@ -50,6 +51,11 @@ class _DrawerPageState extends State<DrawerPage> {
|
|||||||
body = ActorScreen();
|
body = ActorScreen();
|
||||||
title = "Actors";
|
title = "Actors";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Section.TVSHOW:
|
||||||
|
body = TVShowScreen();
|
||||||
|
title = "TV Shows";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DrawerContext(
|
return DrawerContext(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:openmediacentermobile/utils/feature_context.dart';
|
||||||
|
|
||||||
import 'drawer_context.dart';
|
import 'drawer_context.dart';
|
||||||
import 'drawer_page.dart';
|
import 'drawer_page.dart';
|
||||||
@ -7,32 +8,62 @@ class MyDrawer extends StatelessWidget {
|
|||||||
const MyDrawer({Key? key}) : super(key: key);
|
const MyDrawer({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Drawer(
|
Widget build(BuildContext context) {
|
||||||
backgroundColor: Color(0xff3f3f3f),
|
|
||||||
child: ListView(children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 75,
|
|
||||||
),
|
|
||||||
_listelement('Home', Icons.home, Section.HOME, context),
|
|
||||||
_listelement('Shuffle', Icons.update, Section.SHUFFLE, context),
|
|
||||||
_listelement(
|
|
||||||
'Categories', Icons.category, Section.CATEGORIE, context),
|
|
||||||
_listelement('Actors', Icons.people, Section.ACTOR, context),
|
|
||||||
_listelement('Settings', Icons.settings, Section.SETTING, context),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _listelement(
|
|
||||||
String text, IconData icon, Section section, BuildContext context) {
|
|
||||||
final ctx = DrawerContext.of(context);
|
final ctx = DrawerContext.of(context);
|
||||||
|
final featureCtx = FeatureContext.of(context);
|
||||||
|
|
||||||
return ListTile(
|
return Drawer(
|
||||||
title: Text(text, style: TextStyle(color: Color(0xffe9e9e9))),
|
child: ListView(children: [
|
||||||
leading: Icon(icon, color: Color(0xffe9e9e9)),
|
ListTile(
|
||||||
onTap: () {
|
title: const Text('Home'),
|
||||||
ctx.onChangePage(section);
|
leading: const Icon(Icons.home),
|
||||||
Navigator.pop(context);
|
onTap: () {
|
||||||
},
|
ctx.onChangePage(Section.HOME);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Shuffle'),
|
||||||
|
leading: const Icon(Icons.update),
|
||||||
|
onTap: () {
|
||||||
|
ctx.onChangePage(Section.SHUFFLE);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Categories'),
|
||||||
|
leading: const Icon(Icons.category),
|
||||||
|
onTap: () {
|
||||||
|
ctx.onChangePage(Section.CATEGORIE);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Actors'),
|
||||||
|
leading: const Icon(Icons.people),
|
||||||
|
onTap: () {
|
||||||
|
ctx.onChangePage(Section.ACTOR);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (featureCtx.tvShowEnabled)
|
||||||
|
ListTile(
|
||||||
|
title: const Text('TV Shows'),
|
||||||
|
leading: const Icon(Icons.tv),
|
||||||
|
onTap: () {
|
||||||
|
ctx.onChangePage(Section.TVSHOW);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Settings'),
|
||||||
|
leading: const Icon(Icons.settings),
|
||||||
|
onTap: () {
|
||||||
|
ctx.onChangePage(Section.SETTING);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ class _LoginContainerState extends State<LoginContainer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _init() async {
|
void _init() async {
|
||||||
final token = await getToken();
|
final token = await Token.getInstance().getToken();
|
||||||
Log.i("The token value is $token");
|
Log.i("The token value is $token");
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -3,9 +3,8 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
import '../api/settings_api.dart';
|
import '../api/settings_api.dart';
|
||||||
import '../db/settings_db.dart';
|
import '../api/token.dart';
|
||||||
import '../log/log.dart';
|
import '../log/log.dart';
|
||||||
import 'login_context.dart';
|
import 'login_context.dart';
|
||||||
|
|
||||||
@ -45,13 +44,12 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
final json = jsonDecode(resp.body);
|
final json = jsonDecode(resp.body);
|
||||||
final token = json["Token"];
|
final token = json["Token"];
|
||||||
|
|
||||||
SettingsT settings = await SettingsDB.getInstance().getSettings();
|
// todo bit hacky
|
||||||
settings.domain = domain;
|
Token.getInstance().setToken(token, domain, "temp", "temp");
|
||||||
settings.token = token;
|
// we need to call this twice because we need for the loadInitialData an api token
|
||||||
SettingsDB.getInstance().setSettings(settings);
|
final initalData = await loadInitialData();
|
||||||
// we need two steps here because we need an authenticated api call for the videopath
|
Token.getInstance()
|
||||||
settings.videopath = (await loadInitialData()).videoPath;
|
.setToken(token, domain, initalData.videoPath, initalData.tvShowPath);
|
||||||
SettingsDB.getInstance().setSettings(settings);
|
|
||||||
LoginContext.of(context).onLoggin(true);
|
LoginContext.of(context).onLoggin(true);
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/foundation.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:media_kit/media_kit.dart';
|
|
||||||
|
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
import 'db/database.dart';
|
import 'db/database.dart';
|
||||||
@ -11,17 +10,12 @@ import 'utils/platform.dart';
|
|||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
Log.i("App init!");
|
Log.i("App init!");
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
if (isDesktop()) {
|
||||||
MediaKit.ensureInitialized();
|
DartVLC.initialize();
|
||||||
|
} else {
|
||||||
if (!kIsWeb && !isDesktop()) {
|
|
||||||
Log.i("init device info");
|
|
||||||
await loadDeviceInfo();
|
await loadDeviceInfo();
|
||||||
}
|
}
|
||||||
|
Db().init();
|
||||||
Log.i("Mediakit initialized");
|
|
||||||
|
|
||||||
await Db().init();
|
|
||||||
|
|
||||||
runApp(Shortcuts(shortcuts: <LogicalKeySet, Intent>{
|
runApp(Shortcuts(shortcuts: <LogicalKeySet, Intent>{
|
||||||
LogicalKeySet(LogicalKeyboardKey.select): ActivateIntent(),
|
LogicalKeySet(LogicalKeyboardKey.select): ActivateIntent(),
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:openmediacentermobile/db/settings_db.dart';
|
import '../utils/file_formatter.dart';
|
||||||
|
|
||||||
import '../api/token.dart';
|
import '../api/token.dart';
|
||||||
import '../db/database.dart';
|
import '../db/database.dart';
|
||||||
import '../drawer/my_drawer.dart';
|
import '../drawer/my_drawer.dart';
|
||||||
import '../login/login_context.dart';
|
import '../login/login_context.dart';
|
||||||
import '../utils/file_formatter.dart';
|
|
||||||
|
|
||||||
class SettingsScreen extends StatefulWidget {
|
class SettingsScreen extends StatefulWidget {
|
||||||
const SettingsScreen({Key? key}) : super(key: key);
|
const SettingsScreen({Key? key}) : super(key: key);
|
||||||
@ -25,7 +24,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
dbsize = v;
|
dbsize = v;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
getToken().then((value) => setState(() {
|
Token.getInstance().getToken().then((value) => setState(() {
|
||||||
serverUrl = value?.domain ?? "unknown";
|
serverUrl = value?.domain ?? "unknown";
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -54,8 +53,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
loginCtx.onLoggin(false);
|
loginCtx.onLoggin(false);
|
||||||
SettingsDB.getInstance()
|
Token.getInstance().setToken("", "", "", "");
|
||||||
.setSettings(SettingsT("", "", "", 0));
|
|
||||||
Db().clear();
|
Db().clear();
|
||||||
},
|
},
|
||||||
child: Text("Logout"))
|
child: Text("Logout"))
|
||||||
|
15
lib/navigation/tv_show_screen.dart
Normal file
15
lib/navigation/tv_show_screen.dart
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TVShowScreen extends StatefulWidget {
|
||||||
|
const TVShowScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TVShowScreen> createState() => _TVShowScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TVShowScreenState extends State<TVShowScreen> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,9 @@ 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 '../utils/platform.dart';
|
||||||
import '../screen_loading.dart';
|
import '../screen_loading.dart';
|
||||||
import '../types/video.dart';
|
import '../types/video.dart';
|
||||||
import '../utils/platform.dart';
|
|
||||||
import 'preview_tile.dart';
|
import 'preview_tile.dart';
|
||||||
|
|
||||||
class PreviewGrid extends StatefulWidget {
|
class PreviewGrid extends StatefulWidget {
|
||||||
@ -60,7 +60,7 @@ class _PreviewGridState extends State<PreviewGrid> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text("Error" + snapshot.error.toString()),
|
Text("Error"),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => loadData(), child: Text("Reload page"))
|
onPressed: () => loadData(), child: Text("Reload page"))
|
||||||
],
|
],
|
||||||
@ -78,53 +78,50 @@ class _PreviewGridState extends State<PreviewGrid> {
|
|||||||
Widget _mainGrid(List<VideoT> data, double width) {
|
Widget _mainGrid(List<VideoT> data, double width) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Column(
|
||||||
color: Color(0xff999999),
|
children: [
|
||||||
child: Column(
|
if (widget.headerBuilder != null) widget.headerBuilder!(this),
|
||||||
children: [
|
data.length > 0
|
||||||
if (widget.headerBuilder != null) widget.headerBuilder!(this),
|
? Expanded(
|
||||||
data.length > 0
|
child: MasonryGridView.count(
|
||||||
? Expanded(
|
// every tile should be at max 330 pixels long...
|
||||||
child: MasonryGridView.count(
|
crossAxisCount: isTV() ? width ~/ 200 : width ~/ 275,
|
||||||
// every tile should be at max 330 pixels long...
|
// crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330,
|
||||||
crossAxisCount: isTV() ? width ~/ 200 : width ~/ 275,
|
itemCount: data.length,
|
||||||
// crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330,
|
mainAxisSpacing: 4,
|
||||||
itemCount: data.length,
|
crossAxisSpacing: 4,
|
||||||
mainAxisSpacing: 4,
|
padding: EdgeInsets.all(5),
|
||||||
crossAxisSpacing: 4,
|
itemBuilder: (context, index) {
|
||||||
padding: EdgeInsets.all(5),
|
return PreviewTile(
|
||||||
itemBuilder: (context, index) {
|
dta: data[index],
|
||||||
return PreviewTile(
|
onLongPress: (img) {
|
||||||
dta: data[index],
|
setState(() {
|
||||||
onLongPress: (img) {
|
_previewImage = img;
|
||||||
setState(() {
|
});
|
||||||
_previewImage = img;
|
},
|
||||||
});
|
onLongPressEnd: () {
|
||||||
},
|
setState(() {
|
||||||
onLongPressEnd: () {
|
_previewImage = null;
|
||||||
setState(() {
|
});
|
||||||
_previewImage = null;
|
},
|
||||||
});
|
);
|
||||||
},
|
},
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: 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),
|
)
|
||||||
],
|
: 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 (_previewImage != null) ..._buildPreviewImage(),
|
if (_previewImage != null) ..._buildPreviewImage(),
|
||||||
],
|
],
|
||||||
|
@ -5,8 +5,8 @@ import 'package:sqflite/sqflite.dart';
|
|||||||
import '../api/video_api.dart';
|
import '../api/video_api.dart';
|
||||||
import '../db/database.dart';
|
import '../db/database.dart';
|
||||||
import '../log/log.dart';
|
import '../log/log.dart';
|
||||||
import '../types/video.dart';
|
|
||||||
import '../utils/platform.dart';
|
import '../utils/platform.dart';
|
||||||
|
import '../types/video.dart';
|
||||||
import '../video_screen/videoscreen.dart';
|
import '../video_screen/videoscreen.dart';
|
||||||
|
|
||||||
class PreviewTile extends StatefulWidget {
|
class PreviewTile extends StatefulWidget {
|
||||||
@ -76,8 +76,7 @@ class _PreviewTileState extends State<PreviewTile> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// precache image to avoid loading time to render image
|
// precache image to avoid loading time to render image
|
||||||
if(context.mounted)
|
await precacheImage(img.image, context);
|
||||||
await precacheImage(img.image, context);
|
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
@ -104,28 +103,18 @@ class _PreviewTileState extends State<PreviewTile> {
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
color: const Color(0xff3f3f3f),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(20.0),
|
|
||||||
child: image,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 3,
|
|
||||||
),
|
|
||||||
Text(
|
Text(
|
||||||
widget.dta.title,
|
widget.dta.title,
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: isTV() ? 8 : 10.5),
|
||||||
fontSize: isTV() ? 8 : 10.5, color: const Color(0xffe9e9e9)),
|
|
||||||
overflow: TextOverflow.clip,
|
overflow: TextOverflow.clip,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
image
|
||||||
height: 3,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
color: Color(0x6a94a6ff),
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Material(
|
child: Material(
|
||||||
@ -158,24 +147,21 @@ class _PreviewTileState extends State<PreviewTile> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ConstrainedBox(
|
return FutureBuilder<Image>(
|
||||||
constraints: const BoxConstraints(minHeight: 200, minWidth: 200),
|
future: _preview, // a previously-obtained Future<String> or null
|
||||||
child: FutureBuilder<Image>(
|
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
|
||||||
future: _preview, // a previously-obtained Future<String> or null
|
if (snapshot.connectionState != ConnectionState.done) {
|
||||||
builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
|
return _buildLoader();
|
||||||
if (snapshot.connectionState != ConnectionState.done) {
|
}
|
||||||
return _buildLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Text("Error");
|
return Text("Error");
|
||||||
} else if (snapshot.hasData) {
|
} else if (snapshot.hasData) {
|
||||||
return _buildTile(snapshot.data!);
|
return _buildTile(snapshot.data!);
|
||||||
} else {
|
} else {
|
||||||
return _buildLoader();
|
return _buildLoader();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
92
lib/utils/feature_context.dart
Normal file
92
lib/utils/feature_context.dart
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:openmediacentermobile/login/login_context.dart';
|
||||||
|
import '../api/settings_api.dart';
|
||||||
|
|
||||||
|
// todo maybe instead of feature context a context for all settings?
|
||||||
|
class FeatureContext extends InheritedWidget {
|
||||||
|
const FeatureContext(this.tvShowEnabled, this.fullDeleteEnabled,
|
||||||
|
{Key? key, required Widget child})
|
||||||
|
: super(key: key, child: child);
|
||||||
|
|
||||||
|
final bool tvShowEnabled;
|
||||||
|
final bool fullDeleteEnabled;
|
||||||
|
|
||||||
|
static FeatureContext of(BuildContext context) {
|
||||||
|
final FeatureContext? result =
|
||||||
|
context.dependOnInheritedWidgetOfExactType<FeatureContext>();
|
||||||
|
assert(result != null, 'No LoginContext found in context');
|
||||||
|
return result!;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(FeatureContext old) {
|
||||||
|
return tvShowEnabled != old.tvShowEnabled ||
|
||||||
|
fullDeleteEnabled != old.fullDeleteEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FeatureContainer extends StatefulWidget {
|
||||||
|
const FeatureContainer({Key? key, required this.child}) : super(key: key);
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FeatureContainer> createState() => _FeatureContainerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FeatureContainerState extends State<FeatureContainer> {
|
||||||
|
bool? tvShowEnabled;
|
||||||
|
bool? fullDeleteEnabled;
|
||||||
|
bool fetcherror = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
loadInitialData()
|
||||||
|
.then((value) => setState(
|
||||||
|
() {
|
||||||
|
fullDeleteEnabled = value.fullDeleteEnabled;
|
||||||
|
tvShowEnabled = value.tvShowEnabled;
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.catchError((err) => setState(() => fetcherror = true));
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (fetcherror) {
|
||||||
|
final loginctx = LoginContext.of(context);
|
||||||
|
|
||||||
|
return MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child:
|
||||||
|
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
|
Text("Fetch error"),
|
||||||
|
MaterialButton(
|
||||||
|
onPressed: () => loginctx.onLoggin(false),
|
||||||
|
child: Text("Logout"),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (tvShowEnabled == null || fullDeleteEnabled == null) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [CircularProgressIndicator(), Text("loading features")],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return FeatureContext(tvShowEnabled!, fullDeleteEnabled!,
|
||||||
|
child: widget.child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,18 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:media_kit/media_kit.dart';
|
|
||||||
import 'package:media_kit_video/media_kit_video.dart';
|
|
||||||
import 'package:openmediacentermobile/db/settings_db.dart';
|
|
||||||
|
|
||||||
|
import '../api/token.dart';
|
||||||
import '../api/video_api.dart';
|
import '../api/video_api.dart';
|
||||||
|
import '../utils/platform.dart';
|
||||||
import '../screen_loading.dart';
|
import '../screen_loading.dart';
|
||||||
import '../types/video.dart';
|
import '../types/video.dart';
|
||||||
import '../types/video_data.dart';
|
import '../types/video_data.dart';
|
||||||
import '../utils/platform.dart';
|
|
||||||
import 'info_view.dart';
|
import 'info_view.dart';
|
||||||
|
|
||||||
|
import 'videoscreen_desktop.dart'
|
||||||
|
if (dart.library.html) 'videoscreen_mobile.dart';
|
||||||
|
import 'videoscreen_mobile.dart';
|
||||||
|
|
||||||
class VideoScreen extends StatefulWidget {
|
class VideoScreen extends StatefulWidget {
|
||||||
const VideoScreen({Key? key, required this.metaData}) : super(key: key);
|
const VideoScreen({Key? key, required this.metaData}) : super(key: key);
|
||||||
final VideoT metaData;
|
final VideoT metaData;
|
||||||
@ -27,19 +28,16 @@ class _VideoScreenState extends State<VideoScreen> {
|
|||||||
PageController _controller = PageController(
|
PageController _controller = PageController(
|
||||||
initialPage: 0,
|
initialPage: 0,
|
||||||
);
|
);
|
||||||
// Create a [Player] to control playback.
|
|
||||||
late final player = Player();
|
|
||||||
// Create a [VideoController] to handle video output from [Player].
|
|
||||||
late final controller = VideoController(player);
|
|
||||||
|
|
||||||
String url = "";
|
String url = "";
|
||||||
|
|
||||||
void initPlayer() async {
|
void initPlayer() async {
|
||||||
final videodata = await _videoData;
|
final videodata = await _videoData;
|
||||||
|
|
||||||
final settings = await SettingsDB.getInstance().getSettings();
|
final token = await Token.getInstance().getToken();
|
||||||
final path = settings.domain + settings.videopath + videodata.movieUrl;
|
if (token == null) return;
|
||||||
player.open(Media(path));
|
|
||||||
|
final path = token.domain + token.videoPath + videodata.movieUrl;
|
||||||
|
|
||||||
url = path;
|
url = path;
|
||||||
}
|
}
|
||||||
@ -55,7 +53,6 @@ class _VideoScreenState extends State<VideoScreen> {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
player.dispose();
|
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
_appBarTimer?.cancel();
|
_appBarTimer?.cancel();
|
||||||
}
|
}
|
||||||
@ -115,7 +112,13 @@ class _VideoScreenState extends State<VideoScreen> {
|
|||||||
controller: _controller,
|
controller: _controller,
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: Video(controller: controller)),
|
child: isDesktop()
|
||||||
|
? VideoScreenDesktop(
|
||||||
|
url: url,
|
||||||
|
)
|
||||||
|
: VideoScreenMobile(
|
||||||
|
url: url,
|
||||||
|
)),
|
||||||
InfoView(
|
InfoView(
|
||||||
videoId: widget.metaData.id,
|
videoId: widget.metaData.id,
|
||||||
)
|
)
|
||||||
@ -130,10 +133,7 @@ class _VideoScreenState extends State<VideoScreen> {
|
|||||||
leading: new IconButton(
|
leading: new IconButton(
|
||||||
icon: new Icon(Icons.arrow_back_ios,
|
icon: new Icon(Icons.arrow_back_ios,
|
||||||
color: Colors.grey),
|
color: Colors.grey),
|
||||||
onPressed: () async {
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
await player.stop();
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Theme.of(context).primaryColor.withOpacity(0.3),
|
Theme.of(context).primaryColor.withOpacity(0.3),
|
||||||
|
52
lib/video_screen/videoscreen_desktop.dart
Normal file
52
lib/video_screen/videoscreen_desktop.dart
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:dart_vlc/dart_vlc.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class VideoScreenDesktop extends StatefulWidget {
|
||||||
|
const VideoScreenDesktop({Key? key, required this.url}) : super(key: key);
|
||||||
|
final String url;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<VideoScreenDesktop> createState() => _VideoScreenDesktopState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoScreenDesktopState extends State<VideoScreenDesktop> {
|
||||||
|
Player _player = Player(id: Random().nextInt(0x7fffffff));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Video(
|
||||||
|
player: _player,
|
||||||
|
showFullscreenButton: true,
|
||||||
|
scale: 1.0, // default
|
||||||
|
showControls: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
final media2 = Media.network(widget.url);
|
||||||
|
|
||||||
|
_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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(() {});
|
||||||
|
}
|
||||||
|
}
|
@ -6,14 +6,22 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
#include <dart_vlc/dart_vlc_plugin.h>
|
||||||
#include <media_kit_video/media_kit_video_plugin.h>
|
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||||
|
#include <screen_retriever/screen_retriever_plugin.h>
|
||||||
|
#include <window_manager/window_manager_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar =
|
g_autoptr(FlPluginRegistrar) dart_vlc_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "DartVlcPlugin");
|
||||||
media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar);
|
dart_vlc_plugin_register_with_registrar(dart_vlc_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) media_kit_video_registrar =
|
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||||
media_kit_video_plugin_register_with_registrar(media_kit_video_registrar);
|
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
|
||||||
|
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) window_manager_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
|
||||||
|
window_manager_plugin_register_with_registrar(window_manager_registrar);
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
media_kit_libs_linux
|
dart_vlc
|
||||||
media_kit_video
|
flutter_secure_storage_linux
|
||||||
|
screen_retriever
|
||||||
|
window_manager
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
media_kit_native_event_loop
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
758
pubspec.lock
758
pubspec.lock
File diff suppressed because it is too large
Load Diff
16
pubspec.yaml
16
pubspec.yaml
@ -34,23 +34,17 @@ dependencies:
|
|||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
|
flutter_secure_storage: ^6.0.0
|
||||||
logger: ^1.1.0
|
logger: ^1.1.0
|
||||||
http: ^0.13.4
|
http: ^0.13.4
|
||||||
flutter_staggered_grid_view: ^0.6.1
|
flutter_staggered_grid_view: ^0.6.1
|
||||||
device_info_plus: ^8.0.0
|
dart_vlc: ^0.3.0
|
||||||
|
device_info_plus: ^4.0.0
|
||||||
|
video_player: ^2.3.0
|
||||||
|
chewie: ^1.3.2
|
||||||
sqflite: ^2.0.3+1
|
sqflite: ^2.0.3+1
|
||||||
path: ^1.8.1
|
path: ^1.8.1
|
||||||
sqflite_common_ffi: ^2.1.1+1
|
sqflite_common_ffi: ^2.1.1+1
|
||||||
sqflite_common_ffi_web: '^0.3.6'
|
|
||||||
|
|
||||||
media_kit: ^1.0.2 # Primary package.
|
|
||||||
|
|
||||||
media_kit_video: ^1.0.2 # For video rendering.
|
|
||||||
|
|
||||||
media_kit_native_event_loop: ^1.0.6 # Support for higher number of concurrent instances & better performance.
|
|
||||||
|
|
||||||
media_kit_libs_android_video: ^1.1.1 # Android package for video native libraries.
|
|
||||||
media_kit_libs_linux: ^1.0.2 # GNU/Linux dependency package.
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user