Loading app/build.gradle +7 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ android { defaultConfig { applicationId "io.heckel.ntfy" minSdkVersion 21 minSdkVersion 23 targetSdkVersion 33 versionCode 33 Loading @@ -27,6 +27,10 @@ android { } } buildFeatures { viewBinding = true } buildTypes { release { minifyEnabled true Loading Loading @@ -128,4 +132,6 @@ dependencies { // Image viewer implementation 'com.github.stfalcon-studio:StfalconImageViewer:v1.0.1' implementation 'foundation.e:elib:0.0.1-alpha11' } app/src/main/AndroidManifest.xml +27 −3 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="io.heckel.ntfy"> <!-- Permissions --> Loading @@ -25,6 +26,7 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:persistent="true" android:roundIcon="@mipmap/ic_launcher" android:supportsRtl="true" android:theme="@style/AppTheme" Loading @@ -35,10 +37,10 @@ <activity android:name=".ui.MainActivity" android:label="@string/app_name" android:excludeFromRecents="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> Loading Loading @@ -175,5 +177,27 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider> <activity android:name=".ui.MainSettingsActivity" android:theme="@style/PreferenceTheme" android:process=":ui"/> <activity-alias android:name=".ui.SettingsActivityLink" android:exported="true" android:label="@string/eos_settings_title" android:process=":ui" android:targetActivity=".ui.MainSettingsActivity"> <intent-filter> <action android:name="com.android.settings.action.EXTRA_SETTINGS" /> </intent-filter> <meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.device" /> <meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_notification" /> </activity-alias> </application> </manifest> app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt +6 −13 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ import android.os.PowerManager import android.os.SystemClock import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.preference.PreferenceManager import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.R import io.heckel.ntfy.app.Application Loading Loading @@ -88,23 +89,16 @@ class SubscriberService : Service() { Log.init(this) // Init logs in all entry points Log.d(TAG, "Subscriber service has been created") val title = getString(R.string.channel_subscriber_notification_title) val text = if (BuildConfig.FIREBASE_AVAILABLE) { getString(R.string.channel_subscriber_notification_instant_text) } else { getString(R.string.channel_subscriber_notification_noinstant_text) } notificationManager = createNotificationChannel() serviceNotification = createNotification(title, text) startForeground(NOTIFICATION_SERVICE_ID, serviceNotification) } override fun onDestroy() { Log.d(TAG, "Subscriber service has been destroyed") stopService() sendBroadcast(Intent(this, AutoRestartReceiver::class.java)) // Restart it if necessary! val preferenceKey = getString(R.string.eos_preference_key_is_enabled) if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(preferenceKey, false)) { sendBroadcast(Intent(this, AutoRestartReceiver::class.java)) } super.onDestroy() } Loading Loading @@ -138,7 +132,6 @@ class SubscriberService : Service() { } } wakeLock = null stopForeground(true) stopSelf() } catch (e: Exception) { Log.d(TAG, "Service stopped without being started: ${e.message}") Loading app/src/main/java/io/heckel/ntfy/service/SubscriberServiceManager.kt +12 −5 Original line number Diff line number Diff line Loading @@ -2,10 +2,11 @@ package io.heckel.ntfy.service import android.content.Context import android.content.Intent import androidx.core.content.ContextCompat import androidx.preference.PreferenceManager import androidx.work.* import io.heckel.ntfy.app.Application import io.heckel.ntfy.util.Log import io.heckel.ntfy.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext Loading Loading @@ -43,11 +44,17 @@ class SubscriberServiceManager(private val context: Context) { Log.d(TAG, "ServiceStartWorker: Failed, no application found (work ID: ${id})") return Result.failure() } withContext(Dispatchers.IO) { val app = context.applicationContext as Application val subscriptionIdsWithInstantStatus = app.repository.getSubscriptionIdsWithInstantStatus() val instantSubscriptions = subscriptionIdsWithInstantStatus.toList().filter { (_, instant) -> instant }.size val action = if (instantSubscriptions > 0) SubscriberService.Action.START else SubscriberService.Action.STOP val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(app) val preferenceKey = context.getString(R.string.eos_preference_key_is_enabled) val action = if (sharedPreferences.getBoolean(preferenceKey, false)) { SubscriberService.Action.START } else { SubscriberService.Action.STOP } val serviceState = SubscriberService.readServiceState(context) if (serviceState == SubscriberService.ServiceState.STOPPED && action == SubscriberService.Action.STOP) { return@withContext Result.success() Loading @@ -55,7 +62,7 @@ class SubscriberServiceManager(private val context: Context) { Log.d(TAG, "ServiceStartWorker: Starting foreground service with action $action (work ID: ${id})") Intent(context, SubscriberService::class.java).also { it.action = action.name ContextCompat.startForegroundService(context, it) context.startService(it) } } return Result.success() Loading app/src/main/java/io/heckel/ntfy/ui/MainSettingsActivity.kt 0 → 100644 +71 −0 Original line number Diff line number Diff line package io.heckel.ntfy.ui import android.content.res.Configuration import android.os.Build import android.os.Bundle import android.view.WindowInsetsController import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import io.heckel.ntfy.R import io.heckel.ntfy.databinding.MainSettingsActivityBinding class MainSettingsActivity : AppCompatActivity() { private lateinit var mBinding: MainSettingsActivityBinding @RequiresApi(Build.VERSION_CODES.R) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = MainSettingsActivityBinding.inflate(layoutInflater) setContentView(mBinding.root) setupToolbar() setSystemBarsAppearance() showPreferencesFragment() } private fun setupToolbar() { mBinding.toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } } @RequiresApi(Build.VERSION_CODES.R) private fun setSystemBarsAppearance() { val insetsController = window.insetsController ?: return val isLightMode = isSystemInLightMode() if (isLightMode) { insetsController.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS ) insetsController.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS ) } else { insetsController.setSystemBarsAppearance( 0, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS ) insetsController.setSystemBarsAppearance( 0, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS ) } } private fun isSystemInLightMode(): Boolean { val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK return nightModeFlags != Configuration.UI_MODE_NIGHT_YES } private fun showPreferencesFragment() { supportFragmentManager .beginTransaction() .replace(R.id.fragment_container, PreferencesFragment()) .commit() } } No newline at end of file Loading
app/build.gradle +7 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ android { defaultConfig { applicationId "io.heckel.ntfy" minSdkVersion 21 minSdkVersion 23 targetSdkVersion 33 versionCode 33 Loading @@ -27,6 +27,10 @@ android { } } buildFeatures { viewBinding = true } buildTypes { release { minifyEnabled true Loading Loading @@ -128,4 +132,6 @@ dependencies { // Image viewer implementation 'com.github.stfalcon-studio:StfalconImageViewer:v1.0.1' implementation 'foundation.e:elib:0.0.1-alpha11' }
app/src/main/AndroidManifest.xml +27 −3 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="io.heckel.ntfy"> <!-- Permissions --> Loading @@ -25,6 +26,7 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:persistent="true" android:roundIcon="@mipmap/ic_launcher" android:supportsRtl="true" android:theme="@style/AppTheme" Loading @@ -35,10 +37,10 @@ <activity android:name=".ui.MainActivity" android:label="@string/app_name" android:excludeFromRecents="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> Loading Loading @@ -175,5 +177,27 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider> <activity android:name=".ui.MainSettingsActivity" android:theme="@style/PreferenceTheme" android:process=":ui"/> <activity-alias android:name=".ui.SettingsActivityLink" android:exported="true" android:label="@string/eos_settings_title" android:process=":ui" android:targetActivity=".ui.MainSettingsActivity"> <intent-filter> <action android:name="com.android.settings.action.EXTRA_SETTINGS" /> </intent-filter> <meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.device" /> <meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_notification" /> </activity-alias> </application> </manifest>
app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt +6 −13 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ import android.os.PowerManager import android.os.SystemClock import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.preference.PreferenceManager import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.R import io.heckel.ntfy.app.Application Loading Loading @@ -88,23 +89,16 @@ class SubscriberService : Service() { Log.init(this) // Init logs in all entry points Log.d(TAG, "Subscriber service has been created") val title = getString(R.string.channel_subscriber_notification_title) val text = if (BuildConfig.FIREBASE_AVAILABLE) { getString(R.string.channel_subscriber_notification_instant_text) } else { getString(R.string.channel_subscriber_notification_noinstant_text) } notificationManager = createNotificationChannel() serviceNotification = createNotification(title, text) startForeground(NOTIFICATION_SERVICE_ID, serviceNotification) } override fun onDestroy() { Log.d(TAG, "Subscriber service has been destroyed") stopService() sendBroadcast(Intent(this, AutoRestartReceiver::class.java)) // Restart it if necessary! val preferenceKey = getString(R.string.eos_preference_key_is_enabled) if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(preferenceKey, false)) { sendBroadcast(Intent(this, AutoRestartReceiver::class.java)) } super.onDestroy() } Loading Loading @@ -138,7 +132,6 @@ class SubscriberService : Service() { } } wakeLock = null stopForeground(true) stopSelf() } catch (e: Exception) { Log.d(TAG, "Service stopped without being started: ${e.message}") Loading
app/src/main/java/io/heckel/ntfy/service/SubscriberServiceManager.kt +12 −5 Original line number Diff line number Diff line Loading @@ -2,10 +2,11 @@ package io.heckel.ntfy.service import android.content.Context import android.content.Intent import androidx.core.content.ContextCompat import androidx.preference.PreferenceManager import androidx.work.* import io.heckel.ntfy.app.Application import io.heckel.ntfy.util.Log import io.heckel.ntfy.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext Loading Loading @@ -43,11 +44,17 @@ class SubscriberServiceManager(private val context: Context) { Log.d(TAG, "ServiceStartWorker: Failed, no application found (work ID: ${id})") return Result.failure() } withContext(Dispatchers.IO) { val app = context.applicationContext as Application val subscriptionIdsWithInstantStatus = app.repository.getSubscriptionIdsWithInstantStatus() val instantSubscriptions = subscriptionIdsWithInstantStatus.toList().filter { (_, instant) -> instant }.size val action = if (instantSubscriptions > 0) SubscriberService.Action.START else SubscriberService.Action.STOP val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(app) val preferenceKey = context.getString(R.string.eos_preference_key_is_enabled) val action = if (sharedPreferences.getBoolean(preferenceKey, false)) { SubscriberService.Action.START } else { SubscriberService.Action.STOP } val serviceState = SubscriberService.readServiceState(context) if (serviceState == SubscriberService.ServiceState.STOPPED && action == SubscriberService.Action.STOP) { return@withContext Result.success() Loading @@ -55,7 +62,7 @@ class SubscriberServiceManager(private val context: Context) { Log.d(TAG, "ServiceStartWorker: Starting foreground service with action $action (work ID: ${id})") Intent(context, SubscriberService::class.java).also { it.action = action.name ContextCompat.startForegroundService(context, it) context.startService(it) } } return Result.success() Loading
app/src/main/java/io/heckel/ntfy/ui/MainSettingsActivity.kt 0 → 100644 +71 −0 Original line number Diff line number Diff line package io.heckel.ntfy.ui import android.content.res.Configuration import android.os.Build import android.os.Bundle import android.view.WindowInsetsController import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import io.heckel.ntfy.R import io.heckel.ntfy.databinding.MainSettingsActivityBinding class MainSettingsActivity : AppCompatActivity() { private lateinit var mBinding: MainSettingsActivityBinding @RequiresApi(Build.VERSION_CODES.R) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = MainSettingsActivityBinding.inflate(layoutInflater) setContentView(mBinding.root) setupToolbar() setSystemBarsAppearance() showPreferencesFragment() } private fun setupToolbar() { mBinding.toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } } @RequiresApi(Build.VERSION_CODES.R) private fun setSystemBarsAppearance() { val insetsController = window.insetsController ?: return val isLightMode = isSystemInLightMode() if (isLightMode) { insetsController.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS ) insetsController.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS ) } else { insetsController.setSystemBarsAppearance( 0, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS ) insetsController.setSystemBarsAppearance( 0, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS ) } } private fun isSystemInLightMode(): Boolean { val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK return nightModeFlags != Configuration.UI_MODE_NIGHT_YES } private fun showPreferencesFragment() { supportFragmentManager .beginTransaction() .replace(R.id.fragment_container, PreferencesFragment()) .commit() } } No newline at end of file