format, lint
outsource preview table in several function revert android compile version
This commit is contained in:
parent
404d1d7cf7
commit
a7757b14dd
@ -13,3 +13,13 @@ flutter_build_android: #Job name
|
||||
artifacts:
|
||||
paths:
|
||||
- build/app/outputs/apk/release/app-release.apk
|
||||
|
||||
flutter_lint:
|
||||
stage: build
|
||||
script:
|
||||
- flutter format . --output none --set-exit-if-changed
|
||||
|
||||
flutter_analyze:
|
||||
stage: build
|
||||
script:
|
||||
- flutter analyze ./lib
|
||||
|
@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
compileSdkVersion flutter.compileSdkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
@ -45,7 +45,7 @@ android {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "eu.heili.openmediacentermobile"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.0'
|
||||
ext.kotlin_version = '1.4.32'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
|
@ -44,14 +44,17 @@ class _DrawerPageState extends State<DrawerPage> {
|
||||
final loginCtx = LoginContext.of(context);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(title), actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
loginCtx.onLoggin(false);
|
||||
Token.getInstance().setToken("", "");
|
||||
},
|
||||
icon: const Icon(Icons.logout))
|
||||
],),
|
||||
appBar: AppBar(
|
||||
title: Text(title),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
loginCtx.onLoggin(false);
|
||||
Token.getInstance().setToken("", "");
|
||||
},
|
||||
icon: const Icon(Icons.logout))
|
||||
],
|
||||
),
|
||||
body: body,
|
||||
drawer: Drawer(
|
||||
child: ListView(children: [
|
||||
|
@ -19,8 +19,8 @@ class App extends StatelessWidget {
|
||||
} else {
|
||||
return const MaterialApp(
|
||||
home: DrawerPage(
|
||||
title: 'OpenMediaCenter',
|
||||
));
|
||||
title: 'OpenMediaCenter',
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
final TextEditingController _domainTextController = TextEditingController();
|
||||
final TextEditingController _passwordTextController = TextEditingController();
|
||||
String error = "";
|
||||
bool _loginActive = false;
|
||||
|
||||
Future<String> login(String password, String domain) async {
|
||||
Log.i("logging in...");
|
||||
@ -64,7 +63,8 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(image: AssetImage('assets/images/login.png'), fit: BoxFit.cover),
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/login.png'), fit: BoxFit.cover),
|
||||
),
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
@ -79,7 +79,8 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
),
|
||||
SingleChildScrollView(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.5),
|
||||
padding: EdgeInsets.only(
|
||||
top: MediaQuery.of(context).size.height * 0.5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -123,7 +124,8 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
children: [
|
||||
const Text(
|
||||
'Sign in',
|
||||
style: TextStyle(fontSize: 27, fontWeight: FontWeight.w700),
|
||||
style: TextStyle(
|
||||
fontSize: 27, fontWeight: FontWeight.w700),
|
||||
),
|
||||
CircleAvatar(
|
||||
radius: 30,
|
||||
@ -132,18 +134,23 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
color: Colors.white,
|
||||
onPressed: () async {
|
||||
Log.d("clickkked");
|
||||
final pwd = _passwordTextController.value.text;
|
||||
final domain = _domainTextController.value.text;
|
||||
final pwd =
|
||||
_passwordTextController.value.text;
|
||||
final domain =
|
||||
_domainTextController.value.text;
|
||||
|
||||
var err = "";
|
||||
if (domain.startsWith("https://") || domain.startsWith("http://")) {
|
||||
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);
|
||||
err = await login(
|
||||
pwd, "https://" + domain);
|
||||
if (err.isEmpty) return;
|
||||
err = await login(pwd, "http://" + domain);
|
||||
err = await login(
|
||||
pwd, "http://" + domain);
|
||||
if (err.isEmpty) return;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import "package:dart_vlc/dart_vlc.dart";
|
||||
import "package:dart_vlc/dart_vlc.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:openmediacentermobile/app.dart';
|
||||
@ -11,7 +11,6 @@ void main() async {
|
||||
Log.i("App init!");
|
||||
DartVLC.initialize();
|
||||
if (isDesktop()) {
|
||||
|
||||
} else {
|
||||
await loadDeviceInfo();
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ import 'package:flutter/foundation.dart';
|
||||
bool _isTV = false;
|
||||
|
||||
bool isDesktop() {
|
||||
return (Platform.isLinux || Platform.isWindows || Platform.isMacOS) && !kIsWeb;
|
||||
return (Platform.isLinux || Platform.isWindows || Platform.isMacOS) &&
|
||||
!kIsWeb;
|
||||
}
|
||||
|
||||
Future<void> loadDeviceInfo() async {
|
||||
|
@ -6,7 +6,12 @@ import 'package:openmediacentermobile/platform.dart';
|
||||
import 'package:openmediacentermobile/preview_tile.dart';
|
||||
|
||||
class PreviewGrid extends StatefulWidget {
|
||||
const PreviewGrid({Key? key, required this.videoLoader, this.headerBuilder, this.footerBuilder}) : super(key: key);
|
||||
const PreviewGrid(
|
||||
{Key? key,
|
||||
required this.videoLoader,
|
||||
this.headerBuilder,
|
||||
this.footerBuilder})
|
||||
: super(key: key);
|
||||
|
||||
final Future<List<VideoT>> Function() videoLoader;
|
||||
final Widget Function(_PreviewGridState state)? footerBuilder;
|
||||
@ -37,79 +42,94 @@ class _PreviewGridState extends State<PreviewGrid> {
|
||||
final double width = MediaQuery.of(context).size.width;
|
||||
|
||||
return FutureBuilder<List<VideoT>>(
|
||||
future: _data, // a previously-obtained Future<String> or null
|
||||
future: _data,
|
||||
builder: (BuildContext context, AsyncSnapshot<List<VideoT>> snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Text("Error");
|
||||
} else if (snapshot.hasData) {
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
if (widget.headerBuilder != null) widget.headerBuilder!(this),
|
||||
Expanded(
|
||||
child: MasonryGridView.count(
|
||||
// every tile should be at max 330 pixels long...
|
||||
crossAxisCount: isTV() ? width ~/ 200 : width ~/ 275,
|
||||
// crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330,
|
||||
itemCount: snapshot.data!.length,
|
||||
mainAxisSpacing: 4,
|
||||
crossAxisSpacing: 4,
|
||||
padding: EdgeInsets.all(5),
|
||||
itemBuilder: (context, index) {
|
||||
return PreviewTile(
|
||||
dta: snapshot.data![index],
|
||||
onLongPress: (img) {
|
||||
setState(() {
|
||||
_previewImage = img;
|
||||
});
|
||||
},
|
||||
onLongPressEnd: () {
|
||||
setState(() {
|
||||
_previewImage = null;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.footerBuilder != null) widget.footerBuilder!(this),
|
||||
],
|
||||
),
|
||||
if (_previewImage != null) ...[
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: 5.0,
|
||||
sigmaY: 5.0,
|
||||
),
|
||||
child: Container(
|
||||
color: Colors.white.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 50),
|
||||
child: ClipRRect(borderRadius: BorderRadius.circular(10.0), child: _previewImage!)),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
return _mainGrid(snapshot.data!, width);
|
||||
} else {
|
||||
return Column(children: const <Widget>[
|
||||
SizedBox(
|
||||
width: 60,
|
||||
height: 60,
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 16),
|
||||
child: Text('Awaiting result...'),
|
||||
)
|
||||
]);
|
||||
return _pageLoading();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _pageLoading() {
|
||||
return Column(children: const <Widget>[
|
||||
SizedBox(
|
||||
width: 60,
|
||||
height: 60,
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 16),
|
||||
child: Text('Awaiting result...'),
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
Widget _mainGrid(List<VideoT> data, double width) {
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
if (widget.headerBuilder != null) widget.headerBuilder!(this),
|
||||
Expanded(
|
||||
child: MasonryGridView.count(
|
||||
// every tile should be at max 330 pixels long...
|
||||
crossAxisCount: isTV() ? width ~/ 200 : width ~/ 275,
|
||||
// crossAxisCount: isTV() ? width ~/ 200 : width ~/ 330,
|
||||
itemCount: data.length,
|
||||
mainAxisSpacing: 4,
|
||||
crossAxisSpacing: 4,
|
||||
padding: EdgeInsets.all(5),
|
||||
itemBuilder: (context, index) {
|
||||
return PreviewTile(
|
||||
dta: data[index],
|
||||
onLongPress: (img) {
|
||||
setState(() {
|
||||
_previewImage = img;
|
||||
});
|
||||
},
|
||||
onLongPressEnd: () {
|
||||
setState(() {
|
||||
_previewImage = null;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.footerBuilder != null) widget.footerBuilder!(this),
|
||||
],
|
||||
),
|
||||
if (_previewImage != null) ..._buildPreviewImage(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildPreviewImage() {
|
||||
return [
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: 5.0,
|
||||
sigmaY: 5.0,
|
||||
),
|
||||
child: Container(
|
||||
color: Colors.white.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 50),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
child: _previewImage!),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,15 @@ class VideoT {
|
||||
VideoT(this.title, this.id, this.ratio);
|
||||
|
||||
factory VideoT.fromJson(dynamic json) {
|
||||
return VideoT(json['MovieName'] as String, json['MovieId'] as int, (json['Ratio'] as num).toDouble());
|
||||
return VideoT(json['MovieName'] as String, json['MovieId'] as int,
|
||||
(json['Ratio'] as num).toDouble());
|
||||
}
|
||||
}
|
||||
|
||||
class PreviewTile extends StatefulWidget {
|
||||
const PreviewTile({Key? key, required this.dta, this.onLongPress, this.onLongPressEnd}) : super(key: key);
|
||||
const PreviewTile(
|
||||
{Key? key, required this.dta, this.onLongPress, this.onLongPressEnd})
|
||||
: super(key: key);
|
||||
final VideoT dta;
|
||||
final Function(Image img)? onLongPress;
|
||||
final Function? onLongPressEnd;
|
||||
@ -53,7 +56,8 @@ class _PreviewTileState extends State<PreviewTile> {
|
||||
}
|
||||
|
||||
Future<Image> loadData() async {
|
||||
final data = await API.query("video", "readThumbnail", {'Movieid': widget.dta.id});
|
||||
final data =
|
||||
await API.query("video", "readThumbnail", {'Movieid': widget.dta.id});
|
||||
|
||||
final img = Image.memory(
|
||||
base64Decode(data.substring(23)),
|
||||
@ -99,17 +103,20 @@ class _PreviewTileState extends State<PreviewTile> {
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onLongPress: () {
|
||||
if (widget.onLongPress != null) widget.onLongPress!(snapshot.data!);
|
||||
if (widget.onLongPress != null)
|
||||
widget.onLongPress!(snapshot.data!);
|
||||
},
|
||||
onLongPressEnd: (details) {
|
||||
if (widget.onLongPressEnd != null) widget.onLongPressEnd!();
|
||||
if (widget.onLongPressEnd != null)
|
||||
widget.onLongPressEnd!();
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => VideoScreen(metaData: widget.dta),
|
||||
builder: (context) =>
|
||||
VideoScreen(metaData: widget.dta),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -17,11 +17,13 @@ class ShuffleScreen extends StatefulWidget {
|
||||
|
||||
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 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();
|
||||
List<VideoT> dta =
|
||||
(d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList();
|
||||
|
||||
return dta;
|
||||
}
|
||||
|
@ -17,13 +17,13 @@ class VideoFeed extends StatefulWidget {
|
||||
}
|
||||
|
||||
class VideoFeedState extends State<VideoFeed> {
|
||||
|
||||
Future<List<VideoT>> loadData() async {
|
||||
final data = await API.query("video", "getMovies", {'Tag': 1, 'Sort': 0});
|
||||
|
||||
final d = jsonDecode(data);
|
||||
|
||||
List<VideoT> dta = (d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList();
|
||||
List<VideoT> dta =
|
||||
(d['Videos'] as List).map((e) => VideoT.fromJson(e)).toList();
|
||||
|
||||
return dta;
|
||||
}
|
||||
@ -33,6 +33,8 @@ class VideoFeedState extends State<VideoFeed> {
|
||||
double width = MediaQuery.of(context).size.width;
|
||||
Log.d(width);
|
||||
|
||||
return PreviewGrid(videoLoader: () => loadData(),);
|
||||
return PreviewGrid(
|
||||
videoLoader: () => loadData(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import 'package:video_player/video_player.dart';
|
||||
|
||||
import 'api/api.dart';
|
||||
import 'api/token.dart';
|
||||
import 'log/log.dart';
|
||||
import 'platform.dart';
|
||||
|
||||
class VideoScreen extends StatefulWidget {
|
||||
@ -22,11 +21,13 @@ class VideoScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _VideoScreenState extends State<VideoScreen> {
|
||||
Player? _player = isDesktop() ? Player(id: Random().nextInt(0x7fffffff)) : null;
|
||||
Player? _player =
|
||||
isDesktop() ? Player(id: Random().nextInt(0x7fffffff)) : null;
|
||||
ChewieController? _chewieController;
|
||||
|
||||
void loadData() async {
|
||||
final data = await API.query("video", "loadVideo", {'MovieId': widget.metaData.id});
|
||||
final data =
|
||||
await API.query("video", "loadVideo", {'MovieId': widget.metaData.id});
|
||||
|
||||
final d = jsonDecode(data);
|
||||
|
||||
@ -46,18 +47,18 @@ class _VideoScreenState extends State<VideoScreen> {
|
||||
autoStart: true, // default
|
||||
);
|
||||
} else {
|
||||
final VideoPlayerController _controller = VideoPlayerController.network(path);
|
||||
final VideoPlayerController _controller =
|
||||
VideoPlayerController.network(path);
|
||||
await _controller.initialize();
|
||||
|
||||
_chewieController = ChewieController(
|
||||
videoPlayerController: _controller,
|
||||
autoPlay: true,
|
||||
looping: true,
|
||||
allowFullScreen: true,
|
||||
allowMuting: true,
|
||||
allowPlaybackSpeedChanging: true,
|
||||
zoomAndPan: true
|
||||
);
|
||||
videoPlayerController: _controller,
|
||||
autoPlay: true,
|
||||
looping: true,
|
||||
allowFullScreen: true,
|
||||
allowMuting: true,
|
||||
allowPlaybackSpeedChanging: true,
|
||||
zoomAndPan: true);
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
@ -67,17 +68,18 @@ class _VideoScreenState extends State<VideoScreen> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
if(isDesktop()){
|
||||
if (isDesktop()) {
|
||||
RawKeyboard.instance.addListener((value) {
|
||||
if (value.logicalKey == LogicalKeyboardKey.arrowRight) {
|
||||
_player?.seek(_player!.position.position! + const Duration(seconds: 5));
|
||||
_player
|
||||
?.seek(_player!.position.position! + const Duration(seconds: 5));
|
||||
} else if (value.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
||||
_player?.seek(_player!.position.position! + const Duration(seconds: -5));
|
||||
_player
|
||||
?.seek(_player!.position.position! + const Duration(seconds: -5));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
loadData();
|
||||
|
||||
// todo hide appbar after some seonds
|
||||
@ -106,10 +108,9 @@ class _VideoScreenState extends State<VideoScreen> {
|
||||
|
||||
Widget videoDesktop() {
|
||||
return Video(
|
||||
player: _player,
|
||||
scale: 1.0, // default
|
||||
showControls: true
|
||||
);
|
||||
player: _player,
|
||||
scale: 1.0, // default
|
||||
showControls: true);
|
||||
}
|
||||
|
||||
Widget videoNotDesktop() {
|
||||
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'api/api.dart';
|
||||
import 'api/token.dart';
|
||||
import 'log/log.dart';
|
||||
|
||||
class VideoScreen extends StatefulWidget {
|
||||
const VideoScreen({Key? key, required this.videoID}) : super(key: key);
|
||||
@ -15,7 +16,8 @@ class VideoScreen extends StatefulWidget {
|
||||
|
||||
class _VideoScreenState extends State<VideoScreen> {
|
||||
void loadData() async {
|
||||
final data = await API.query("video", "loadVideo", {'MovieId': widget.videoID});
|
||||
final data =
|
||||
await API.query("video", "loadVideo", {'MovieId': widget.videoID});
|
||||
|
||||
final d = jsonDecode(data);
|
||||
|
||||
@ -25,8 +27,8 @@ class _VideoScreenState extends State<VideoScreen> {
|
||||
|
||||
final baseurl = token.domain;
|
||||
// todo not static middle path
|
||||
final path = baseurl + "/videos/vids/" + url;
|
||||
|
||||
final String path = baseurl + "/videos/vids/" + url;
|
||||
Log.d(path);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -44,9 +46,7 @@ class _VideoScreenState extends State<VideoScreen> {
|
||||
appBar: AppBar(
|
||||
title: const Text('Second Route'),
|
||||
),
|
||||
body: const Center(
|
||||
child: Text("Todo to implement")
|
||||
),
|
||||
body: const Center(child: Text("Todo to implement")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ packages:
|
||||
name: flutter_secure_storage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
version: "5.1.2"
|
||||
flutter_secure_storage_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -34,7 +34,7 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.2
|
||||
flutter_secure_storage: ^6.0.0
|
||||
flutter_secure_storage: ^5.0.2
|
||||
logger: ^1.1.0
|
||||
http: ^0.13.4
|
||||
flutter_staggered_grid_view: ^0.6.1
|
||||
|
@ -11,7 +11,5 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:openmediacentermobile/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
|
||||
});
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user