Make login functional + add to database

This commit is contained in:
Jarne Demeulemeester 2021-06-10 17:04:55 +02:00
parent 08a62ad6b2
commit dbe3d221e4
No known key found for this signature in database
GPG key ID: 60884A0C1EBA43E5
8 changed files with 190 additions and 69 deletions

View file

@ -6,6 +6,7 @@ import dev.jdtech.jellyfin.BuildConfig
import org.jellyfin.sdk.Jellyfin import org.jellyfin.sdk.Jellyfin
import org.jellyfin.sdk.android import org.jellyfin.sdk.android
import org.jellyfin.sdk.api.operations.SystemApi import org.jellyfin.sdk.api.operations.SystemApi
import org.jellyfin.sdk.api.operations.UserApi
import org.jellyfin.sdk.model.ClientInfo import org.jellyfin.sdk.model.ClientInfo
class JellyfinApi(context: Context, baseUrl: String) { class JellyfinApi(context: Context, baseUrl: String) {
@ -16,6 +17,7 @@ class JellyfinApi(context: Context, baseUrl: String) {
} }
val api = jellyfin.createApi(baseUrl = baseUrl) val api = jellyfin.createApi(baseUrl = baseUrl)
val systemApi = SystemApi(api) val systemApi = SystemApi(api)
val userApi = UserApi(api)
init { init {
Log.i("JellyfinApi", "Constructor called!") Log.i("JellyfinApi", "Constructor called!")

View file

@ -26,7 +26,7 @@ class AddServerFragment : Fragment() {
binding.lifecycleOwner = this binding.lifecycleOwner = this
binding.viewModel = viewModel binding.viewModel = viewModel
binding.buttonConnect.setOnClickListener { v: View -> binding.buttonConnect.setOnClickListener {
val serverAddress = binding.editTextServerAddress.text.toString() val serverAddress = binding.editTextServerAddress.text.toString()
if (serverAddress.isNotBlank()) { if (serverAddress.isNotBlank()) {
viewModel.checkServer(serverAddress) viewModel.checkServer(serverAddress)

View file

@ -5,13 +5,36 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dev.jdtech.jellyfin.R import androidx.lifecycle.ViewModelProvider
import dev.jdtech.jellyfin.databinding.FragmentLoginBinding
import dev.jdtech.jellyfin.viewmodels.LoginViewModel
import dev.jdtech.jellyfin.viewmodels.LoginViewModelFactory
class LoginFragment : Fragment() { class LoginFragment : Fragment() {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
return inflater.inflate(R.layout.fragment_login, container, false) val application = requireNotNull(this.activity).application
val binding = FragmentLoginBinding.inflate(inflater)
val viewModelFactory = LoginViewModelFactory(application)
val viewModel = ViewModelProvider(this, viewModelFactory).get(LoginViewModel::class.java)
binding.lifecycleOwner = this
binding.viewModel = viewModel
binding.buttonLogin.setOnClickListener {
val username = binding.editTextUsername.text.toString()
val password = binding.editTextPassword.text.toString()
binding.progressCircular.visibility = View.VISIBLE
viewModel.login(username, password)
}
viewModel.error.observe(viewLifecycleOwner, {
binding.progressCircular.visibility = View.GONE
binding.editTextUsername.error = it
})
return binding.root
} }
} }

View file

@ -34,7 +34,7 @@ class ServerSelectFragment : Fragment() {
binding.lifecycleOwner = this binding.lifecycleOwner = this
binding.viewModel = viewModel binding.viewModel = viewModel
binding.serversRecyclerView.adapter = ServerGridAdapter(ServerGridAdapter.OnClickListener { server -> binding.serversRecyclerView.adapter = ServerGridAdapter(ServerGridAdapter.OnClickListener { server ->
Toast.makeText(application, "You selected server ${server.name}", Toast.LENGTH_SHORT).show() Toast.makeText(application, "You selected server $server", Toast.LENGTH_SHORT).show()
}, ServerGridAdapter.OnLongClickListener { server -> }, ServerGridAdapter.OnLongClickListener { server ->
DeleteServerDialogFragment(viewModel, server).show(parentFragmentManager, "deleteServer") DeleteServerDialogFragment(viewModel, server).show(parentFragmentManager, "deleteServer")
true true

View file

@ -28,7 +28,7 @@ class AddServerViewModel(val application: Application) : ViewModel() {
_error.value = null _error.value = null
_navigateToLogin.value = true _navigateToLogin.value = true
} catch (e: Exception) { } catch (e: Exception) {
Log.e("JellyfinApi", "${e.message}") Log.e("AddServerViewModel", "${e.message}")
_error.value = e.message _error.value = e.message
_navigateToLogin.value = false _navigateToLogin.value = false
} }

View file

@ -0,0 +1,51 @@
package dev.jdtech.jellyfin.viewmodels
import android.app.Application
import android.util.Log
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.ServerDatabase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.exception.ApiClientException
import org.jellyfin.sdk.model.api.AuthenticateUserByName
import java.lang.Exception
class LoginViewModel(application: Application) : ViewModel() {
private val jellyfinApi = JellyfinApi.getInstance(application, "")
private val database = ServerDatabase.getInstance(application).serverDatabaseDao
private val _error = MutableLiveData<String>()
val error: LiveData<String>
get() = _error
fun login(username: String, password: String) {
viewModelScope.launch {
try {
val authenticationResult by jellyfinApi.userApi.authenticateUserByName(
data = AuthenticateUserByName(
username = username,
pw = password)
)
_error.value = null
val serverInfo by jellyfinApi.systemApi.getPublicSystemInfo()
val server = Server(serverInfo.id!!, serverInfo.serverName!!, jellyfinApi.api.baseUrl!!, authenticationResult.user?.id.toString(), authenticationResult.user?.name!!, authenticationResult.accessToken!!)
insert(server)
} catch (e: Exception) {
Log.e("LoginViewModel", "${e.message}")
_error.value = e.message
}
}
}
private suspend fun insert(server: Server) {
withContext(Dispatchers.IO) {
database.insert(server)
}
}
}

View file

@ -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 LoginViewModelFactory(
private val application: Application
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return LoginViewModel(application) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

View file

@ -1,75 +1,102 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools">
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.LoginFragment">
<ImageView <data>
android:id="@+id/image_banner"
android:layout_width="268dp"
android:layout_height="75dp"
android:layout_marginTop="64dp"
android:contentDescription="@string/jellyfin_banner"
android:src="@drawable/ic_banner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout <variable
android:id="@+id/linearLayout" name="viewModel"
type="dev.jdtech.jellyfin.viewmodels.LoginViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginStart="24dp" tools:context=".fragments.LoginFragment">
android:layout_marginEnd="24dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image_banner"
app:layout_constraintVertical_bias="0.36">
<TextView <ImageView
android:id="@+id/text_login" android:id="@+id/image_banner"
style="@style/text_header" android:layout_width="268dp"
android:layout_width="wrap_content" android:layout_height="75dp"
android:layout_height="wrap_content" android:layout_marginTop="64dp"
android:layout_marginBottom="32dp" android:contentDescription="@string/jellyfin_banner"
android:text="@string/login" android:src="@drawable/ic_banner"
android:textColor="?android:textColorPrimary" /> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText <LinearLayout
android:id="@+id/edit_text_username" android:id="@+id/linearLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="12dp" android:layout_marginStart="24dp"
android:autofillHints="username" android:layout_marginEnd="24dp"
android:background="@drawable/edit_text_background" android:orientation="vertical"
android:hint="@string/edit_text_username_hint" app:layout_constraintBottom_toBottomOf="parent"
android:inputType="text" app:layout_constraintEnd_toEndOf="parent"
android:padding="10dp" app:layout_constraintStart_toStartOf="parent"
android:textAppearance="@style/text_subtitle" app:layout_constraintTop_toBottomOf="@+id/image_banner"
android:textColorHint="@color/neutral_400" /> app:layout_constraintVertical_bias="0.36">
<EditText <TextView
android:id="@+id/edit_text_password" android:id="@+id/text_login"
android:layout_width="match_parent" style="@style/text_header"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_marginBottom="24dp" android:layout_height="wrap_content"
android:autofillHints="password" android:layout_marginBottom="32dp"
android:background="@drawable/edit_text_background" android:text="@string/login"
android:hint="@string/edit_text_password_hint" android:textColor="?android:textColorPrimary" />
android:inputType="textPassword"
android:padding="10dp"
android:textAppearance="@style/text_subtitle"
android:textColorHint="@color/neutral_400" />
<Button <EditText
android:id="@+id/button_login" android:id="@+id/edit_text_username"
android:layout_width="match_parent" android:layout_width="match_parent"
style="@style/setup_button" android:layout_height="wrap_content"
android:text="@string/button_login" /> android:layout_marginBottom="12dp"
</LinearLayout> android:autofillHints="username"
android:background="@drawable/edit_text_background"
android:hint="@string/edit_text_username_hint"
android:inputType="text"
android:padding="10dp"
android:textAppearance="@style/text_subtitle"
android:textColorHint="@color/neutral_400" />
</androidx.constraintlayout.widget.ConstraintLayout> <EditText
android:id="@+id/edit_text_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:autofillHints="password"
android:background="@drawable/edit_text_background"
android:hint="@string/edit_text_password_hint"
android:inputType="textPassword"
android:padding="10dp"
android:textAppearance="@style/text_subtitle"
android:textColorHint="@color/neutral_400" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/button_login"
style="@style/setup_button"
android:layout_width="match_parent"
android:text="@string/button_login" />
<ProgressBar
android:id="@+id/progress_circular"
android:layout_width="48dp"
android:layout_height="48dp"
android:elevation="8dp"
android:indeterminateTint="@color/white"
android:padding="8dp"
android:visibility="invisible" />
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>