Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure Webapp UI #445

Merged
merged 4 commits into from
Jun 20, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app/src/main/java/org/jellyfin/mobile/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import org.koin.core.KoinExperimentalAPI

class MainActivity : AppCompatActivity() {
private val mainViewModel: MainViewModel by viewModel()
val appPreferences: AppPreferences by inject()
val chromecast: IChromecast = Chromecast()
private val permissionRequestHelper: PermissionRequestHelper by inject()

Expand Down
20 changes: 12 additions & 8 deletions app/src/main/java/org/jellyfin/mobile/fragment/WebViewFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import android.webkit.WebView
import android.widget.Toast
import androidx.activity.addCallback
import androidx.appcompat.app.AlertDialog
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import androidx.core.view.doOnNextLayout
import androidx.fragment.app.Fragment
Expand All @@ -33,7 +34,6 @@ import androidx.webkit.WebViewCompat
import androidx.webkit.WebViewFeature
import kotlinx.coroutines.launch
import org.jellyfin.mobile.AppPreferences
import org.jellyfin.mobile.MainActivity
import org.jellyfin.mobile.R
import org.jellyfin.mobile.bridge.ExternalPlayer
import org.jellyfin.mobile.bridge.NativeInterface
Expand All @@ -50,6 +50,7 @@ import org.jellyfin.mobile.utils.addFragment
import org.jellyfin.mobile.utils.applyDefault
import org.jellyfin.mobile.utils.applyWindowInsetsAsMargins
import org.jellyfin.mobile.utils.dip
import org.jellyfin.mobile.utils.fadeIn
import org.jellyfin.mobile.utils.initLocale
import org.jellyfin.mobile.utils.isOutdated
import org.jellyfin.mobile.utils.replaceFragment
Expand All @@ -68,7 +69,7 @@ import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

class WebViewFragment : Fragment(), NativePlayerHost {
private val appPreferences: AppPreferences by inject()
val appPreferences: AppPreferences by inject()
private val apiController: ApiController by inject()
private val webappFunctionChannel: WebappFunctionChannel by inject()
private lateinit var assetsPathHandler: AssetsPathHandler
Expand All @@ -81,7 +82,8 @@ class WebViewFragment : Fragment(), NativePlayerHost {
// UI
private var _webViewBinding: FragmentWebviewBinding? = null
private val webViewBinding get() = _webViewBinding!!
val webView: WebView get() = webViewBinding.root
val rootView: CoordinatorLayout get() = webViewBinding.root
val webView: WebView get() = webViewBinding.webView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -100,13 +102,14 @@ class WebViewFragment : Fragment(), NativePlayerHost {

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_webViewBinding = FragmentWebviewBinding.inflate(inflater, container, false)
return webView.apply { applyWindowInsetsAsMargins() }
return webViewBinding.root
}

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

// Apply window insets
webView.applyWindowInsetsAsMargins()
ViewCompat.requestApplyInsets(webView)

// Setup exclusion rects for gestures
Expand Down Expand Up @@ -185,7 +188,7 @@ class WebViewFragment : Fragment(), NativePlayerHost {
val user = storedServer.getString("UserId")
val token = storedServer.getString("AccessToken")
apiController.setupUser(server.id, user, token)
initLocale(user)
webView.initLocale(user)
}
null
}
Expand Down Expand Up @@ -289,9 +292,10 @@ class WebViewFragment : Fragment(), NativePlayerHost {
}.show()
}

fun onConnectedToWebapp() {
private fun onConnectedToWebapp() {
connected = true
(activity as? MainActivity)?.requestNoBatteryOptimizations()
runOnUiThread { webView.fadeIn() }
requestNoBatteryOptimizations()
}

fun onSelectServer(error: Boolean = false) = runOnUiThread {
Expand All @@ -308,7 +312,7 @@ class WebViewFragment : Fragment(), NativePlayerHost {
}
}

fun onErrorReceived() {
private fun onErrorReceived() {
connected = false
onSelectServer(error = true)
}
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/org/jellyfin/mobile/utils/LocaleUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ package org.jellyfin.mobile.utils
import android.content.Context
import android.content.res.Configuration
import android.os.Build
import org.jellyfin.mobile.fragment.WebViewFragment
import android.webkit.WebView
import timber.log.Timber
import java.util.Locale
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

suspend fun WebViewFragment.initLocale(userId: String) {
suspend fun WebView.initLocale(userId: String) {
// Try to set locale via user settings
val userSettings = suspendCoroutine<String> { continuation ->
webView.evaluateJavascript("window.localStorage.getItem('$userId-language')") { result ->
evaluateJavascript("window.localStorage.getItem('$userId-language')") { result ->
continuation.resume(result)
}
}
if (requireContext().setLocale(userSettings.unescapeJson()))
if (context.setLocale(userSettings.unescapeJson()))
return

// Fallback to device locale
Expand Down
7 changes: 3 additions & 4 deletions app/src/main/java/org/jellyfin/mobile/utils/SystemUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeout
import org.jellyfin.mobile.AppPreferences
import org.jellyfin.mobile.BuildConfig
import org.jellyfin.mobile.MainActivity
import org.jellyfin.mobile.R
import org.jellyfin.mobile.fragment.WebViewFragment
import org.jellyfin.mobile.settings.ExternalPlayerPackage
Expand All @@ -34,11 +33,11 @@ import java.io.File
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

fun MainActivity.requestNoBatteryOptimizations() {
fun WebViewFragment.requestNoBatteryOptimizations() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val powerManager: PowerManager = getSystemService(AppCompatActivity.POWER_SERVICE) as PowerManager
val powerManager: PowerManager = requireContext().getSystemService(AppCompatActivity.POWER_SERVICE) as PowerManager
if (!appPreferences.ignoreBatteryOptimizations && !powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) {
Snackbar.make(findViewById(R.id.root_view), R.string.battery_optimizations_message, Snackbar.LENGTH_INDEFINITE).apply {
Snackbar.make(rootView, R.string.battery_optimizations_message, Snackbar.LENGTH_INDEFINITE).apply {
setAction(android.R.string.ok) {
try {
val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/org/jellyfin/mobile/utils/UIExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import androidx.annotation.StringRes
import androidx.annotation.StyleRes
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updateMargins
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -46,6 +48,18 @@ fun View.applyWindowInsetsAsMargins() {
}
}

fun View.fadeIn() {
alpha = 0f
isVisible = true
with(animate()) {
alpha(1f)
@Suppress("MagicNumber")
duration = 300L
interpolator = LinearOutSlowInInterpolator()
start()
}
Maxr1998 marked this conversation as resolved.
Show resolved Hide resolved
}

inline fun Resources.dip(px: Int) = (px * displayMetrics.density).toInt()

inline var Window.brightness: Float
Expand Down
14 changes: 4 additions & 10 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_view"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:viewBindingIgnore="true">

<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/fragment_connect" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
tools:layout="@layout/fragment_connect"
tools:viewBindingIgnore="true" />
11 changes: 9 additions & 2 deletions app/src/main/res/layout/fragment_webview.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
nielsvanvelzen marked this conversation as resolved.
Show resolved Hide resolved
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/theme_background" />
android:background="@color/theme_background">

<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>