Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion assets/strings/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"trending": "Trending",
"information": "Information",
"trailers": "Trailers",
"casts": "Casts"
"casts": "Casts",
"delete": "Delete"
}
3 changes: 2 additions & 1 deletion assets/strings/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"trending": "Trending",
"information": "Information",
"trailers": "Trailers",
"casts": "Casts"
"casts": "Casts",
"delete": "Delete"
}
1 change: 1 addition & 0 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class App extends StatelessWidget {
MainScreen.routeName: (context) => MainScreen(),
GenreScreen.routeName: (context) => GenreScreen(),
DetailMovieScreen.routeName: (context) => DetailMovieScreen(),
FavoriteScreen.routeName: (context) => FavoriteScreen(),
},
);
}
Expand Down
1 change: 1 addition & 0 deletions lib/src/blocs/blocs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export 'genre_bloc/blocs.dart';
export 'setting_bloc/blocs.dart';
export 'detail_movie_bloc/blocs.dart';
export 'main_bloc/blocs.dart';
export 'favorite_bloc/blocs.dart';
2 changes: 1 addition & 1 deletion lib/src/blocs/detail_movie_bloc/detail_movie_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:moviesdb/src/locator.dart';
import 'package:moviesdb/src/repositories/repositories.dart';

class DetailMovieBloc extends Bloc<BaseEvent, BaseState> {
MoviesRepositories moviesRepositories = locator<MoviesRepositories>();
MoviesRepository moviesRepositories = locator<MoviesRepository>();

@override
BaseState get initialState => InitState();
Expand Down
3 changes: 3 additions & 0 deletions lib/src/blocs/favorite_bloc/blocs.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export 'favorite_event.dart';
export 'favorite_state.dart';
export 'favorite_bloc.dart';
53 changes: 53 additions & 0 deletions lib/src/blocs/favorite_bloc/favorite_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:moviesdb/src/blocs/base_bloc/base.dart';
import 'package:moviesdb/src/blocs/blocs.dart';
import 'package:moviesdb/src/locator.dart';
import 'package:moviesdb/src/repositories/repositories.dart';

class FavoriteBloc extends Bloc<BaseEvent, BaseState> {
final FavoriteRepository repository = locator<FavoriteRepository>();

@override
BaseState get initialState => InitState();

@override
Stream<BaseState> mapEventToState(BaseEvent event) async* {
if (event is ClickedFavorite) {
try {
yield (LoadingState());
final result = await repository.isFavorite(event.movie);
if (result == true) {
await repository.deleteFavorite(event.movie);
yield (NormalState());
} else if (result == false) {
await repository.addFavorite(event.movie);
yield (FavoriteState());
}
} catch (e) {
yield (ErrorState(data: e.toString()));
}
} else if (event is CheckFavorite) {
try {
yield (LoadingState());
final result = await repository.isFavorite(event.movie);
yield (result == true ? FavoriteState() : NormalState());
} catch (e) {
yield (ErrorState(data: e.toString()));
}
} else if (event is GetFavorites) {
try {
yield (LoadingState());
final result = await repository.getFavorites();
yield (LoadedState(data: result));
} catch (e) {
yield (ErrorState(data: e.toString()));
}
} else if (event is UnFavorite) {
try {
await repository.deleteFavorite(event.movie);
} catch (e) {
yield (ErrorState(data: e.toString()));
}
}
}
}
22 changes: 22 additions & 0 deletions lib/src/blocs/favorite_bloc/favorite_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:moviesdb/src/blocs/base_bloc/base.dart';
import 'package:moviesdb/src/data/models/models.dart';

class GetFavorites extends BaseEvent {}

class CheckFavorite extends BaseEvent {
final Movie movie;

CheckFavorite(this.movie);
}

class ClickedFavorite extends BaseEvent {
final Movie movie;

ClickedFavorite(this.movie);
}

class UnFavorite extends BaseEvent {
final Movie movie;

UnFavorite(this.movie);
}
5 changes: 5 additions & 0 deletions lib/src/blocs/favorite_bloc/favorite_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'package:moviesdb/src/blocs/base_bloc/base.dart';

class FavoriteState extends BaseState {}

class NormalState extends BaseState {}
2 changes: 1 addition & 1 deletion lib/src/blocs/genre_bloc/genre_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:moviesdb/src/repositories/repositories.dart';
import 'package:rxdart/rxdart.dart';

class GenreBloc extends Bloc<BaseEvent, BaseState> {
MoviesRepositories moviesRepositories = locator<MoviesRepositories>();
MoviesRepository moviesRepositories = locator<MoviesRepository>();
bool loadingMore = false;

@override
Expand Down
2 changes: 1 addition & 1 deletion lib/src/blocs/home_bloc/home_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:moviesdb/src/locator.dart';
import 'package:moviesdb/src/repositories/repositories.dart';

class HomeBloc extends Bloc<BaseEvent, BaseState> {
MoviesRepositories moviesRepositories = locator<MoviesRepositories>();
MoviesRepository moviesRepositories = locator<MoviesRepository>();

@override
BaseState get initialState => InitState();
Expand Down
2 changes: 1 addition & 1 deletion lib/src/blocs/setting_bloc/setting_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:moviesdb/src/repositories/repositories.dart';
import 'package:package_info/package_info.dart';

class SettingBloc extends Bloc<BaseEvent, BaseState> {
SettingRepositories settingRepositories = locator<SettingRepositories>();
SettingRepository settingRepositories = locator<SettingRepository>();

@override
BaseState get initialState => InitState();
Expand Down
10 changes: 10 additions & 0 deletions lib/src/data/models/movie.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,14 @@ class Movie extends Equatable {
? json["credits"]["cast"]?.map((e) => Actor.fromJson(e))?.toList()?.cast<Actor>()
: [];
}

Map<String, dynamic> toMap() {
return Map<String, dynamic>()
..["id"] = id
..["poster_path"] = porterPath
..["title"] = title
..["overview"] = overview
..["release_date"] = releaseDate
..["vote_average"] = voteAverage;
}
}
6 changes: 4 additions & 2 deletions lib/src/locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ GetIt locator = GetIt.instance;

void setupLocator() {
locator.registerLazySingleton(() => Network());
locator.registerLazySingleton<MoviesRepositories>(() => MoviesRepositories());
locator.registerLazySingleton<SettingRepositories>(() => SettingRepositories());
locator.registerLazySingleton(() => DatabaseProvider.databaseProvider);
locator.registerLazySingleton<MoviesRepository>(() => MoviesRepository());
locator.registerLazySingleton<SettingRepository>(() => SettingRepository());
locator.registerLazySingleton<FavoriteRepository>(() => FavoriteRepository());
}

void setupLocatorWithContext(BuildContext context) {
Expand Down
23 changes: 23 additions & 0 deletions lib/src/repositories/favorite_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:moviesdb/src/data/models/models.dart';
import 'package:moviesdb/src/locator.dart';
import 'package:moviesdb/src/services/database.dart';

class FavoriteRepository {
DatabaseProvider databaseProvider = locator<DatabaseProvider>();

Future<int> addFavorite(Movie movie) {
return databaseProvider.addMovie(movie);
}

Future<bool> isFavorite(Movie movie) {
return databaseProvider.checkExist(movie);
}

Future<List<Movie>> getFavorites() {
return databaseProvider.getMovies();
}

Future<bool> deleteFavorite(Movie movie) {
return databaseProvider.deleteMovie(movie);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:moviesdb/src/services/services.dart';
import 'package:moviesdb/src/utils/utils.dart';
import 'package:moviesdb/src/extension.dart';

class MoviesRepositories {
class MoviesRepository {
Network _network = locator<Network>();

Future<Movie> getDetailMovie(int movieId) async {
Expand Down
5 changes: 3 additions & 2 deletions lib/src/repositories/repositories.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export 'movies_repositories.dart';
export 'setting_repositories.dart';
export 'movies_repository.dart';
export 'setting_repository.dart';
export 'favorite_repository.dart';
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:package_info/package_info.dart';

class SettingRepositories{
class SettingRepository{
Future<PackageInfo> getAppInfo() async{
return await PackageInfo.fromPlatform();
}
Expand Down
78 changes: 78 additions & 0 deletions lib/src/services/database.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'package:moviesdb/src/data/models/movie.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqflite/sqlite_api.dart';

const String DB_NAME = "movies_database.db";
const String TABLE_FAVORITE = "favorite";

class DatabaseProvider {
static final DatabaseProvider databaseProvider = DatabaseProvider._();
Database _database;

DatabaseProvider._();

Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}

_initDatabase() async {
return await openDatabase(
join(await getDatabasesPath(), DB_NAME),
version: 1,
onCreate: (db, version) {
return db.execute("""CREATE TABLE $TABLE_FAVORITE (
id INTEGER PRIMARY KEY,
poster_path TEXT,
title TEXT,
overview TEXT,
release_date TEXT,
vote_average REAL
)""");
},
);
}

Future close() {
return _database?.close();
}

//delete the database
Future deleteDB() async {
return deleteDatabase(join(await getDatabasesPath(), DB_NAME));
}

Future<int> addMovie(Movie movie) async {
final db = await database;
return await db.insert(TABLE_FAVORITE, movie.toMap(),
conflictAlgorithm: ConflictAlgorithm.ignore);
}

Future<bool> checkExist(Movie movie) async {
final db = await database;
List<Map<String, dynamic>> maps =
await db.query(TABLE_FAVORITE, where: "id = ?", whereArgs: [movie.id]);
return maps.isNotEmpty;
}

Future<List<Movie>> getMovies() async {
final db = await database;
List<Map<String, dynamic>> maps = await db.query(TABLE_FAVORITE);
return maps.map((e) => Movie.formJson(e)).toList();
}

Future<bool> deleteMovie(Movie movie) async {
final db = await database;
final result = await db.delete(TABLE_FAVORITE, where: "id = ?", whereArgs: [movie.id]);
return result >= 0;
}

Future<bool> updateMovie(Movie movie) async {
final db = await database;
final result =
await db.update(TABLE_FAVORITE, movie.toMap(), where: "id = ?", whereArgs: [movie.id]);
return result >= 0;
}
}
3 changes: 2 additions & 1 deletion lib/src/services/services.dart
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export 'network.dart';
export 'network.dart';
export 'database.dart';
39 changes: 33 additions & 6 deletions lib/src/ui/screens/detail_movie_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ class DetailMovieScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Movie movie = ModalRoute.of(context).settings.arguments;
return BlocProvider(
create: (context) => DetailMovieBloc()..add(GetDetailMovie(movie.id)),
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => DetailMovieBloc()..add(GetDetailMovie(movie.id)),
),
BlocProvider(
create: (context) => FavoriteBloc(),
)
],
child: Scaffold(
appBar: AppBar(
title: Text(
Expand All @@ -35,7 +42,12 @@ class DetailMovieScreen extends StatelessWidget {
}

Widget _body(BuildContext context) {
return BlocBuilder<DetailMovieBloc, BaseState>(
return BlocConsumer<DetailMovieBloc, BaseState>(
listener: (context, state) {
if (state is LoadedState) {
context.bloc<FavoriteBloc>().add(CheckFavorite(state.data));
}
},
builder: (context, state) {
if (state is LoadedState) {
return Container(
Expand Down Expand Up @@ -153,9 +165,24 @@ class DetailMovieScreen extends StatelessWidget {
),
),
GestureDetector(
child: Padding(
padding: const EdgeInsets.all(6),
child: Icon(Icons.favorite_border),
onTap: () {
context.bloc<FavoriteBloc>().add(ClickedFavorite(movie));
},
child: BlocBuilder<FavoriteBloc, BaseState>(
condition: (previous, current) {
return current is FavoriteState || current is NormalState;
},
builder: (context, state) {
return Padding(
padding: const EdgeInsets.all(6),
child: state is FavoriteState
? Icon(
Icons.favorite,
color: Colors.redAccent,
)
: Icon(Icons.favorite_border),
);
},
),
),
],
Expand Down
Loading