Compare commits
	
		
			1 Commits
		
	
	
		
			master
			...
			better_pla
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| dc87a4369e | 
							
								
								
									
										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' |  | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' | |||||||
| apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" | ||||||
|  |  | ||||||
| android { | android { | ||||||
|     compileSdkVersion 33 |     compileSdkVersion flutter.compileSdkVersion | ||||||
|  |  | ||||||
|     compileOptions { |     compileOptions { | ||||||
|         sourceCompatibility JavaVersion.VERSION_1_8 |         sourceCompatibility JavaVersion.VERSION_1_8 | ||||||
|   | |||||||
| @@ -1,12 +1,12 @@ | |||||||
| buildscript { | buildscript { | ||||||
|     ext.kotlin_version = '1.6.10' |     ext.kotlin_version = '1.4.32' | ||||||
|     repositories { |     repositories { | ||||||
|         google() |         google() | ||||||
|         mavenCentral() |         mavenCentral() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     dependencies { |     dependencies { | ||||||
|         classpath 'com.android.tools.build:gradle:7.1.2' |         classpath 'com.android.tools.build:gradle:4.1.0' | ||||||
|         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" |         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME | |||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| zipStoreBase=GRADLE_USER_HOME | zipStoreBase=GRADLE_USER_HOME | ||||||
| zipStorePath=wrapper/dists | zipStorePath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
|  |  | ||||||
| import '../log/log.dart'; |  | ||||||
| import '../types/actor.dart'; | import '../types/actor.dart'; | ||||||
| import 'api.dart'; | import 'api.dart'; | ||||||
|  |  | ||||||
| @@ -11,26 +10,3 @@ Future<List<Actor>> loadAllActors() async { | |||||||
|   final actors = d.map((e) => Actor.fromJson(e)).toList(growable: false); |   final actors = d.map((e) => Actor.fromJson(e)).toList(growable: false); | ||||||
|   return actors; |   return actors; | ||||||
| } | } | ||||||
|  |  | ||||||
| Future<List<Actor>> loadActorsOfVideo(int movieId) async { |  | ||||||
|   final data = |  | ||||||
|       await API.query("actor", "getActorsOfVideo", {'MovieId': movieId}); |  | ||||||
|   if (data == 'null') { |  | ||||||
|     return []; |  | ||||||
|   } |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|  |  | ||||||
|   List<Actor> dta = (d as List).map((e) => Actor.fromJson(e)).toList(); |  | ||||||
|  |  | ||||||
|   return dta; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Future<void> addActorToVideo(int actorId, int movieId) async { |  | ||||||
|   final data = await API.query( |  | ||||||
|       "actor", "addActorToVideo", {'ActorId': actorId, 'MovieId': movieId}); |  | ||||||
|  |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|   if (d["result"] != "success") { |  | ||||||
|     Log.w("couldn't add actor to video"); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -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,42 +0,0 @@ | |||||||
| import 'dart:convert'; |  | ||||||
|  |  | ||||||
| import 'api.dart'; |  | ||||||
|  |  | ||||||
| class InitialData { |  | ||||||
|   bool darkMode; |  | ||||||
|   bool password; |  | ||||||
|   String mediacenterName; |  | ||||||
|   String videoPath; |  | ||||||
|   String tvShowPath; |  | ||||||
|   bool tvShowEnabled; |  | ||||||
|   bool fullDeleteEnabled; |  | ||||||
|  |  | ||||||
|   InitialData( |  | ||||||
|       this.darkMode, |  | ||||||
|       this.password, |  | ||||||
|       this.mediacenterName, |  | ||||||
|       this.videoPath, |  | ||||||
|       this.tvShowPath, |  | ||||||
|       this.tvShowEnabled, |  | ||||||
|       this.fullDeleteEnabled); |  | ||||||
|  |  | ||||||
|   factory InitialData.fromJson(dynamic json) { |  | ||||||
|     return InitialData( |  | ||||||
|       json['DarkMode'] as bool, |  | ||||||
|       json['Pasword'] as bool, |  | ||||||
|       json['MediacenterName'] as String, |  | ||||||
|       json['VideoPath'] as String, |  | ||||||
|       json['TVShowPath'] as String, |  | ||||||
|       json['TVShowEnabled'] as bool, |  | ||||||
|       json['FullDeleteEnabled'] as bool, |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Future<InitialData> loadInitialData() async { |  | ||||||
|   final data = await API.query("settings", "loadInitialData", {}); |  | ||||||
|  |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|   final video = InitialData.fromJson(d); |  | ||||||
|   return video; |  | ||||||
| } |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| import 'dart:convert'; |  | ||||||
|  |  | ||||||
| import '../log/log.dart'; |  | ||||||
| import '../types/tag.dart'; |  | ||||||
| import 'api.dart'; |  | ||||||
|  |  | ||||||
| Future<List<Tag>> loadAllTags() async { |  | ||||||
|   final data = await API.query("tags", "getAllTags", {}); |  | ||||||
|  |  | ||||||
|   final d = (jsonDecode(data) ?? []) as List<dynamic>; |  | ||||||
|   final tags = d.map((e) => Tag.fromJson(e)).toList(growable: false); |  | ||||||
|   return tags; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Future<void> addTagToVideo(int tagId, int movieId) async { |  | ||||||
|   final data = |  | ||||||
|       await API.query("tags", "addTag", {'TagId': tagId, 'MovieId': movieId}); |  | ||||||
|  |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|   if (d["result"] != "success") { |  | ||||||
|     Log.w("couldn't add actor to video"); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,6 +1,9 @@ | |||||||
| 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; | ||||||
| @@ -9,11 +12,47 @@ class TokenT { | |||||||
|   TokenT(this.token, this.domain); |   TokenT(this.token, this.domain); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class Token { | ||||||
|  |   static final Token _token = Token._(); | ||||||
|  |   final _storage = const FlutterSecureStorage(); | ||||||
|  |  | ||||||
|  |   String _tokenval = ""; | ||||||
|  |   String _domain = ""; | ||||||
|  |  | ||||||
|  |   static Token getInstance() { | ||||||
|  |     return _token; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   Future<TokenT?> getToken() async { |   Future<TokenT?> getToken() async { | ||||||
|   final settings = await SettingsDB.getInstance().getSettings(); |     var completer = Completer<TokenT?>(); | ||||||
|   if (settings.token == "" || settings.domain == "") { |  | ||||||
|     return null; |     if (_tokenval == "" || _domain == "") { | ||||||
|  |       Log.d("reading token store"); | ||||||
|  |       WidgetsFlutterBinding.ensureInitialized(); | ||||||
|  |       final token = await _storage.read(key: 'jwt'); | ||||||
|  |       final domain = await _storage.read(key: 'domain'); | ||||||
|  |  | ||||||
|  |       // check if value is defined in phone store | ||||||
|  |       if (token != null && domain != null) { | ||||||
|  |         _tokenval = token; | ||||||
|  |         _domain = domain; | ||||||
|  |         completer.complete(TokenT(token, domain)); | ||||||
|       } else { |       } else { | ||||||
|     return TokenT(settings.token, settings.domain); |         Log.d("no token defined"); | ||||||
|  |         completer.complete(null); | ||||||
|       } |       } | ||||||
|  |     } else { | ||||||
|  |       completer.complete(TokenT(_tokenval, _domain)); | ||||||
|  |     } | ||||||
|  |     return completer.future; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setToken(String token, String domain) { | ||||||
|  |     _tokenval = token; | ||||||
|  |     _domain = domain; | ||||||
|  |     _storage.write(key: 'jwt', value: token); | ||||||
|  |     _storage.write(key: 'domain', value: domain); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Token._(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,11 +1,5 @@ | |||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
| import 'dart:math'; |  | ||||||
| import 'dart:typed_data'; |  | ||||||
|  |  | ||||||
| import '../log/log.dart'; |  | ||||||
| import '../types/actor.dart'; |  | ||||||
| import '../types/tag.dart'; |  | ||||||
| import '../types/video.dart'; |  | ||||||
| import '../types/video_data.dart'; | import '../types/video_data.dart'; | ||||||
| import 'api.dart'; | import 'api.dart'; | ||||||
|  |  | ||||||
| @@ -16,55 +10,3 @@ Future<VideoData> loadVideoData(int videoId) async { | |||||||
|   final video = VideoData.fromJson(d); |   final video = VideoData.fromJson(d); | ||||||
|   return video; |   return video; | ||||||
| } | } | ||||||
|  |  | ||||||
| Future<List<VideoT>> loadVideo(Tag? tag, int filterIdx) async { |  | ||||||
|   final data = await API |  | ||||||
|       .query("video", "getMovies", {'Tag': tag?.tagId ?? 1, 'Sort': filterIdx}); |  | ||||||
|  |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|  |  | ||||||
|   List<VideoT> dta = |  | ||||||
|       (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList(); |  | ||||||
|  |  | ||||||
|   return dta; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Future<List<VideoT>> loadShuffledVideos(int nr) async { |  | ||||||
|   final data = await API.query("video", "getRandomMovies", |  | ||||||
|       {'Number': nr, 'Seed': Random().nextInt(0x7fffffff)}); |  | ||||||
|  |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|  |  | ||||||
|   List<VideoT> dta = |  | ||||||
|       (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList(); |  | ||||||
|  |  | ||||||
|   return dta; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Future<List<VideoT>> loadVideoByActor(Actor actor) async { |  | ||||||
|   final data = |  | ||||||
|       await API.query("actor", "getActorInfo", {'ActorId': actor.actorId}); |  | ||||||
|  |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|  |  | ||||||
|   List<VideoT> dta = |  | ||||||
|       (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList(); |  | ||||||
|  |  | ||||||
|   return dta; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Future<bool> addLike(int movieId) async { |  | ||||||
|   final data = await API.query("video", "addLike", {'MovieId': movieId}); |  | ||||||
|   final d = jsonDecode(data); |  | ||||||
|   if (d["result"] != 'success') { |  | ||||||
|     Log.w(d); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return d["result"] == 'success'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Future<Uint8List> fetchThumbnail(int movieId) async { |  | ||||||
|   final base64str = |  | ||||||
|       await API.query("video", "readThumbnail", {'Movieid': movieId}); |  | ||||||
|   return base64Decode(base64str.substring(23)); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -5,14 +5,13 @@ import 'package:openmediacentermobile/log/log.dart'; | |||||||
| import 'package:openmediacentermobile/login/login_screen.dart'; | import 'package:openmediacentermobile/login/login_screen.dart'; | ||||||
|  |  | ||||||
| import 'drawer/drawer_page.dart'; | import 'drawer/drawer_page.dart'; | ||||||
| import 'login/login_context.dart'; | import 'login/logincontext.dart'; | ||||||
|  |  | ||||||
| class AppScrollBehavior extends MaterialScrollBehavior { | class AppScrollBehavior extends MaterialScrollBehavior { | ||||||
|   @override |   @override | ||||||
|   Set<PointerDeviceKind> get dragDevices => { |   Set<PointerDeviceKind> get dragDevices => { | ||||||
|         PointerDeviceKind.touch, |         PointerDeviceKind.touch, | ||||||
|         PointerDeviceKind.mouse, |         PointerDeviceKind.mouse, | ||||||
|         PointerDeviceKind.trackpad |  | ||||||
|       }; |       }; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -29,8 +28,6 @@ class App extends StatelessWidget { | |||||||
|       return const MaterialApp(home: LoginScreen()); |       return const MaterialApp(home: LoginScreen()); | ||||||
|     } else { |     } else { | ||||||
|       return MaterialApp( |       return MaterialApp( | ||||||
|           theme: ThemeData( |  | ||||||
|               appBarTheme: AppBarTheme(backgroundColor: Color(0xff0d0d0d))), |  | ||||||
|           scrollBehavior: AppScrollBehavior(), |           scrollBehavior: AppScrollBehavior(), | ||||||
|           home: DrawerPage( |           home: DrawerPage( | ||||||
|             title: 'OpenMediaCenter', |             title: 'OpenMediaCenter', | ||||||
|   | |||||||
| @@ -1,47 +1,43 @@ | |||||||
| 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( | ||||||
|  |       // 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. | ||||||
|       dbpath, |       dbpath, | ||||||
|       onCreate: (db, version) { |       onCreate: (db, version) { | ||||||
|         final batch = db.batch(); |         // Run the CREATE TABLE statement on the database. | ||||||
|         batch.execute( |         return db.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 +50,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._(); |  | ||||||
| } |  | ||||||
| @@ -1,6 +1,10 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| import '../api/actor_api.dart'; | import '../api/actor_api.dart'; | ||||||
|  | import '../api/api.dart'; | ||||||
|  | import '../log/log.dart'; | ||||||
| import '../screen_loading.dart'; | import '../screen_loading.dart'; | ||||||
| import '../types/actor.dart'; | import '../types/actor.dart'; | ||||||
|  |  | ||||||
| @@ -15,6 +19,16 @@ class AddActorDialog extends StatefulWidget { | |||||||
| class _AddActorDialogState extends State<AddActorDialog> { | class _AddActorDialogState extends State<AddActorDialog> { | ||||||
|   late Future<List<Actor>> actors = loadAllActors(); |   late Future<List<Actor>> actors = loadAllActors(); | ||||||
|  |  | ||||||
|  |   Future<void> addActorToVideo(int actorId) async { | ||||||
|  |     final data = await API.query("actor", "addActorToVideo", | ||||||
|  |         {'ActorId': actorId, 'MovieId': widget.movieId}); | ||||||
|  |  | ||||||
|  |     final d = jsonDecode(data); | ||||||
|  |     if (d["result"] != "success") { | ||||||
|  |       Log.w("couldn't add actor to video"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
| @@ -32,15 +46,13 @@ 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 | ||||||
|                     .map((e) => ListTile( |                     .map((e) => ListTile( | ||||||
|                           title: Text(e.name), |                           title: Text(e.name), | ||||||
|                           onTap: () async { |                           onTap: () async { | ||||||
|                             await addActorToVideo(e.actorId, widget.movieId); |                             await addActorToVideo(e.actorId); | ||||||
|                             Navigator.pop(context, e); |                             Navigator.pop(context, e); | ||||||
|                           }, |                           }, | ||||||
|                         )) |                         )) | ||||||
|   | |||||||
| @@ -1,6 +1,9 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| import '../api/tag_api.dart'; | import '../api/api.dart'; | ||||||
|  | import '../log/log.dart'; | ||||||
| import '../screen_loading.dart'; | import '../screen_loading.dart'; | ||||||
| import '../types/tag.dart'; | import '../types/tag.dart'; | ||||||
|  |  | ||||||
| @@ -15,6 +18,24 @@ class AddTagDialog extends StatefulWidget { | |||||||
| class _AddTagDialogState extends State<AddTagDialog> { | class _AddTagDialogState extends State<AddTagDialog> { | ||||||
|   late Future<List<Tag>> tags = loadAllTags(); |   late Future<List<Tag>> tags = loadAllTags(); | ||||||
|  |  | ||||||
|  |   Future<List<Tag>> loadAllTags() async { | ||||||
|  |     final data = await API.query("tags", "getAllTags", {}); | ||||||
|  |  | ||||||
|  |     final d = (jsonDecode(data) ?? []) as List<dynamic>; | ||||||
|  |     final tags = d.map((e) => Tag.fromJson(e)).toList(growable: false); | ||||||
|  |     return tags; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<void> addTagToVideo(int tagId) async { | ||||||
|  |     final data = await API | ||||||
|  |         .query("tags", "addTag", {'TagId': tagId, 'MovieId': widget.movieId}); | ||||||
|  |  | ||||||
|  |     final d = jsonDecode(data); | ||||||
|  |     if (d["result"] != "success") { | ||||||
|  |       Log.w("couldn't add actor to video"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
| @@ -32,10 +53,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 | ||||||
| @@ -43,7 +60,7 @@ class _AddTagDialogState extends State<AddTagDialog> { | |||||||
|                       (e) => ListTile( |                       (e) => ListTile( | ||||||
|                         title: Text(e.tagName), |                         title: Text(e.tagName), | ||||||
|                         onTap: () async { |                         onTap: () async { | ||||||
|                           await addTagToVideo(e.tagId, widget.movieId); |                           await addTagToVideo(e.tagId); | ||||||
|                           Navigator.pop(context, e); |                           Navigator.pop(context, e); | ||||||
|                         }, |                         }, | ||||||
|                       ), |                       ), | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:openmediacentermobile/navigation/settings_screen.dart'; | 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/shufflescreen.dart'; | ||||||
| import '../navigation/video_feed.dart'; | import '../navigation/video_feed.dart'; | ||||||
| import 'drawer_context.dart'; | import 'drawer_context.dart'; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,32 +7,52 @@ 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); | ||||||
|  |  | ||||||
|     return ListTile( |     return Drawer( | ||||||
|       title: Text(text, style: TextStyle(color: Color(0xffe9e9e9))), |       child: ListView(children: [ | ||||||
|       leading: Icon(icon, color: Color(0xffe9e9e9)), |         ListTile( | ||||||
|  |           title: const Text('Home'), | ||||||
|  |           leading: const Icon(Icons.home), | ||||||
|           onTap: () { |           onTap: () { | ||||||
|         ctx.onChangePage(section); |             ctx.onChangePage(Section.HOME); | ||||||
|             Navigator.pop(context); |             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); | ||||||
|  |           }, | ||||||
|  |         ), | ||||||
|  |         ListTile( | ||||||
|  |           title: const Text('Settings'), | ||||||
|  |           leading: const Icon(Icons.settings), | ||||||
|  |           onTap: () { | ||||||
|  |             ctx.onChangePage(Section.SETTING); | ||||||
|  |             Navigator.pop(context); | ||||||
|  |           }, | ||||||
|  |         ), | ||||||
|  |       ]), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,25 +0,0 @@ | |||||||
| import 'package:flutter/material.dart'; |  | ||||||
|  |  | ||||||
| class LoginContext extends InheritedWidget { |  | ||||||
|   const LoginContext( |  | ||||||
|       {Key? key, |  | ||||||
|       required Widget child, |  | ||||||
|       required this.loggedIn, |  | ||||||
|       required this.onLoggin}) |  | ||||||
|       : super(key: key, child: child); |  | ||||||
|  |  | ||||||
|   final bool loggedIn; |  | ||||||
|   final void Function(bool) onLoggin; |  | ||||||
|  |  | ||||||
|   static LoginContext of(BuildContext context) { |  | ||||||
|     final LoginContext? result = |  | ||||||
|         context.dependOnInheritedWidgetOfExactType<LoginContext>(); |  | ||||||
|     assert(result != null, 'No LoginContext found in context'); |  | ||||||
|     return result!; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   bool updateShouldNotify(LoginContext old) { |  | ||||||
|     return loggedIn != old.loggedIn; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -3,11 +3,9 @@ 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 'package:openmediacentermobile/api/token.dart'; | ||||||
| import '../api/settings_api.dart'; | import 'package:openmediacentermobile/log/log.dart'; | ||||||
| import '../db/settings_db.dart'; | import 'package:openmediacentermobile/login/logincontext.dart'; | ||||||
| import '../log/log.dart'; |  | ||||||
| import 'login_context.dart'; |  | ||||||
|  |  | ||||||
| class LoginScreen extends StatefulWidget { | class LoginScreen extends StatefulWidget { | ||||||
|   const LoginScreen({Key? key}) : super(key: key); |   const LoginScreen({Key? key}) : super(key: key); | ||||||
| @@ -41,46 +39,19 @@ class _LoginScreenState extends State<LoginScreen> { | |||||||
|  |  | ||||||
|     if (resp.statusCode != 200) { |     if (resp.statusCode != 200) { | ||||||
|       return "error" + resp.body; |       return "error" + resp.body; | ||||||
|  |  | ||||||
|  |       // compl.complete(resp.body); | ||||||
|     } else { |     } else { | ||||||
|       final json = jsonDecode(resp.body); |       final json = jsonDecode(resp.body); | ||||||
|       final token = json["Token"]; |       final token = json["Token"]; | ||||||
|  |  | ||||||
|       SettingsT settings = await SettingsDB.getInstance().getSettings(); |       Token.getInstance().setToken(token, domain); | ||||||
|       settings.domain = domain; |  | ||||||
|       settings.token = token; |  | ||||||
|       SettingsDB.getInstance().setSettings(settings); |  | ||||||
|       // we need two steps here because we need an authenticated api call for the videopath |  | ||||||
|       settings.videopath = (await loadInitialData()).videoPath; |  | ||||||
|       SettingsDB.getInstance().setSettings(settings); |  | ||||||
|       LoginContext.of(context).onLoggin(true); |       LoginContext.of(context).onLoggin(true); | ||||||
|  |  | ||||||
|       return ""; |       return ""; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> onLoginClick() async { |  | ||||||
|     Log.d("logging in"); |  | ||||||
|     final pwd = _passwordTextController.value.text; |  | ||||||
|     final domain = _domainTextController.value.text; |  | ||||||
|  |  | ||||||
|     var err = ""; |  | ||||||
|     if (domain.startsWith("https://") || domain.startsWith("http://")) { |  | ||||||
|       err = await login(pwd, domain); |  | ||||||
|       if (err.isEmpty) return; |  | ||||||
|     } else { |  | ||||||
|       // try to auto infering domain prefix |  | ||||||
|       err = await login(pwd, "https://" + domain); |  | ||||||
|       if (err.isEmpty) return; |  | ||||||
|       err = await login(pwd, "http://" + domain); |  | ||||||
|       if (err.isEmpty) return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Log.i(err); |  | ||||||
|     setState(() { |  | ||||||
|       error = err; |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void dispose() { |   void dispose() { | ||||||
|     _domainTextController.dispose(); |     _domainTextController.dispose(); | ||||||
| @@ -161,7 +132,33 @@ class _LoginScreenState extends State<LoginScreen> { | |||||||
|                                 backgroundColor: const Color(0xff4c505b), |                                 backgroundColor: const Color(0xff4c505b), | ||||||
|                                 child: IconButton( |                                 child: IconButton( | ||||||
|                                     color: Colors.white, |                                     color: Colors.white, | ||||||
|                                     onPressed: () async => await onLoginClick(), |                                     onPressed: () async { | ||||||
|  |                                       Log.d("clickkked"); | ||||||
|  |                                       final pwd = | ||||||
|  |                                           _passwordTextController.value.text; | ||||||
|  |                                       final domain = | ||||||
|  |                                           _domainTextController.value.text; | ||||||
|  |  | ||||||
|  |                                       var err = ""; | ||||||
|  |                                       if (domain.startsWith("https://") || | ||||||
|  |                                           domain.startsWith("http://")) { | ||||||
|  |                                         err = await login(pwd, domain); | ||||||
|  |                                         if (err.isEmpty) return; | ||||||
|  |                                       } else { | ||||||
|  |                                         // try to auto infering domain prefix | ||||||
|  |                                         err = await login( | ||||||
|  |                                             pwd, "https://" + domain); | ||||||
|  |                                         if (err.isEmpty) return; | ||||||
|  |                                         err = await login( | ||||||
|  |                                             pwd, "http://" + domain); | ||||||
|  |                                         if (err.isEmpty) return; | ||||||
|  |                                       } | ||||||
|  |  | ||||||
|  |                                       Log.i(err); | ||||||
|  |                                       setState(() { | ||||||
|  |                                         error = err; | ||||||
|  |                                       }); | ||||||
|  |                                     }, | ||||||
|                                     icon: const Icon( |                                     icon: const Icon( | ||||||
|                                       Icons.arrow_forward, |                                       Icons.arrow_forward, | ||||||
|                                     )), |                                     )), | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; | |||||||
| 
 | 
 | ||||||
| import '../api/token.dart'; | import '../api/token.dart'; | ||||||
| import '../log/log.dart'; | import '../log/log.dart'; | ||||||
| import 'login_context.dart'; |  | ||||||
| 
 | 
 | ||||||
| class LoginContainer extends StatefulWidget { | class LoginContainer extends StatefulWidget { | ||||||
|   const LoginContainer({Key? key, required this.child}) : super(key: key); |   const LoginContainer({Key? key, required this.child}) : super(key: key); | ||||||
| @@ -19,13 +18,11 @@ class _LoginContainerState extends State<LoginContainer> { | |||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
|     _init(); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   void _init() async { |     final token = Token.getInstance(); | ||||||
|     final token = await getToken(); |     token.getToken().then((value) { | ||||||
|     Log.i("The token value is $token"); |       Log.i("The token value is $value"); | ||||||
|     if (token != null) { |       if (value != null) { | ||||||
|         setState(() { |         setState(() { | ||||||
|           _loggedIn = true; |           _loggedIn = true; | ||||||
|           _loading = false; |           _loading = false; | ||||||
| @@ -36,6 +33,7 @@ class _LoginContainerState extends State<LoginContainer> { | |||||||
|           _loading = false; |           _loading = false; | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|  |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
| @@ -60,3 +58,27 @@ class _LoginContainerState extends State<LoginContainer> { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | class LoginContext extends InheritedWidget { | ||||||
|  |   const LoginContext( | ||||||
|  |       {Key? key, | ||||||
|  |       required Widget child, | ||||||
|  |       required this.loggedIn, | ||||||
|  |       required this.onLoggin}) | ||||||
|  |       : super(key: key, child: child); | ||||||
|  | 
 | ||||||
|  |   final bool loggedIn; | ||||||
|  |   final void Function(bool) onLoggin; | ||||||
|  | 
 | ||||||
|  |   static LoginContext of(BuildContext context) { | ||||||
|  |     final LoginContext? result = | ||||||
|  |         context.dependOnInheritedWidgetOfExactType<LoginContext>(); | ||||||
|  |     assert(result != null, 'No LoginContext found in context'); | ||||||
|  |     return result!; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool updateShouldNotify(LoginContext old) { | ||||||
|  |     return loggedIn != old.loggedIn; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -1,27 +1,21 @@ | |||||||
| 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'; | ||||||
| import 'log/log.dart'; | import 'log/log.dart'; | ||||||
| import 'login/login_container.dart'; | import 'login/logincontext.dart'; | ||||||
| import 'utils/platform.dart'; | 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,9 +1,11 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import '../api/tag_api.dart'; | import 'package:openmediacentermobile/preview/tag_tile.dart'; | ||||||
| import '../preview/tag_tile.dart'; |  | ||||||
| import '../drawer/my_drawer.dart'; | import '../drawer/my_drawer.dart'; | ||||||
| import '../screen_loading.dart'; | import '../screen_loading.dart'; | ||||||
|  |  | ||||||
|  | import '../api/api.dart'; | ||||||
| import '../types/tag.dart'; | import '../types/tag.dart'; | ||||||
|  |  | ||||||
| class CategorieScreen extends StatefulWidget { | class CategorieScreen extends StatefulWidget { | ||||||
| @@ -16,10 +18,18 @@ class CategorieScreen extends StatefulWidget { | |||||||
| class _CategorieScreenState extends State<CategorieScreen> { | class _CategorieScreenState extends State<CategorieScreen> { | ||||||
|   late Future<List<Tag>> _categories; |   late Future<List<Tag>> _categories; | ||||||
|  |  | ||||||
|  |   Future<List<Tag>> loadVideoData() async { | ||||||
|  |     final data = await API.query("tags", "getAllTags", {}); | ||||||
|  |  | ||||||
|  |     final d = (jsonDecode(data) ?? []) as List<dynamic>; | ||||||
|  |     final tags = d.map((e) => Tag.fromJson(e)).toList(growable: false); | ||||||
|  |     return tags; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
|     _categories = loadAllTags(); |     _categories = loadVideoData(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -1,11 +1,10 @@ | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:openmediacentermobile/db/settings_db.dart'; | import 'package:openmediacentermobile/utils/FileFormatter.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/logincontext.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); | ||||||
| @@ -16,7 +15,6 @@ class SettingsScreen extends StatefulWidget { | |||||||
|  |  | ||||||
| class _SettingsScreenState extends State<SettingsScreen> { | class _SettingsScreenState extends State<SettingsScreen> { | ||||||
|   int dbsize = 0; |   int dbsize = 0; | ||||||
|   String serverUrl = ""; |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
| @@ -24,10 +22,6 @@ class _SettingsScreenState extends State<SettingsScreen> { | |||||||
|     Db().getDbSize().then((v) => setState(() { |     Db().getDbSize().then((v) => setState(() { | ||||||
|           dbsize = v; |           dbsize = v; | ||||||
|         })); |         })); | ||||||
|  |  | ||||||
|     getToken().then((value) => setState(() { |  | ||||||
|           serverUrl = value?.domain ?? "unknown"; |  | ||||||
|         })); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -40,7 +34,6 @@ class _SettingsScreenState extends State<SettingsScreen> { | |||||||
|         ), |         ), | ||||||
|         body: Column( |         body: Column( | ||||||
|           children: [ |           children: [ | ||||||
|             Text("Current server: $serverUrl"), |  | ||||||
|             ElevatedButton( |             ElevatedButton( | ||||||
|                 onPressed: () async { |                 onPressed: () async { | ||||||
|                   await Db().clear(); |                   await Db().clear(); | ||||||
| @@ -54,8 +47,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")) | ||||||
|   | |||||||
| @@ -1,9 +1,12 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  | import 'dart:math'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| 
 | 
 | ||||||
| import '../api/video_api.dart'; |  | ||||||
| import '../drawer/my_drawer.dart'; | import '../drawer/my_drawer.dart'; | ||||||
| import '../preview/preview_grid.dart'; | import '../preview/preview_grid.dart'; | ||||||
|  | import '../api/api.dart'; | ||||||
| import '../utils/platform.dart'; | import '../utils/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); | ||||||
| @@ -13,6 +16,18 @@ class ShuffleScreen extends StatefulWidget { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class _ShuffleScreenState extends State<ShuffleScreen> { | class _ShuffleScreenState extends State<ShuffleScreen> { | ||||||
|  |   Future<List<VideoT>> loadData(int nr) async { | ||||||
|  |     final data = await API.query("video", "getRandomMovies", | ||||||
|  |         {'Number': nr, 'Seed': Random().nextInt(0x7fffffff)}); | ||||||
|  | 
 | ||||||
|  |     final d = jsonDecode(data); | ||||||
|  | 
 | ||||||
|  |     List<VideoT> dta = | ||||||
|  |         (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList(); | ||||||
|  | 
 | ||||||
|  |     return dta; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     double width = MediaQuery.of(context).size.width; |     double width = MediaQuery.of(context).size.width; | ||||||
| @@ -23,8 +38,7 @@ class _ShuffleScreenState extends State<ShuffleScreen> { | |||||||
|         ), |         ), | ||||||
|         body: PreviewGrid( |         body: PreviewGrid( | ||||||
|           videoLoader: () { |           videoLoader: () { | ||||||
|             return loadShuffledVideos( |             return loadData((isTV() ? width ~/ 200 : width ~/ 275) * 2); | ||||||
|                 (isTV() ? width ~/ 200 : width ~/ 275) * 2); |  | ||||||
|           }, |           }, | ||||||
|           footerBuilder: (state) => Column( |           footerBuilder: (state) => Column( | ||||||
|             children: [ |             children: [ | ||||||
| @@ -1,9 +1,12 @@ | |||||||
| import 'package:flutter/material.dart'; | import 'dart:convert'; | ||||||
| import '../api/video_api.dart'; |  | ||||||
|  |  | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | import '../api/api.dart'; | ||||||
| import '../drawer/my_drawer.dart'; | import '../drawer/my_drawer.dart'; | ||||||
| import '../preview/preview_grid.dart'; | import '../preview/preview_grid.dart'; | ||||||
| import '../types/tag.dart'; | import '../types/tag.dart'; | ||||||
|  | import '../types/video.dart'; | ||||||
|  |  | ||||||
| enum FilterTypes { DATE, LIKES, RANDOM, NAMES, LENGTH } | enum FilterTypes { DATE, LIKES, RANDOM, NAMES, LENGTH } | ||||||
|  |  | ||||||
| @@ -21,6 +24,18 @@ class VideoFeedState extends State<VideoFeed> { | |||||||
|   FilterTypes filterSelection = FilterTypes.DATE; |   FilterTypes filterSelection = FilterTypes.DATE; | ||||||
|   Key _refreshKey = UniqueKey(); |   Key _refreshKey = UniqueKey(); | ||||||
|  |  | ||||||
|  |   Future<List<VideoT>> loadData() async { | ||||||
|  |     final data = await API.query("video", "getMovies", | ||||||
|  |         {'Tag': widget.tag?.tagId ?? 1, 'Sort': filterSelection.index}); | ||||||
|  |  | ||||||
|  |     final d = jsonDecode(data); | ||||||
|  |  | ||||||
|  |     List<VideoT> dta = | ||||||
|  |         (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList(); | ||||||
|  |  | ||||||
|  |     return dta; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
| @@ -65,7 +80,7 @@ class VideoFeedState extends State<VideoFeed> { | |||||||
|         ), |         ), | ||||||
|         body: PreviewGrid( |         body: PreviewGrid( | ||||||
|           key: _refreshKey, |           key: _refreshKey, | ||||||
|           videoLoader: () => loadVideo(widget.tag, filterSelection.index), |           videoLoader: () => loadData(), | ||||||
|         ), |         ), | ||||||
|         drawer: widget.tag == null ? MyDrawer() : null); |         drawer: widget.tag == null ? MyDrawer() : null); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,8 +1,11 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| import '../api/video_api.dart'; | import '../api/api.dart'; | ||||||
| import 'preview_grid.dart'; | import 'preview_grid.dart'; | ||||||
| import '../types/actor.dart'; | import '../types/actor.dart'; | ||||||
|  | import '../types/video.dart'; | ||||||
|  |  | ||||||
| class ActorFeed extends StatefulWidget { | class ActorFeed extends StatefulWidget { | ||||||
|   const ActorFeed({Key? key, required this.actor}) : super(key: key); |   const ActorFeed({Key? key, required this.actor}) : super(key: key); | ||||||
| @@ -13,10 +16,22 @@ class ActorFeed extends StatefulWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class _ActorFeedState extends State<ActorFeed> { | 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 |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return PreviewGrid( |     return PreviewGrid( | ||||||
|       videoLoader: () => loadVideoByActor(widget.actor), |       videoLoader: () => loadData(), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import '../preview/actor_feed.dart'; | import 'package:openmediacentermobile/preview/actor_feed.dart'; | ||||||
|  |  | ||||||
| import '../utils/platform.dart'; | import '../utils/platform.dart'; | ||||||
| import '../types/actor.dart'; | import '../types/actor.dart'; | ||||||
|   | |||||||
| @@ -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 { | ||||||
| @@ -56,15 +56,15 @@ class _PreviewGridState extends State<PreviewGrid> { | |||||||
|           builder: |           builder: | ||||||
|               (BuildContext context, AsyncSnapshot<List<VideoT>> snapshot) { |               (BuildContext context, AsyncSnapshot<List<VideoT>> snapshot) { | ||||||
|             if (snapshot.hasError) { |             if (snapshot.hasError) { | ||||||
|               return Center( |               return Column( | ||||||
|                 child: Column( |  | ||||||
|                   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")) | ||||||
|                 ], |                 ], | ||||||
|                 ), |  | ||||||
|               ); |               ); | ||||||
|             } else if (snapshot.hasData) { |             } else if (snapshot.hasData) { | ||||||
|               return _mainGrid(snapshot.data!, width); |               return _mainGrid(snapshot.data!, width); | ||||||
| @@ -78,9 +78,7 @@ 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), |  | ||||||
|           child: Column( |  | ||||||
|           children: [ |           children: [ | ||||||
|             if (widget.headerBuilder != null) widget.headerBuilder!(this), |             if (widget.headerBuilder != null) widget.headerBuilder!(this), | ||||||
|             data.length > 0 |             data.length > 0 | ||||||
| @@ -125,7 +123,6 @@ class _PreviewGridState extends State<PreviewGrid> { | |||||||
|             if (widget.footerBuilder != null) widget.footerBuilder!(this), |             if (widget.footerBuilder != null) widget.footerBuilder!(this), | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|         ), |  | ||||||
|         if (_previewImage != null) ..._buildPreviewImage(), |         if (_previewImage != null) ..._buildPreviewImage(), | ||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -1,12 +1,15 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  | import 'dart:typed_data'; | ||||||
|  |  | ||||||
| import 'package:flutter/foundation.dart'; | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:sqflite/sqflite.dart'; | import 'package:sqflite/sqflite.dart'; | ||||||
|  |  | ||||||
| import '../api/video_api.dart'; | import '../api/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 { | ||||||
| @@ -50,17 +53,23 @@ class _PreviewTileState extends State<PreviewTile> { | |||||||
|         ); |         ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   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 { | ||||||
|     Uint8List data; |     Uint8List data; | ||||||
|     final id = widget.dta.id; |     final id = widget.dta.id; | ||||||
|     if (kIsWeb) { |     if (kIsWeb) { | ||||||
|       data = await fetchThumbnail(id); |       data = await _fetchThumbnail(id); | ||||||
|     } else { |     } else { | ||||||
|       final List<Map<String, dynamic>> prev = |       final List<Map<String, dynamic>> prev = | ||||||
|           await Db().db().query('previews', where: "id=$id"); |           await Db().db().query('previews', where: "id=$id"); | ||||||
|  |  | ||||||
|       if (prev.isEmpty) { |       if (prev.isEmpty) { | ||||||
|         data = await fetchThumbnail(id); |         data = await _fetchThumbnail(id); | ||||||
|         insert(id, data); |         insert(id, data); | ||||||
|         Log.d("Adding $id to db"); |         Log.d("Adding $id to db"); | ||||||
|       } else { |       } else { | ||||||
| @@ -76,7 +85,6 @@ 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 +112,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,9 +156,7 @@ 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), |  | ||||||
|       child: FutureBuilder<Image>( |  | ||||||
|       future: _preview, // a previously-obtained Future<String> or null |       future: _preview, // a previously-obtained Future<String> or null | ||||||
|       builder: (BuildContext context, AsyncSnapshot<Image> snapshot) { |       builder: (BuildContext context, AsyncSnapshot<Image> snapshot) { | ||||||
|         if (snapshot.connectionState != ConnectionState.done) { |         if (snapshot.connectionState != ConnectionState.done) { | ||||||
| @@ -175,7 +171,6 @@ class _PreviewTileState extends State<PreviewTile> { | |||||||
|           return _buildLoader(); |           return _buildLoader(); | ||||||
|         } |         } | ||||||
|       }, |       }, | ||||||
|       ), |  | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ class TagTile extends StatelessWidget { | |||||||
|           ), |           ), | ||||||
|         ); |         ); | ||||||
|       }, |       }, | ||||||
|       style: ElevatedButton.styleFrom(backgroundColor: Color(0x6a94a6ff)), |       style: ElevatedButton.styleFrom(primary: Color(0x6a94a6ff)), | ||||||
|       child: SizedBox( |       child: SizedBox( | ||||||
|         child: Center(child: Text(tag.tagName)), |         child: Center(child: Text(tag.tagName)), | ||||||
|         height: 100, |         height: 100, | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import '../api/actor_api.dart'; |  | ||||||
| import '../api/video_api.dart'; | import '../api/video_api.dart'; | ||||||
| import '../dialog/add_actor_dialog.dart'; | import '../dialog/add_actor_dialog.dart'; | ||||||
| import '../dialog/add_tag_dialog.dart'; | import '../dialog/add_tag_dialog.dart'; | ||||||
| @@ -7,6 +8,9 @@ import '../navigation/video_feed.dart'; | |||||||
| import '../screen_loading.dart'; | import '../screen_loading.dart'; | ||||||
| import '../types/video_data.dart'; | import '../types/video_data.dart'; | ||||||
| import '../preview/actor_tile.dart'; | import '../preview/actor_tile.dart'; | ||||||
|  |  | ||||||
|  | import '../api/api.dart'; | ||||||
|  | import '../log/log.dart'; | ||||||
| import '../types/actor.dart'; | import '../types/actor.dart'; | ||||||
|  |  | ||||||
| class InfoView extends StatefulWidget { | class InfoView extends StatefulWidget { | ||||||
| @@ -25,7 +29,7 @@ class _InfoViewState extends State<InfoView> { | |||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
|     setState(() { |     setState(() { | ||||||
|       _data = loadActorsOfVideo(widget.videoId); |       _data = loadData(); | ||||||
|       vdata = loadVideoData(widget.videoId); |       vdata = loadVideoData(widget.videoId); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| @@ -35,6 +39,19 @@ class _InfoViewState extends State<InfoView> { | |||||||
|     super.didUpdateWidget(oldWidget); |     super.didUpdateWidget(oldWidget); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   Future<List<Actor>> loadData() async { | ||||||
|  |     final data = await API | ||||||
|  |         .query("actor", "getActorsOfVideo", {'MovieId': widget.videoId}); | ||||||
|  |     if (data == 'null') { | ||||||
|  |       return []; | ||||||
|  |     } | ||||||
|  |     final d = jsonDecode(data); | ||||||
|  |  | ||||||
|  |     List<Actor> dta = (d as List).map((e) => Actor.fromJson(e)).toList(); | ||||||
|  |  | ||||||
|  |     return dta; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return FutureBuilder( |     return FutureBuilder( | ||||||
| @@ -54,7 +71,12 @@ class _InfoViewState extends State<InfoView> { | |||||||
|                       children: [ |                       children: [ | ||||||
|                         IconButton( |                         IconButton( | ||||||
|                             onPressed: () async { |                             onPressed: () async { | ||||||
|                               if (await addLike(videoData.movieId)) |                               final data = await API.query("video", "addLike", | ||||||
|  |                                   {'MovieId': videoData.movieId}); | ||||||
|  |                               final d = jsonDecode(data); | ||||||
|  |                               if (d["result"] != 'success') { | ||||||
|  |                                 Log.w(d); | ||||||
|  |                               } | ||||||
|                               setState(() { |                               setState(() { | ||||||
|                                 vdata = loadVideoData(widget.videoId); |                                 vdata = loadVideoData(widget.videoId); | ||||||
|                               }); |                               }); | ||||||
| @@ -68,8 +90,9 @@ class _InfoViewState extends State<InfoView> { | |||||||
|                                 movieId: videoData.movieId, |                                 movieId: videoData.movieId, | ||||||
|                               ), |                               ), | ||||||
|                             ); |                             ); | ||||||
|  |                             Log.d("finished dialog"); | ||||||
|                             setState(() { |                             setState(() { | ||||||
|                               _data = loadActorsOfVideo(widget.videoId); |                               _data = loadData(); | ||||||
|                             }); |                             }); | ||||||
|                           }, |                           }, | ||||||
|                           child: Text("Add Actor"), |                           child: Text("Add Actor"), | ||||||
| @@ -82,6 +105,7 @@ class _InfoViewState extends State<InfoView> { | |||||||
|                                 movieId: videoData.movieId, |                                 movieId: videoData.movieId, | ||||||
|                               ), |                               ), | ||||||
|                             ); |                             ); | ||||||
|  |                             Log.d("finished dialog"); | ||||||
|                             setState(() { |                             setState(() { | ||||||
|                               vdata = loadVideoData(widget.videoId); |                               vdata = loadVideoData(widget.videoId); | ||||||
|                             }); |                             }); | ||||||
|   | |||||||
| @@ -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,18 @@ 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 baseurl = token.domain; | ||||||
|  |     // todo not static middle path | ||||||
|  |     final path = baseurl + "/videos/vids/" + videodata.movieUrl; | ||||||
|  |  | ||||||
|     url = path; |     url = path; | ||||||
|   } |   } | ||||||
| @@ -55,7 +55,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(); | ||||||
|   } |   } | ||||||
| @@ -95,7 +94,7 @@ class _VideoScreenState extends State<VideoScreen> { | |||||||
|               child: GestureDetector( |               child: GestureDetector( | ||||||
|                 onPanDown: (details) async { |                 onPanDown: (details) async { | ||||||
|                   if (_appBarVisible) { |                   if (_appBarVisible) { | ||||||
|                     await Future.delayed(Duration(milliseconds: 300)); |                     await Future.delayed(Duration(milliseconds: 100)); | ||||||
|                     setState(() { |                     setState(() { | ||||||
|                       _appBarVisible = false; |                       _appBarVisible = false; | ||||||
|                     }); |                     }); | ||||||
| @@ -115,7 +114,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 +135,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), | ||||||
|   | |||||||
							
								
								
									
										53
									
								
								lib/video_screen/videoscreen_desktop.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								lib/video_screen/videoscreen_desktop.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | 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, | ||||||
|  |       scale: 1.0, // default | ||||||
|  |       showControls: true, | ||||||
|  |       playlistLength: 1, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @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(); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								lib/video_screen/videoscreen_mobile.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								lib/video_screen/videoscreen_mobile.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | import 'package:better_player/better_player.dart'; | ||||||
|  | import 'package:flutter/material.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> { | ||||||
|  |   BetterPlayerController? _betterPlayerController; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     if (_betterPlayerController == null) { | ||||||
|  |       return Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |         mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |         children: const [CircularProgressIndicator(), Text("loading...")], | ||||||
|  |       ); | ||||||
|  |     } else { | ||||||
|  |       return BetterPlayer( | ||||||
|  |         controller: _betterPlayerController!, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     super.dispose(); | ||||||
|  |     _betterPlayerController?.videoPlayerController?.dispose(); | ||||||
|  |     _betterPlayerController?.dispose(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     _init(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void _init() async { | ||||||
|  |     BetterPlayerDataSource betterPlayerDataSource = | ||||||
|  |         BetterPlayerDataSource(BetterPlayerDataSourceType.network, widget.url); | ||||||
|  |     _betterPlayerController = BetterPlayerController( | ||||||
|  |         BetterPlayerConfiguration( | ||||||
|  |             autoPlay: true, looping: true, allowedScreenSleep: false), | ||||||
|  |         betterPlayerDataSource: betterPlayerDataSource); | ||||||
|  |  | ||||||
|  |     setState(() {}); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -6,14 +6,14 @@ | |||||||
|  |  | ||||||
| #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> | ||||||
|  |  | ||||||
| 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); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,12 +3,11 @@ | |||||||
| # | # | ||||||
|  |  | ||||||
| list(APPEND FLUTTER_PLUGIN_LIST | list(APPEND FLUTTER_PLUGIN_LIST | ||||||
|   media_kit_libs_linux |   dart_vlc | ||||||
|   media_kit_video |   flutter_secure_storage_linux | ||||||
| ) | ) | ||||||
|  |  | ||||||
| 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) | ||||||
|   | |||||||
							
								
								
									
										756
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										756
									
								
								pubspec.lock
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										15
									
								
								pubspec.yaml
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								pubspec.yaml
									
									
									
									
									
								
							| @@ -34,23 +34,16 @@ 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: ^5.0.2 | ||||||
|   logger: ^1.1.0 |   logger: ^1.1.0 | ||||||
|   http: ^0.13.4 |   http: ^0.13.4 | ||||||
|   flutter_staggered_grid_view: ^0.6.1 |   flutter_staggered_grid_view: ^0.6.1 | ||||||
|   device_info_plus: ^8.0.0 |   dart_vlc: ^0.1.9 | ||||||
|  |   device_info_plus: ^3.2.3 | ||||||
|   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' |   better_player: ^0.0.83 | ||||||
|  |  | ||||||
|   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: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user