Skip to content

Commit

Permalink
Rewrite connection screen in Jetpack Compose
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxr1998 committed Sep 21, 2022
1 parent 1f6e475 commit 6dbe848
Show file tree
Hide file tree
Showing 22 changed files with 656 additions and 371 deletions.
9 changes: 8 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,15 @@ android {
@Suppress("UnstableApiUsage")
buildFeatures {
viewBinding = true
compose = true
}
kotlinOptions {
@Suppress("SuspiciousCollectionReassignment")
freeCompilerArgs += listOf("-Xopt-in=kotlin.RequiresOptIn")
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
Expand All @@ -108,7 +112,7 @@ dependencies {
implementation(libs.bundles.coroutines)

// Core
implementation(libs.koin)
implementation(libs.bundles.koin)
implementation(libs.androidx.core)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.activity)
Expand All @@ -124,6 +128,9 @@ dependencies {
implementation(libs.androidx.webkit)
implementation(libs.modernandroidpreferences)

// Jetpack Compose
implementation(libs.bundles.compose)

// Network
val sdkVersion = findProperty("sdk.version")?.toString()
implementation(libs.jellyfin.sdk) {
Expand Down
1 change: 1 addition & 0 deletions app/src/debug/res/values/strings_donottranslate.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Jellyfin Debug</string>
<string name="app_name_short" translatable="false">Jellyfin</string>
</resources>
4 changes: 2 additions & 2 deletions app/src/main/java/org/jellyfin/mobile/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import androidx.lifecycle.lifecycleScope
import org.jellyfin.mobile.player.cast.Chromecast
import org.jellyfin.mobile.player.cast.IChromecast
import org.jellyfin.mobile.player.ui.PlayerFragment
import org.jellyfin.mobile.setup.ConnectFragment
import org.jellyfin.mobile.setup.ComposeFragment
import org.jellyfin.mobile.utils.Constants
import org.jellyfin.mobile.utils.PermissionRequestHelper
import org.jellyfin.mobile.utils.SmartOrientationListener
Expand Down Expand Up @@ -83,7 +83,7 @@ class MainActivity : AppCompatActivity() {
ServerState.Pending -> {
// TODO add loading indicator
}
is ServerState.Unset -> replaceFragment<ConnectFragment>()
is ServerState.Unset -> replaceFragment<ComposeFragment>()
is ServerState.Available -> {
val currentFragment = findFragmentById(R.id.fragment_container)
if (currentFragment !is WebViewFragment || currentFragment.server != state.server) {
Expand Down
12 changes: 8 additions & 4 deletions app/src/main/java/org/jellyfin/mobile/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ class MainViewModel(

init {
viewModelScope.launch {
apiClientController.migrateFromPreferences()
refreshServer()
}
}

suspend fun refreshServer() {
val server = apiClientController.loadSavedServer()
_serverState.value = server?.let { ServerState.Available(it) } ?: ServerState.Unset
suspend fun switchServer(hostname: String) {
apiClientController.setupServer(hostname)
refreshServer()
}

private suspend fun refreshServer() {
val serverEntity = apiClientController.loadSavedServer()
_serverState.value = serverEntity?.let { entity -> ServerState.Available(entity) } ?: ServerState.Unset
}
}

Expand Down
11 changes: 1 addition & 10 deletions app/src/main/java/org/jellyfin/mobile/app/ApiClientController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import org.jellyfin.sdk.Jellyfin
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.model.DeviceInfo
import org.jellyfin.sdk.model.serializer.toUUID
import java.util.*

class ApiClientController(
private val appPreferences: AppPreferences,
Expand All @@ -22,16 +21,8 @@ class ApiClientController(
get() = jellyfin.options.deviceInfo!!

/**
* Migrate from preferences if necessary
* Store server with [hostname] in the database.
*/
@Suppress("DEPRECATION")
suspend fun migrateFromPreferences() {
appPreferences.instanceUrl?.let { url ->
setupServer(url)
appPreferences.instanceUrl = null
}
}

suspend fun setupServer(hostname: String) {
appPreferences.currentServerId = withContext(Dispatchers.IO) {
serverDao.getServerByHostname(hostname)?.id ?: serverDao.insert(hostname)
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/java/org/jellyfin/mobile/app/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import org.jellyfin.mobile.player.deviceprofile.DeviceProfileBuilder
import org.jellyfin.mobile.player.interaction.PlayerEvent
import org.jellyfin.mobile.player.source.MediaSourceResolver
import org.jellyfin.mobile.player.ui.PlayerFragment
import org.jellyfin.mobile.setup.ConnectFragment
import org.jellyfin.mobile.setup.ConnectionHelper
import org.jellyfin.mobile.utils.Constants
import org.jellyfin.mobile.utils.PermissionRequestHelper
import org.jellyfin.mobile.utils.isLowRamDevice
Expand Down Expand Up @@ -58,10 +58,12 @@ val applicationModule = module {
viewModel { MainViewModel(get(), get()) }

// Fragments
fragment { ConnectFragment() }
fragment { WebViewFragment() }
fragment { PlayerFragment() }

// Connection helper
single { ConnectionHelper(get(), get()) }

// Media player helpers
single { MediaSourceResolver(get()) }
single { DeviceProfileBuilder() }
Expand Down
46 changes: 46 additions & 0 deletions app/src/main/java/org/jellyfin/mobile/setup/ComposeFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.jellyfin.mobile.setup

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import org.jellyfin.mobile.MainViewModel
import org.jellyfin.mobile.databinding.FragmentComposeBinding
import org.jellyfin.mobile.ui.screens.connect.ConnectScreen
import org.jellyfin.mobile.ui.utils.AppTheme
import org.jellyfin.mobile.utils.Constants
import org.jellyfin.mobile.utils.applyWindowInsetsAsMargins
import org.koin.androidx.viewmodel.ext.android.sharedViewModel

class ComposeFragment : Fragment() {
private val mainViewModel: MainViewModel by sharedViewModel()
private var _viewBinding: FragmentComposeBinding? = null
private val viewBinding get() = _viewBinding!!
private val composeView: ComposeView get() = viewBinding.composeView

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_viewBinding = FragmentComposeBinding.inflate(inflater, container, false)
return composeView.apply { applyWindowInsetsAsMargins() }
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

// Apply window insets
ViewCompat.requestApplyInsets(composeView)

val encounteredConnectionError = arguments?.getBoolean(Constants.FRAGMENT_CONNECT_EXTRA_ERROR) == true

composeView.setContent {
AppTheme {
ConnectScreen(
mainViewModel = mainViewModel,
showExternalConnectionError = encounteredConnectionError,
)
}
}
}
}
Loading

0 comments on commit 6dbe848

Please sign in to comment.