diff --git a/app/src/main/java/com/immichframe/immichframe/Helpers.kt b/app/src/main/java/com/immichframe/immichframe/Helpers.kt index 2321f93..1ff4786 100644 --- a/app/src/main/java/com/immichframe/immichframe/Helpers.kt +++ b/app/src/main/java/com/immichframe/immichframe/Helpers.kt @@ -10,8 +10,10 @@ import retrofit2.Call import retrofit2.http.GET import androidx.core.graphics.scale import okhttp3.OkHttpClient +import okhttp3.Request import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit object Helpers { fun textSizeMultiplier(context: Context, currentSizeSp: Float, multiplier: Float): Float { @@ -184,4 +186,23 @@ object Helpers { .addConverterFactory(GsonConverterFactory.create()).build() } + private val reachabilityClient = OkHttpClient.Builder() + .connectTimeout(5, TimeUnit.SECONDS) + .readTimeout(5, TimeUnit.SECONDS) + .build() + + fun isServerReachable(url: String): Boolean { + return try { + val request = Request.Builder() + .url(url) + .head() + .build() + reachabilityClient.newCall(request).execute().use { + true // any HTTP response = reachable + } + } catch (e: Exception) { + false + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/immichframe/immichframe/MainActivity.kt b/app/src/main/java/com/immichframe/immichframe/MainActivity.kt index 25210fa..fb8ea4a 100644 --- a/app/src/main/java/com/immichframe/immichframe/MainActivity.kt +++ b/app/src/main/java/com/immichframe/immichframe/MainActivity.kt @@ -43,6 +43,7 @@ import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale import kotlinx.coroutines.* +import androidx.lifecycle.lifecycleScope import androidx.core.graphics.toColorInt import androidx.core.graphics.drawable.toDrawable import androidx.core.net.toUri @@ -588,7 +589,7 @@ class MainActivity : AppCompatActivity() { webView.settings.javaScriptEnabled = true webView.settings.cacheMode = WebSettings.LOAD_NO_CACHE webView.settings.domStorageEnabled = true - webView.loadUrl(savedUrl) + loadWebViewWithRetry(savedUrl) } else { retrofit = Helpers.createRetrofit(savedUrl, authSecret) apiService = retrofit!!.create(Helpers.ApiService::class.java) @@ -856,4 +857,37 @@ class MainActivity : AppCompatActivity() { rcpServer.stop() handler.removeCallbacksAndMessages(null) } + + private fun loadWebViewWithRetry( + url: String, + attempt: Int = 1, + maxAttempts: Int = 36 + ) { + lifecycleScope.launch { + val reachable = withContext(Dispatchers.IO) { + Helpers.isServerReachable(url) + } + + if (reachable) { + webView.loadUrl(url) + } else if (attempt <= maxAttempts) { + Toast.makeText( + this@MainActivity, + "Connecting to server... Attempt $attempt of $maxAttempts", + Toast.LENGTH_SHORT + ).show() + + delay(5_000) + loadWebViewWithRetry(url, attempt + 1, maxAttempts) + } else { + Toast.makeText( + this@MainActivity, + "Could not connect to server after $maxAttempts attempts", + Toast.LENGTH_LONG + ).show() + + webView.loadUrl(url) + } + } + } } diff --git a/app/src/main/java/com/immichframe/immichframe/ScreenSaverService.kt b/app/src/main/java/com/immichframe/immichframe/ScreenSaverService.kt index 7ef1891..97cf85e 100644 --- a/app/src/main/java/com/immichframe/immichframe/ScreenSaverService.kt +++ b/app/src/main/java/com/immichframe/immichframe/ScreenSaverService.kt @@ -27,6 +27,9 @@ import android.widget.Toast import androidx.preference.PreferenceManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import retrofit2.Call @@ -41,6 +44,7 @@ import androidx.core.graphics.drawable.toDrawable import androidx.core.net.toUri class ScreenSaverService : DreamService() { + private var webViewRetryScope: CoroutineScope? = null private var wakeLock: PowerManager.WakeLock? = null private lateinit var webView: WebView private lateinit var imageView1: ImageView @@ -83,6 +87,7 @@ class ScreenSaverService : DreamService() { @SuppressLint("ClickableViewAccessibility") override fun onDreamingStarted() { super.onDreamingStarted() + webViewRetryScope = CoroutineScope(Dispatchers.Main + Job()) isFullscreen = true isInteractive = true setContentView(R.layout.screen_saver_view) @@ -105,6 +110,8 @@ class ScreenSaverService : DreamService() { override fun onDreamingStopped() { super.onDreamingStopped() + webViewRetryScope?.cancel() + webViewRetryScope = null stopImageTimer() releaseWakeLock() handler.removeCallbacksAndMessages(null) @@ -518,7 +525,7 @@ class ScreenSaverService : DreamService() { webView.settings.javaScriptEnabled = true webView.settings.cacheMode = WebSettings.LOAD_NO_CACHE webView.settings.domStorageEnabled = true - webView.loadUrl(savedUrl) + loadWebViewWithRetry(savedUrl) } else { retrofit = Helpers.createRetrofit(savedUrl, authSecret) apiService = retrofit!!.create(Helpers.ApiService::class.java) @@ -613,4 +620,37 @@ class ScreenSaverService : DreamService() { } wakeLock = null } + + private fun loadWebViewWithRetry( + url: String, + attempt: Int = 1, + maxAttempts: Int = 36 + ) { + webViewRetryScope?.launch { + val reachable = withContext(Dispatchers.IO) { + Helpers.isServerReachable(url) + } + + if (reachable) { + webView.loadUrl(url) + } else if (attempt <= maxAttempts) { + Toast.makeText( + this@ScreenSaverService, + "Connecting to server... Attempt $attempt of $maxAttempts", + Toast.LENGTH_SHORT + ).show() + + delay(5_000) + loadWebViewWithRetry(url, attempt + 1, maxAttempts) + } else { + Toast.makeText( + this@ScreenSaverService, + "Could not connect to server after $maxAttempts attempts", + Toast.LENGTH_LONG + ).show() + + webView.loadUrl(url) + } + } + } } \ No newline at end of file