From 93518f67eed6d27515c1eaaeb1f41890273b34bd Mon Sep 17 00:00:00 2001 From: Jarne Demeulemeester Date: Sun, 13 Jun 2021 14:42:03 +0200 Subject: [PATCH] Get views in home fragment --- app/src/main/AndroidManifest.xml | 3 +- .../dev/jdtech/jellyfin/BindingAdapters.kt | 12 ++++- .../jellyfin/adapters/ViewListAdapter.kt | 37 +++++++++++++++ .../dev/jdtech/jellyfin/api/JellyfinApi.kt | 5 ++ .../jdtech/jellyfin/fragments/HomeFragment.kt | 17 ++++++- .../fragments/ServerSelectFragment.kt | 30 ++++++++---- .../jellyfin/viewmodels/HomeViewModel.kt | 27 +++++++++++ .../viewmodels/HomeViewModelFactory.kt | 18 ++++++++ .../viewmodels/ServerSelectViewModel.kt | 18 ++++++++ app/src/main/res/layout/fragment_home.xml | 46 +++++++++++-------- .../res/layout/fragment_server_select.xml | 2 +- app/src/main/res/layout/view_item.xml | 38 +++++++++++++++ 12 files changed, 220 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt create mode 100644 app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt create mode 100644 app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModelFactory.kt create mode 100644 app/src/main/res/layout/view_item.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 242deab7..96a0e86d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,8 +14,7 @@ android:label="@string/title_activity_main"/> + android:windowSoftInputMode="adjustPan"> diff --git a/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt b/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt index 55d290b2..15e27745 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt @@ -4,9 +4,17 @@ import androidx.databinding.BindingAdapter import androidx.recyclerview.widget.RecyclerView import dev.jdtech.jellyfin.database.Server import dev.jdtech.jellyfin.adapters.ServerGridAdapter +import dev.jdtech.jellyfin.adapters.ViewListAdapter +import org.jellyfin.sdk.model.api.BaseItemDto -@BindingAdapter("listData") -fun bindRecyclerView(recyclerView: RecyclerView, data: List?) { +@BindingAdapter("servers") +fun bindServers(recyclerView: RecyclerView, data: List?) { val adapter = recyclerView.adapter as ServerGridAdapter adapter.submitList(data) +} + +@BindingAdapter("views") +fun bindViews(recyclerView: RecyclerView, data: List?) { + val adapter = recyclerView.adapter as ViewListAdapter + adapter.submitList(data) } \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt b/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt new file mode 100644 index 00000000..b5635eed --- /dev/null +++ b/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt @@ -0,0 +1,37 @@ +package dev.jdtech.jellyfin.adapters + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import dev.jdtech.jellyfin.databinding.ViewItemBinding +import org.jellyfin.sdk.model.api.BaseItemDto + +class ViewListAdapter : ListAdapter(DiffCallback) { + class ViewHolder(private var binding: ViewItemBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(view: BaseItemDto) { + binding.view = view + binding.executePendingBindings() + } + } + + companion object DiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: BaseItemDto, newItem: BaseItemDto): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: BaseItemDto, newItem: BaseItemDto): Boolean { + return oldItem == newItem + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder(ViewItemBinding.inflate(LayoutInflater.from(parent.context))) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val view = getItem(position) + holder.bind(view) + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt b/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt index bcb74045..6403e0ca 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt @@ -7,7 +7,9 @@ import org.jellyfin.sdk.Jellyfin import org.jellyfin.sdk.android import org.jellyfin.sdk.api.operations.SystemApi import org.jellyfin.sdk.api.operations.UserApi +import org.jellyfin.sdk.api.operations.UserViewsApi import org.jellyfin.sdk.model.ClientInfo +import java.util.* /** @@ -24,8 +26,11 @@ class JellyfinApi(context: Context, baseUrl: String) { android(context) } val api = jellyfin.createApi(baseUrl = baseUrl) + var userId: UUID? = null + val systemApi = SystemApi(api) val userApi = UserApi(api) + val viewsApi = UserViewsApi(api) init { Log.i("JellyfinApi", "Constructor called!") diff --git a/app/src/main/java/dev/jdtech/jellyfin/fragments/HomeFragment.kt b/app/src/main/java/dev/jdtech/jellyfin/fragments/HomeFragment.kt index 2cf42784..d0d9b02d 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/fragments/HomeFragment.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/fragments/HomeFragment.kt @@ -1,11 +1,17 @@ package dev.jdtech.jellyfin.fragments import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider import dev.jdtech.jellyfin.R +import dev.jdtech.jellyfin.adapters.ViewListAdapter +import dev.jdtech.jellyfin.databinding.FragmentHomeBinding +import dev.jdtech.jellyfin.viewmodels.HomeViewModel +import dev.jdtech.jellyfin.viewmodels.HomeViewModelFactory class HomeFragment : Fragment() { override fun onCreateView( @@ -13,6 +19,15 @@ class HomeFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_home, container, false) + val application = requireNotNull(this.activity).application + val binding = FragmentHomeBinding.inflate(inflater) + val viewModelFactory = HomeViewModelFactory(application) + val viewModel = ViewModelProvider(this, viewModelFactory).get(HomeViewModel::class.java) + + binding.lifecycleOwner = this + binding.viewModel = viewModel + binding.viewsRecyclerView.adapter = ViewListAdapter() + + return binding.root } } \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/fragments/ServerSelectFragment.kt b/app/src/main/java/dev/jdtech/jellyfin/fragments/ServerSelectFragment.kt index 585df83c..d81d6fe8 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/fragments/ServerSelectFragment.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/fragments/ServerSelectFragment.kt @@ -29,21 +29,35 @@ class ServerSelectFragment : Fragment() { val dataSource = ServerDatabase.getInstance(application).serverDatabaseDao val viewModelFactory = ServerSelectViewModelFactory(dataSource, application) - val viewModel = ViewModelProvider(this, viewModelFactory).get(ServerSelectViewModel::class.java) + val viewModel = + ViewModelProvider(this, viewModelFactory).get(ServerSelectViewModel::class.java) binding.lifecycleOwner = this binding.viewModel = viewModel - binding.serversRecyclerView.adapter = ServerGridAdapter(ServerGridAdapter.OnClickListener { server -> - Toast.makeText(application, "You selected server $server", Toast.LENGTH_SHORT).show() - findNavController().navigate(R.id.action_serverSelectFragment_to_mainActivity) - }, ServerGridAdapter.OnLongClickListener { server -> - DeleteServerDialogFragment(viewModel, server).show(parentFragmentManager, "deleteServer") - true - }) + binding.serversRecyclerView.adapter = + ServerGridAdapter(ServerGridAdapter.OnClickListener { server -> + Toast.makeText(application, "You selected server $server", Toast.LENGTH_SHORT) + .show() + viewModel.connectToServer(server) + }, ServerGridAdapter.OnLongClickListener { server -> + DeleteServerDialogFragment(viewModel, server).show( + parentFragmentManager, + "deleteServer" + ) + true + }) binding.buttonAddServer.setOnClickListener { this.findNavController().navigate(R.id.action_serverSelectFragment_to_addServerFragment) } + + viewModel.navigateToMain.observe(viewLifecycleOwner, { + if (it) { + findNavController().navigate(R.id.action_serverSelectFragment_to_mainActivity) + viewModel.doneNavigatingToMain() + } + }) + return binding.root } } \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt new file mode 100644 index 00000000..c2181bd3 --- /dev/null +++ b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt @@ -0,0 +1,27 @@ +package dev.jdtech.jellyfin.viewmodels + +import android.app.Application +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dev.jdtech.jellyfin.api.JellyfinApi +import kotlinx.coroutines.launch +import org.jellyfin.sdk.model.api.BaseItemDto + +class HomeViewModel( + application: Application +) : ViewModel() { + private val jellyfinApi = JellyfinApi.getInstance(application, "") + + private val _views = MutableLiveData>() + val views: LiveData> = _views + + init { + viewModelScope.launch { + val result by jellyfinApi.viewsApi.getUserViews(jellyfinApi.userId!!) + _views.value = result.items + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModelFactory.kt b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModelFactory.kt new file mode 100644 index 00000000..4b1e6bde --- /dev/null +++ b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModelFactory.kt @@ -0,0 +1,18 @@ +package dev.jdtech.jellyfin.viewmodels + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import java.lang.IllegalArgumentException + +class HomeViewModelFactory( + private val application: Application +) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(HomeViewModel::class.java)) { + @Suppress("UNCHECKED_CAST") + return HomeViewModel(application) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt index 3ef005cf..80993dae 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt @@ -2,13 +2,16 @@ package dev.jdtech.jellyfin.viewmodels import android.app.Application import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import dev.jdtech.jellyfin.api.JellyfinApi import dev.jdtech.jellyfin.database.Server import dev.jdtech.jellyfin.database.ServerDatabaseDao import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.util.* class ServerSelectViewModel( val database: ServerDatabaseDao, @@ -17,6 +20,9 @@ class ServerSelectViewModel( private val _servers = database.getAllServers() val servers: LiveData> = _servers + private val _navigateToMain = MutableLiveData() + val navigateToMain: LiveData = _navigateToMain + /** * Delete server from database * @@ -29,4 +35,16 @@ class ServerSelectViewModel( } } } + + fun connectToServer(server: Server) { + JellyfinApi.getInstance(application, server.address).apply { + api.accessToken = server.accessToken + userId = UUID.fromString(server.userId) + } + _navigateToMain.value = true + } + + fun doneNavigatingToMain() { + _navigateToMain.value = false + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index abccaa1b..dca99714 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -1,23 +1,31 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + + + + + - + android:layout_height="match_parent" + tools:context=".fragments.HomeFragment"> + + + + diff --git a/app/src/main/res/layout/fragment_server_select.xml b/app/src/main/res/layout/fragment_server_select.xml index bd189b91..9c5a5ef2 100644 --- a/app/src/main/res/layout/fragment_server_select.xml +++ b/app/src/main/res/layout/fragment_server_select.xml @@ -60,7 +60,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/image_banner" app:layout_constraintVertical_bias="0.36" - app:listData="@{viewModel.servers}" + app:servers="@{viewModel.servers}" app:spanCount="3" tools:itemCount="4" tools:listitem="@layout/server_item" /> diff --git a/app/src/main/res/layout/view_item.xml b/app/src/main/res/layout/view_item.xml new file mode 100644 index 00000000..77a466c2 --- /dev/null +++ b/app/src/main/res/layout/view_item.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + \ No newline at end of file