Files
2025-04-18 10:16:03 +02:00

474 lines
14 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:multimedia/widgets/movies/add/add_screen.dart';
import 'package:multimedia/widgets/movies/details/details_screen.dart';
import 'package:multimedia/widgets/movies/filter_box.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:intl/intl.dart';
import 'package:http/http.dart' as http;
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:syncfusion_flutter_core/theme.dart';
import 'package:multimedia/data/movies.dart';
import 'package:multimedia/constants.dart';
import 'package:logger/logger.dart';
import 'package:multimedia/log_printer.dart';
class MoviesScreen extends StatefulWidget {
const MoviesScreen({
super.key,
});
@override
State<StatefulWidget> createState() => _MoviesScreenState();
}
class _MoviesScreenState extends State<MoviesScreen> {
final DataGridController _dataGridController = DataGridController();
late MovieDataSource movieDataSource;
List<GridColumn> _columns = [];
late List<Movie> _moviesList;
String searchText = '';
bool showInit = false;
bool showProg = false;
bool showDone = false;
Logger logger = getLogger();
Future<List<Movie>> generateMovieList() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? dbProtocol = prefs.getString('dbProtocol');
String? dbHost = prefs.getString('dbHost');
String? dbPath = prefs.getString('dbPath');
Uri url = Uri(
scheme: dbProtocol,
host: dbHost,
path: dbPath,
queryParameters: {
'module': 'movie',
'function': 'getList',
},
);
try {
final response = await http.get(url);
//LATER bool? error;
//LATER String? errorMessage;
Map<String, dynamic> movies = json.decode(response.body);
//LATER error = movies['error'];
//LATER errorMessage = movies['errmsg'];
var list = movies['data'];
List<Movie> moviesTmp =
await list.map<Movie>((json) => Movie.fromJson(json)).toList();
movieDataSource = MovieDataSource(moviesTmp);
_moviesList = moviesTmp;
return moviesTmp;
} catch (e) {
print(e.toString());
}
return [];
}
List<GridColumn> getColumns() {
return <GridColumn>[
GridColumn(
columnName: 'movieID',
visible: false,
width: 70,
label: Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.centerLeft,
child: const Text('movieID'))),
GridColumn(
columnName: 'state',
visible: false,
width: 70,
label: Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.centerLeft,
child: const Text('state'))),
GridColumn(
columnName: 'backdropPath',
visible: false,
width: 70,
label: Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.centerLeft,
child: const Text('backdropPath'))),
GridColumn(
columnName: 'movieTitle',
columnWidthMode: ColumnWidthMode.auto,
label: Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: const Text('Title'))),
GridColumn(
columnName: 'releaseDate',
columnWidthMode: ColumnWidthMode.auto,
label: Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: const Text('First Aired'))),
GridColumn(
columnName: 'resolution',
columnWidthMode: ColumnWidthMode.auto,
label: Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: const Text('Resolution'))),
GridColumn(
columnName: 'overview',
columnWidthMode: ColumnWidthMode.auto,
label: Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: const Text('Overview'))),
];
}
@override
void initState() {
super.initState();
_columns = getColumns();
}
Future<void> showMovieDetails(int index) async {
DataGridRow row = movieDataSource.effectiveRows.elementAt(index);
List<DataGridCell<dynamic>> cells = row.getCells();
String movieID = cells[MovieColumn.movieID].value.toString();
bool found = false;
int movieIndex;
int realIndex;
movieDataSource.clearFilters();
realIndex = movieDataSource.rows.indexOf(row);
for (movieIndex = 0; movieIndex < _moviesList.length; movieIndex++) {
if (_moviesList[movieIndex].movieID == int.parse(movieID)) {
found = true;
break;
}
}
if (found) {
final m = await Navigator.push(
context,
MaterialPageRoute(
builder: (ctx) =>
MovieDetailsScreen(movie: _moviesList[movieIndex])));
if (m != null) {
_moviesList[movieIndex].movieTitle = m.movieTitle;
_moviesList[movieIndex].localPath = m.localPath;
_moviesList[movieIndex].resolution = m.resolution;
_moviesList[movieIndex].state = m.state;
Movie e = _moviesList[movieIndex];
movieDataSource._movieDataGridRows[realIndex] = DataGridRow(cells: [
DataGridCell<int>(columnName: 'movieID', value: e.movieID),
DataGridCell<int>(columnName: 'state', value: e.state),
DataGridCell<String>(
columnName: 'backdropPath', value: e.backdropPath),
DataGridCell<String>(columnName: 'movieTitle', value: e.movieTitle),
DataGridCell<String>(
columnName: 'releaseDate',
value: DateFormat('yyyy-MM-dd').format(e.releaseDate)),
DataGridCell<String>(columnName: 'resolution', value: e.resolution),
DataGridCell<String>(columnName: 'overview', value: e.overview),
]);
for (int i = 0; i < _columns.length; i++) {
movieDataSource.updateDataGridSource(
rowColumnIndex: RowColumnIndex(realIndex, i));
}
} else {}
filter();
}
}
void setFilter(String text, bool sInit, bool sProg, bool sDone) {
searchText = text;
showInit = sInit;
showProg = sProg;
showDone = sDone;
filter();
}
void filter() {
movieDataSource.clearFilters();
if (showInit)
movieDataSource.addFilter(
'state',
FilterCondition(
type: FilterType.equals,
value: 1,
filterOperator: FilterOperator.or),
);
if (showProg)
movieDataSource.addFilter(
'state',
FilterCondition(
type: FilterType.equals,
value: 2,
filterOperator: FilterOperator.or,
));
if (showDone)
movieDataSource.addFilter(
'state',
FilterCondition(
type: FilterType.equals,
value: 3,
filterOperator: FilterOperator.or,
));
movieDataSource.addFilter(
'movieTitle',
FilterCondition(
type: FilterType.beginsWith,
value: searchText,
filterOperator: FilterOperator.and,
filterBehavior: FilterBehavior.stringDataType,
));
}
late SfDataGrid dataGrid;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Movies'),
actions: [
const VerticalDivider(
width: 10,
thickness: 3,
indent: 0,
endIndent: 0,
color: Colors.grey,
),
IconButton(
icon: const Icon(Icons.add_circle_outline),
tooltip: 'Add Movie',
onPressed: () {
addMovie();
},
),
IconButton(
icon: const Icon(Icons.update_outlined),
tooltip: 'Update movie',
onPressed: () {
updateMovies();
//todo
},
),
],
),
body: Column(children: [
MovieFilterBox(setFilter: setFilter),
Expanded(
child: FutureBuilder<Object>(
future: generateMovieList(),
builder: (context, data) {
if (data.hasData) {
dataGrid = SfDataGrid(
source: movieDataSource,
selectionMode: SelectionMode.single,
navigationMode: GridNavigationMode.row,
columns: _columns,
controller: _dataGridController,
columnWidthMode: ColumnWidthMode.auto,
columnWidthCalculationRange:
ColumnWidthCalculationRange.allRows,
onCellTap: (DataGridCellTapDetails details) {
int index = details.rowColumnIndex.rowIndex - 1;
if (index < 0) {
return;
}
showMovieDetails(index);
},
onCellDoubleTap: (DataGridCellDoubleTapDetails details) {
print(details.rowColumnIndex);
},
onCellLongPress: (DataGridCellLongPressDetails details) {
print(details.rowColumnIndex);
},
onCellSecondaryTap: (DataGridCellTapDetails details) {
print(details.rowColumnIndex);
},
);
return SfDataGridTheme(
data: const SfDataGridThemeData(
headerColor: Color(0xff009889),
),
child: dataGrid,
);
} else {
return const Center(
child: CircularProgressIndicator(
strokeWidth: 2,
value: 0.8,
),
);
}
},
),
),
]),
);
}
void addMovieToList(Movie movie) {
String movieTitle = movie.movieTitle.toUpperCase().replaceAll('Ä', 'a').replaceAll('Ö', 'ö').replaceAll('Ü', 'ü').replaceAll('ß', 'ss');
_moviesList.add(movie);
DataGridRow newRow = DataGridRow(cells: [
DataGridCell<int>(columnName: 'movieID', value: movie.movieID),
DataGridCell<int>(columnName: 'state', value: movie.state),
DataGridCell<String>(
columnName: 'backdropPath', value: movie.backdropPath),
DataGridCell<String>(columnName: 'movieTitle', value: movie.movieTitle),
DataGridCell<String>(
columnName: 'releaseDate',
value: DateFormat('yyyy-MM-dd').format(movie.releaseDate)),
DataGridCell<String>(columnName: 'resolution', value: movie.resolution),
DataGridCell<String>(columnName: 'overview', value: movie.overview),
]);
int rowNum = -1;
for (int i = 0; i < movieDataSource._movieDataGridRows.length; i++) {
DataGridRow tmpRow = movieDataSource._movieDataGridRows[i];
List<DataGridCell> tmpCells = tmpRow.getCells();
String tmpTitle = tmpCells[3].value.toString().toUpperCase().replaceAll('Ä', 'a').replaceAll('Ö', 'ö').replaceAll('Ü', 'ü').replaceAll('ß', 'ss');
if (tmpTitle.toUpperCase().compareTo(movieTitle) >= 0) {
rowNum = i;
break;
}
}
if (rowNum == -1) {
rowNum = movieDataSource._movieDataGridRows.length;
}
movieDataSource.rows.insert(rowNum, newRow);
movieDataSource.notifyListeners();
}
void addMovieFinished() {}
void addMovie() {
/*final m =*/ Navigator.push(
context,
MaterialPageRoute(
builder: (ctx) =>
AddMovieScreen(addMovieToList, addMovieFinished)));
}
void searchMovie() {
logger.i('search movie');
}
void updateMovies() {
logger.i('update movies');
}
}
class MovieDataSource extends DataGridSource {
/// Creates the employee data source class with required details.
MovieDataSource(this.movies) {
buildDataGridRow();
}
void addDataGridRow(DataGridRow newRow) {
rows.add(newRow);
// To refresh the DataGrid based on CRUD operation.
notifyListeners();
}
Logger logger = getLogger();
void buildDataGridRow() {
_movieDataGridRows = movies
.map<DataGridRow>((e) => DataGridRow(cells: [
DataGridCell<int>(columnName: 'movieID', value: e.movieID),
DataGridCell<int>(columnName: 'state', value: e.state),
DataGridCell<String>(
columnName: 'backdropPath', value: e.backdropPath),
DataGridCell<String>(
columnName: 'movieTitle', value: e.movieTitle),
DataGridCell<String>(
columnName: 'releaseDate',
value: DateFormat('yyyy-MM-dd').format(e.releaseDate)),
DataGridCell<String>(
columnName: 'resolution', value: e.resolution),
DataGridCell<String>(columnName: 'overview', value: e.overview),
]))
.toList();
}
List<Movie> movies = [];
List<DataGridRow> _movieDataGridRows = [];
@override
List<DataGridRow> get rows => _movieDataGridRows;
@override
DataGridRowAdapter buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells: row.getCells().map<Widget>((e) {
Color colorBG = Colors.white;
Color colorFG = Colors.black;
if (e.columnName == 'movieTitle') {
int state = row.getCells().toList()[MovieColumn.movieState].value;
if (state == 1) {
colorBG = StateColor.init;
} else if (state == 2) {
colorBG = StateColor.prog;
colorFG = Colors.white;
} else {
colorBG = StateColor.done;
}
}
return Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.all(8.0),
color: colorBG,
child: Text(
e.value.toString(),
style: TextStyle(color: colorFG),
),
);
}).toList());
}
void updateDataGrid() {
notifyListeners();
}
void updateDataGridSource({required RowColumnIndex rowColumnIndex}) {
notifyDataSourceListeners(rowColumnIndex: rowColumnIndex);
}
}