diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 68ba94e4..f15f38d3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,7 +16,8 @@
+ android:label="@string/title_activity_main"
+ android:windowSoftInputMode="adjustPan"/>
+ navigateToMediaInfoFragment(item)
+ }, HomeEpisodeListAdapter.OnClickListener { item ->
+ navigateToEpisodeBottomSheetFragment(item)
+ })
+
+ viewModel.finishedLoading.observe(viewLifecycleOwner, { isFinished ->
+ binding.loadingIndicator.visibility = if (isFinished) View.GONE else View.VISIBLE
+ })
+
+ viewModel.error.observe(viewLifecycleOwner, { error ->
+ if (error) {
+ snackbar.show()
+ }
+ })
+
+ viewModel.sections.observe(viewLifecycleOwner, { sections ->
+ if (sections.isEmpty()) {
+ binding.noSearchResultsText.visibility = View.VISIBLE
+ } else {
+ binding.noSearchResultsText.visibility = View.GONE
+ }
+ })
+
+ viewModel.loadData(args.query)
+
+ return binding.root
+ }
+
+ private fun navigateToMediaInfoFragment(item: BaseItemDto) {
+ findNavController().navigate(
+ FavoriteFragmentDirections.actionFavoriteFragmentToMediaInfoFragment(
+ item.id,
+ item.name,
+ item.type ?: "Unknown"
+ )
+ )
+ }
+
+ private fun navigateToEpisodeBottomSheetFragment(episode: BaseItemDto) {
+ findNavController().navigate(
+ FavoriteFragmentDirections.actionFavoriteFragmentToEpisodeBottomSheetFragment(
+ episode.id
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepository.kt b/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepository.kt
index e4648c27..64abe807 100644
--- a/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepository.kt
+++ b/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepository.kt
@@ -14,6 +14,8 @@ interface JellyfinRepository {
suspend fun getFavoriteItems(): List
+ suspend fun getSearchItems(searchQuery: String): List
+
suspend fun getResumeItems(): List
suspend fun getLatestMedia(parentId: UUID): List
diff --git a/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt b/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt
index 18f7916b..6008226f 100644
--- a/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt
+++ b/app/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt
@@ -49,6 +49,19 @@ class JellyfinRepositoryImpl(private val jellyfinApi: JellyfinApi) : JellyfinRep
return items
}
+ override suspend fun getSearchItems(searchQuery: String): List {
+ val items: List
+ withContext(Dispatchers.IO) {
+ items = jellyfinApi.itemsApi.getItems(
+ jellyfinApi.userId!!,
+ searchTerm = searchQuery,
+ includeItemTypes = listOf("Movie", "Series", "Episode"),
+ recursive = true
+ ).content.items ?: listOf()
+ }
+ return items
+ }
+
override suspend fun getResumeItems(): List {
val items: List
withContext(Dispatchers.IO) {
diff --git a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/SearchResultViewModel.kt b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/SearchResultViewModel.kt
new file mode 100644
index 00000000..f5f8f925
--- /dev/null
+++ b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/SearchResultViewModel.kt
@@ -0,0 +1,82 @@
+package dev.jdtech.jellyfin.viewmodels
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import dev.jdtech.jellyfin.models.FavoriteSection
+import dev.jdtech.jellyfin.repository.JellyfinRepository
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+import java.util.*
+import javax.inject.Inject
+
+@HiltViewModel
+class SearchResultViewModel
+@Inject
+constructor(
+ private val jellyfinRepository: JellyfinRepository
+) : ViewModel() {
+ private val _sections = MutableLiveData>()
+ val sections: LiveData> = _sections
+
+ private val _finishedLoading = MutableLiveData()
+ val finishedLoading: LiveData = _finishedLoading
+
+ private val _error = MutableLiveData()
+ val error: LiveData = _error
+
+ fun loadData(query: String) {
+ _error.value = false
+ _finishedLoading.value = false
+ viewModelScope.launch {
+ try {
+ val items = jellyfinRepository.getSearchItems(query)
+
+ if (items.isEmpty()) {
+ _sections.value = listOf()
+ _finishedLoading.value = true
+ return@launch
+ }
+
+ val tempSections = mutableListOf()
+
+ withContext(Dispatchers.Default) {
+ FavoriteSection(
+ UUID.randomUUID(),
+ "Movies",
+ items.filter { it.type == "Movie" }).let {
+ if (it.items.isNotEmpty()) tempSections.add(
+ it
+ )
+ }
+ FavoriteSection(
+ UUID.randomUUID(),
+ "Shows",
+ items.filter { it.type == "Series" }).let {
+ if (it.items.isNotEmpty()) tempSections.add(
+ it
+ )
+ }
+ FavoriteSection(
+ UUID.randomUUID(),
+ "Episodes",
+ items.filter { it.type == "Episode" }).let {
+ if (it.items.isNotEmpty()) tempSections.add(
+ it
+ )
+ }
+ }
+
+ _sections.value = tempSections
+ } catch (e: Exception) {
+ Timber.e(e)
+ _error.value = true
+ }
+ _finishedLoading.value = true
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml
new file mode 100644
index 00000000..00b5e5f3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_search.xml
@@ -0,0 +1,21 @@
+
+
+
+
diff --git a/app/src/main/res/layout/favorite_section.xml b/app/src/main/res/layout/favorite_section.xml
index 67fc3242..c8a67162 100644
--- a/app/src/main/res/layout/favorite_section.xml
+++ b/app/src/main/res/layout/favorite_section.xml
@@ -32,7 +32,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
- android:layoutAnimation="@anim/overview_media_animation"
android:orientation="horizontal"
android:paddingHorizontal="12dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
diff --git a/app/src/main/res/layout/fragment_search_result.xml b/app/src/main/res/layout/fragment_search_result.xml
new file mode 100644
index 00000000..d250d75e
--- /dev/null
+++ b/app/src/main/res/layout/fragment_search_result.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/media_menu.xml b/app/src/main/res/menu/media_menu.xml
new file mode 100644
index 00000000..9195a338
--- /dev/null
+++ b/app/src/main/res/menu/media_menu.xml
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/main_navigation.xml b/app/src/main/res/navigation/main_navigation.xml
index ae17c88f..7a2a1246 100644
--- a/app/src/main/res/navigation/main_navigation.xml
+++ b/app/src/main/res/navigation/main_navigation.xml
@@ -48,12 +48,15 @@
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
+
+ android:label="@string/title_settings" />
+ app:nullable="true" />
+ tools:layout="@layout/activity_player">
@@ -165,4 +168,19 @@
android:id="@+id/action_favoriteFragment_to_mediaInfoFragment"
app:destination="@id/mediaInfoFragment" />
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 27989468..9dbea87d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -40,7 +40,8 @@
Latest %1$s
Series poster
You have no favorites
-
+ Search
+ No search results
Language
Preferred audio language
Preferred subtitle language