Make login functional + add to database
This commit is contained in:
parent
08a62ad6b2
commit
dbe3d221e4
8 changed files with 190 additions and 69 deletions
|
@ -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!")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue