Skip to content

Commit 4aded60

Browse files
authored
Merge pull request #17 from immichFrame/dev.3rob3.NewSettings
New settings and theme
2 parents cd0eaf5 + 68dc5bd commit 4aded60

File tree

14 files changed

+326
-354
lines changed

14 files changed

+326
-354
lines changed

app/build.gradle.kts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ android {
3030
applicationId = "com.immichframe.immichframe"
3131
minSdk = 23
3232
targetSdk = 35
33-
versionCode = 42
34-
versionName = "1.0.42.0"
33+
versionCode = 43
34+
versionName = "1.0.43.0"
3535
}
3636

3737
buildTypes {
@@ -75,6 +75,7 @@ dependencies {
7575
implementation(libs.retrofit)
7676
implementation(libs.retrofitgson)
7777
implementation(libs.nanohttpd)
78+
implementation(libs.androidx.preference)
7879
testImplementation(libs.junit)
7980
androidTestImplementation(libs.androidx.junit)
8081
androidTestImplementation(libs.androidx.espresso.core)

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
xmlns:tools="http://schemas.android.com/tools"
44
package="com.immichframe.immichframe">
55

6+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
67
<uses-permission android:name="android.permission.INTERNET" />
78
<uses-permission android:name="android.permission.WAKE_LOCK" />
89

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
5+
<title>Error</title>
6+
<style>
7+
body {
8+
background-color: #121212;
9+
color: #ffffff;
10+
font-family: sans-serif;
11+
padding: 20px;
12+
text-align: center;
13+
}
14+
h2 {
15+
color: #ff5555;
16+
}
17+
.error-details {
18+
margin-top: 20px;
19+
font-size: 14px;
20+
color: #bbbbbb;
21+
}
22+
</style>
23+
</head>
24+
<body>
25+
<h2>Oops! Something went wrong.</h2>
26+
<p>Unable to load the page. Please check your connection.</p>
27+
<p>Retrying in 5 seconds...</p>
28+
<div class="error-details" id="error-details">
29+
<!-- Error info will be injected by JavaScript -->
30+
</div>
31+
<script>
32+
function showError(code, description) {
33+
document.getElementById("error-details").innerHTML =
34+
"<p><strong>Error code:</strong> " + code + "</p>" +
35+
"<p><strong>Description:</strong> " + description + "</p>";
36+
}
37+
</script>
38+
</body>
39+
</html>

app/src/main/java/com/immichframe/immichframe/Helpers.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ import android.graphics.Bitmap
55
import android.graphics.BitmapFactory
66
import android.graphics.Canvas
77
import android.graphics.Paint
8+
import android.net.ConnectivityManager
9+
import android.net.NetworkCapabilities
810
import android.util.Base64
11+
import android.widget.Toast
912
import retrofit2.Call
1013
import retrofit2.http.GET
1114
import androidx.core.graphics.scale
15+
import kotlinx.coroutines.delay
1216
import okhttp3.OkHttpClient
1317
import retrofit2.Retrofit
1418
import retrofit2.converter.gson.GsonConverterFactory
@@ -167,6 +171,7 @@ object Helpers {
167171
@GET("api/Weather")
168172
fun getWeather(): Call<Weather>
169173
}
174+
170175
fun createRetrofit(baseUrl: String, authSecret: String): Retrofit {
171176
val normalizedBaseUrl = if (!baseUrl.endsWith("/")) "$baseUrl/" else baseUrl
172177

@@ -193,4 +198,18 @@ object Helpers {
193198
.build()
194199
}
195200

201+
fun isNetworkAvailable(context: Context): Boolean {
202+
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
203+
val network = cm.activeNetwork
204+
val capabilities = cm.getNetworkCapabilities(network)
205+
return capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
206+
}
207+
208+
suspend fun waitForNetwork(context: Context) {
209+
while (!isNetworkAvailable(context)) {
210+
Toast.makeText(context, "Waiting for network...", Toast.LENGTH_SHORT)
211+
.show()
212+
delay(3000)
213+
}
214+
}
196215
}

app/src/main/java/com/immichframe/immichframe/MainActivity.kt

Lines changed: 63 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ import android.widget.TextView
3434
import android.widget.Toast
3535
import androidx.activity.result.contract.ActivityResultContracts
3636
import androidx.appcompat.app.AppCompatActivity
37+
import androidx.appcompat.app.AppCompatDelegate
3738
import androidx.core.view.WindowCompat
39+
import androidx.lifecycle.lifecycleScope
40+
import androidx.preference.PreferenceManager
3841
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
3942
import retrofit2.Call
4043
import retrofit2.Callback
@@ -103,14 +106,17 @@ class MainActivity : AppCompatActivity() {
103106
}
104107

105108
override fun onCreate(savedInstanceState: Bundle?) {
109+
//force dark mode
110+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
106111
super.onCreate(savedInstanceState)
107112

108113
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
109114
setContentView(R.layout.main_view)
110115
hideSystemUI()
111116

112117
webView = findViewById(R.id.webView)
113-
//webView.setBackgroundColor(Color.TRANSPARENT)
118+
webView.setBackgroundColor(Color.BLACK)
119+
webView.loadUrl("about:blank")
114120
imageView1 = findViewById(R.id.imageView1)
115121
imageView2 = findViewById(R.id.imageView2)
116122
txtPhotoInfo = findViewById(R.id.txtPhotoInfo)
@@ -125,6 +131,7 @@ class MainActivity : AppCompatActivity() {
125131
swipeRefreshLayout.isRefreshing = false
126132
settingsAction()
127133
}
134+
128135
btnPrevious.setOnClickListener {
129136
val toast = Toast.makeText(this, "Previous", Toast.LENGTH_SHORT)
130137
toast.setGravity(Gravity.CENTER_VERTICAL or Gravity.START, 0, 0)
@@ -148,21 +155,28 @@ class MainActivity : AppCompatActivity() {
148155

149156
rcpServer = RpcHttpServer(
150157
onDimCommand = { dim -> runOnUiThread { screenDim(dim) } },
151-
onNextCommand = { runOnUiThread {nextAction()} },
152-
onPreviousCommand = { runOnUiThread {previousAction()} },
153-
onPauseCommand = { runOnUiThread {pauseAction()} },
154-
onSettingsCommand = { runOnUiThread {settingsAction()} },
155-
onBrightnessCommand = { brightness -> runOnUiThread { screenBrightnessAction(brightness) }},
158+
onNextCommand = { runOnUiThread { nextAction() } },
159+
onPreviousCommand = { runOnUiThread { previousAction() } },
160+
onPauseCommand = { runOnUiThread { pauseAction() } },
161+
onSettingsCommand = { runOnUiThread { settingsAction() } },
162+
onBrightnessCommand = { brightness -> runOnUiThread { screenBrightnessAction(brightness) } },
156163
)
157164
rcpServer.start()
158165

159-
val savedUrl = getSharedPreferences("ImmichFramePrefs", MODE_PRIVATE).getString("webview_url", "") ?: ""
160-
if (savedUrl.isBlank()) {
161-
val intent = Intent(this, SettingsActivity::class.java)
162-
settingsLauncher.launch(intent)
163-
}
164-
else {
165-
loadSettings()
166+
//wait for network connection
167+
lifecycleScope.launch {
168+
if (!Helpers.isNetworkAvailable(this@MainActivity)) {
169+
Helpers.waitForNetwork(this@MainActivity)
170+
Toast.makeText(this@MainActivity, "Connected!", Toast.LENGTH_SHORT).show()
171+
}
172+
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
173+
val savedUrl = prefs.getString("webview_url", "") ?: ""
174+
if (savedUrl.isBlank()) {
175+
val intent = Intent(this@MainActivity, SettingsActivity::class.java)
176+
settingsLauncher.launch(intent)
177+
} else {
178+
loadSettings()
179+
}
166180
}
167181
}
168182

@@ -429,6 +443,9 @@ class MainActivity : AppCompatActivity() {
429443
var retryCount = 0
430444

431445
fun attemptFetch() {
446+
if (useWebView) {
447+
return
448+
}
432449
apiService.getServerSettings().enqueue(object : Callback<Helpers.ServerSettings> {
433450
override fun onResponse(
434451
call: Call<Helpers.ServerSettings>,
@@ -451,6 +468,9 @@ class MainActivity : AppCompatActivity() {
451468
}
452469

453470
private fun handleFailure(t: Throwable) {
471+
if (useWebView) {
472+
return
473+
}
454474
if (retryCount < maxRetries) {
455475
retryCount++
456476
Toast.makeText(
@@ -473,14 +493,14 @@ class MainActivity : AppCompatActivity() {
473493

474494
@SuppressLint("SetJavaScriptEnabled")
475495
private fun loadSettings() {
476-
val sharedPreferences = getSharedPreferences("ImmichFramePrefs", MODE_PRIVATE)
477-
blurredBackground = sharedPreferences.getBoolean("blurredBackground", true)
478-
showCurrentDate = sharedPreferences.getBoolean("showCurrentDate", true)
479-
var savedUrl = sharedPreferences.getString("webview_url", "") ?: ""
480-
useWebView = sharedPreferences.getBoolean("useWebView", true)
481-
keepScreenOn = sharedPreferences.getBoolean("keepScreenOn", true)
482-
val authSecret = sharedPreferences.getString("authSecret", "") ?: ""
483-
val screenDim = sharedPreferences.getBoolean("screenDim", false)
496+
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
497+
blurredBackground = prefs.getBoolean("blurredBackground", true)
498+
showCurrentDate = prefs.getBoolean("showCurrentDate", true)
499+
var savedUrl = prefs.getString("webview_url", "") ?: ""
500+
useWebView = prefs.getBoolean("useWebView", true)
501+
keepScreenOn = prefs.getBoolean("keepScreenOn", true)
502+
val authSecret = prefs.getString("authSecret", "") ?: ""
503+
val screenDim = prefs.getBoolean("screenDim", false)
484504

485505
webView.visibility = if (useWebView) View.VISIBLE else View.GONE
486506
imageView1.visibility = if (useWebView) View.GONE else View.VISIBLE
@@ -515,8 +535,6 @@ class MainActivity : AppCompatActivity() {
515535
} else {
516536
savedUrl
517537
}
518-
519-
//handler.removeCallbacksAndMessages(null)
520538
handler.removeCallbacks(imageRunnable)
521539
handler.removeCallbacks(weatherRunnable)
522540

@@ -541,9 +559,19 @@ class MainActivity : AppCompatActivity() {
541559
error: WebResourceError?
542560
) {
543561
super.onReceivedError(view, request, error)
562+
563+
if (request?.isForMainFrame == true && error != null) {
564+
view?.loadUrl("file:///android_asset/error_page.html")
565+
566+
Handler(Looper.getMainLooper()).postDelayed({
567+
val errorCode = error.errorCode
568+
val errorDescription = error.description.toString().replace("'", "\\'")
569+
view?.evaluateJavascript("showError('$errorCode', '$errorDescription')", null)
570+
}, 500)
571+
}
544572
Handler(Looper.getMainLooper()).postDelayed({
545-
view?.reload()
546-
}, 3000)
573+
webView.loadUrl(savedUrl)
574+
}, 5000)
547575
}
548576
}
549577
webView.settings.javaScriptEnabled = true
@@ -567,15 +595,13 @@ class MainActivity : AppCompatActivity() {
567595
}
568596
)
569597
}
570-
571598
}
572599

573600
private fun onSettingsLoaded() {
574-
if (serverSettings.imageFill){
601+
if (serverSettings.imageFill) {
575602
imageView1.scaleType = ImageView.ScaleType.CENTER_CROP
576603
imageView2.scaleType = ImageView.ScaleType.CENTER_CROP
577-
}
578-
else{
604+
} else {
579605
imageView1.scaleType = ImageView.ScaleType.FIT_CENTER
580606
imageView2.scaleType = ImageView.ScaleType.FIT_CENTER
581607
}
@@ -613,14 +639,13 @@ class MainActivity : AppCompatActivity() {
613639
}
614640
}
615641

616-
private fun previousAction(){
642+
private fun previousAction() {
617643
if (useWebView) {
618644
// Simulate a key press
619645
webView.requestFocus()
620646
val event = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT)
621647
dispatchKeyEvent(event)
622-
}
623-
else {
648+
} else {
624649
val safePreviousImage = previousImage
625650
if (safePreviousImage != null) {
626651
stopImageTimer()
@@ -630,14 +655,13 @@ class MainActivity : AppCompatActivity() {
630655
}
631656
}
632657

633-
private fun nextAction(){
658+
private fun nextAction() {
634659
if (useWebView) {
635660
// Simulate a key press
636661
webView.requestFocus()
637662
val event = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT)
638663
dispatchKeyEvent(event)
639-
}
640-
else {
664+
} else {
641665
stopImageTimer()
642666
getNextImage()
643667
startImageTimer()
@@ -698,7 +722,7 @@ class MainActivity : AppCompatActivity() {
698722
return true
699723
}
700724

701-
KeyEvent.KEYCODE_SPACE ->{
725+
KeyEvent.KEYCODE_SPACE -> {
702726
pauseAction()
703727
return true
704728
}
@@ -741,10 +765,9 @@ class MainActivity : AppCompatActivity() {
741765
dimOverlay.apply {
742766
visibility = View.VISIBLE
743767
alpha = 0f
744-
if(useWebView){
768+
if (useWebView) {
745769
webView.loadUrl("about:blank")
746-
}
747-
else {
770+
} else {
748771
stopImageTimer()
749772
stopWeatherTimer()
750773
}
@@ -771,7 +794,7 @@ class MainActivity : AppCompatActivity() {
771794
}
772795

773796
private fun checkDimTime() {
774-
val prefs = getSharedPreferences("ImmichFramePrefs", MODE_PRIVATE)
797+
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
775798
val startHour = prefs.getInt("dimStartHour", 22)
776799
val startMinute = prefs.getInt("dimStartMinute", 0)
777800
val endHour = prefs.getInt("dimEndHour", 6)

0 commit comments

Comments
 (0)