Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add search screen #14

Merged
merged 1 commit into from
Dec 21, 2023
Merged
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
8 changes: 7 additions & 1 deletion lib/screens/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:jellyflix/screens/library_screen.dart';
import 'package:jellyflix/screens/profile_screen.dart';
import 'package:jellyflix/screens/search_screen.dart';

class HomeScreen extends HookConsumerWidget {
const HomeScreen({super.key});
Expand All @@ -24,7 +25,12 @@ class HomeScreen extends HookConsumerWidget {
icon: const Icon(Icons.video_library_outlined),
),
actions: [
IconButton(onPressed: () {}, icon: const Icon(Icons.search_rounded)),
IconButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const SearchScreen()));
},
icon: const Icon(Icons.search_rounded)),
IconButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
Expand Down
2 changes: 1 addition & 1 deletion lib/screens/library_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class LibraryScreen extends HookConsumerWidget {
);
},
child: Text(
"Genre: ${genreFilter.value!.map(
"Genre: ${genreFilter.value == null ? "All" : genreFilter.value!.map(
(e) => e.name,
).isEmpty ? "All" : genreFilter.value!.map(
(e) => e.name,
Expand Down
157 changes: 157 additions & 0 deletions lib/screens/search_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:jellyflix/components/item_carousel.dart';
import 'package:jellyflix/models/poster_type.dart';
import 'package:jellyflix/providers/api_provider.dart';
import 'package:jellyflix/screens/detail_screen.dart';
import 'package:openapi/openapi.dart';

class SearchScreen extends HookConsumerWidget {
const SearchScreen({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final searchQuery = useState<String?>(null);

return Scaffold(
appBar: AppBar(
title: Padding(
padding: const EdgeInsets.all(5.0),
child: SizedBox(
width: double.infinity,
height: 40,
child: SearchBar(
hintText: "Search",
leading: const Icon(Icons.search_rounded),
onChanged: (value) {
if (value != "") {
searchQuery.value = value;
} else {
searchQuery.value = null;
}
},
),
)),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 20.0),
child: (searchQuery.value ?? "").isEmpty
? const Center(child: Text("Start typing to search"))
: SingleChildScrollView(
child: FutureBuilder(
future: ref
.read(apiProvider)
.getFilterItems(searchTerm: searchQuery.value),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data!.isEmpty) {
return const Center(child: Text("No results found"));
}
List<BaseItemDto> movieList = snapshot.data!
.where(
(element) => element.type == BaseItemKind.movie)
.toList();
List<BaseItemDto> seriesList = snapshot.data!
.where(
(element) => element.type == BaseItemKind.series)
.toList();
List<BaseItemDto> episodeList = snapshot.data!
.where(
(element) => element.type == BaseItemKind.episode)
.toList();
List<BaseItemDto> collectionList = snapshot.data!
.where(
(element) => element.type == BaseItemKind.boxSet)
.toList();
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
movieList.isEmpty
? const SizedBox()
: ItemCarousel(
imageList: movieList.map((e) {
return e.id!;
}).toList(),
titleList: movieList.map((e) {
return e.name!;
}).toList(),
onTap: (index) {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => DetailScreen(
itemId: movieList[index].id!,
)));
},
title: "Movies",
),
seriesList.isEmpty
? const SizedBox()
: ItemCarousel(
imageList: seriesList.map((e) {
return e.id!;
}).toList(),
titleList: seriesList.map((e) {
return e.name!;
}).toList(),
onTap: (index) {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => DetailScreen(
itemId: seriesList[index].id!,
)));
},
title: "Series",
),
episodeList.isEmpty
? const SizedBox()
: ItemCarousel(
posterType: PosterType.horizontal,
imageList: episodeList.map((e) {
return e.id!;
}).toList(),
titleList: episodeList.map((e) {
return e.name!;
}).toList(),
onTap: (index) {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => DetailScreen(
itemId:
episodeList[index].id!,
)));
},
title: "Episodes",
),
collectionList.isEmpty
? const SizedBox()
: ItemCarousel(
imageList: collectionList.map((e) {
return e.id!;
}).toList(),
titleList: collectionList.map((e) {
return e.name!;
}).toList(),
onTap: (index) {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => DetailScreen(
itemId:
collectionList[index].id!,
)));
},
title: "Collections",
),
],
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
),
),
);
}
}
24 changes: 14 additions & 10 deletions lib/services/api_service.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import 'package:jellyflix/models/sort_type.dart';
import 'package:jellyflix/models/user.dart';
import 'package:flutter/material.dart';
import 'package:jellyflix/screens/filter_type.dart';
import 'package:jellyflix/screens/library_screen.dart';
import 'package:openapi/openapi.dart';
import 'package:built_collection/built_collection.dart';

Expand Down Expand Up @@ -120,20 +117,27 @@ class ApiService {
}

Future<List<BaseItemDto>> getFilterItems(
{List<BaseItemDto>? genreIds,
List<FilterType>? filters,
SortType? sortType}) async {
{List<BaseItemDto>? genreIds, String? searchTerm}) async {
var folders = await getMediaFolders();
var ids = genreIds == null
? null
: BuiltList<String>.from(genreIds.map((e) => e.id!));
List<BaseItemDto> items = [];
for (var folder in folders) {
var response = await _jellyfinApi!.getItemsApi().getItems(
userId: _user!.id!,
headers: headers,
parentId: folder.id,
genreIds: ids);
userId: _user!.id!,
headers: headers,
parentId: folder.id,
genreIds: ids,
searchTerm: searchTerm,
recursive: true,
includeItemTypes: BuiltList<BaseItemKind>([
BaseItemKind.movie,
BaseItemKind.series,
BaseItemKind.episode,
BaseItemKind.boxSet
]),
);
items.addAll(response.data!.items!);
}
return items;
Expand Down
Loading