diff --git a/.editorconfig b/.editorconfig index 1b8d08e..3f25798 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,2 @@ [*.{kt,kts}] -ktlint_code_style = android \ No newline at end of file +ktlint_code_style = android_studio \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index c40f793..bbc090d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,16 +1,16 @@ plugins { id 'com.android.application' id 'kotlin-android' - id 'org.jmailen.kotlinter' version '3.15.0' + id 'org.jmailen.kotlinter' version '4.0.0' } android { namespace "com.github.gotify" - compileSdk 33 + compileSdk 34 defaultConfig { applicationId "com.github.gotify" minSdk 23 - targetSdk 33 + targetSdk 34 versionCode 30 versionName "2.7.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -68,13 +68,13 @@ dependencies { implementation project(':client') implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.core:core-splashscreen:1.0.1' - implementation 'com.google.android.material:material:1.9.0' + implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.vectordrawable:vectordrawable:1.1.0' - implementation 'androidx.preference:preference-ktx:1.2.0' + implementation 'androidx.preference:preference-ktx:1.2.1' - implementation 'com.github.cyb3rko:QuickPermissions-Kotlin:1.1.2' + implementation 'com.github.cyb3rko:QuickPermissions-Kotlin:1.1.3' implementation 'com.squareup.picasso:picasso:2.71828' implementation 'io.noties.markwon:core:4.6.2' implementation 'io.noties.markwon:image-picasso:4.6.2' @@ -87,7 +87,7 @@ dependencies { } configurations { - all { + configureEach { exclude group: 'org.json', module: 'json' exclude group: 'androidx.lifecycle', module: 'lifecycle-viewmodel-ktx' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ff4af56..07465df 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,6 +10,7 @@ + - + + + diff --git a/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt b/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt index c9f5800..77cc0b1 100644 --- a/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt +++ b/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt @@ -51,10 +51,7 @@ internal object NotificationSupport { } @RequiresApi(Build.VERSION_CODES.O) - private fun createGeneralChannels( - context: Context, - notificationManager: NotificationManager - ) { + private fun createGeneralChannels(context: Context, notificationManager: NotificationManager) { try { val messagesImportanceMin = NotificationChannel( Channel.MESSAGES_IMPORTANCE_MIN, @@ -98,11 +95,7 @@ internal object NotificationSupport { } @RequiresApi(api = Build.VERSION_CODES.O) - fun createChannelIfNonexistent( - context: Context, - groupId: String, - channelId: String - ) { + fun createChannelIfNonexistent(context: Context, groupId: String, channelId: String) { if (!doesNotificationChannelExist(context, channelId)) { val notificationManager = (context as Service) .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager diff --git a/app/src/main/kotlin/com/github/gotify/api/ClientFactory.kt b/app/src/main/kotlin/com/github/gotify/api/ClientFactory.kt index 7a837d2..1edf4e0 100644 --- a/app/src/main/kotlin/com/github/gotify/api/ClientFactory.kt +++ b/app/src/main/kotlin/com/github/gotify/api/ClientFactory.kt @@ -30,11 +30,7 @@ internal object ClientFactory { return client } - fun clientToken( - baseUrl: String, - sslSettings: SSLSettings, - token: String? - ): ApiClient { + fun clientToken(baseUrl: String, sslSettings: SSLSettings, token: String?): ApiClient { val client = defaultClient( arrayOf("clientTokenHeader"), "$baseUrl/", diff --git a/app/src/main/kotlin/com/github/gotify/messages/Extras.kt b/app/src/main/kotlin/com/github/gotify/messages/Extras.kt index 39a01d9..68086fc 100644 --- a/app/src/main/kotlin/com/github/gotify/messages/Extras.kt +++ b/app/src/main/kotlin/com/github/gotify/messages/Extras.kt @@ -18,11 +18,7 @@ internal object Extras { return "text/markdown" == display["contentType"] } - fun getNestedValue( - clazz: Class, - extras: Map?, - vararg keys: String - ): T? { + fun getNestedValue(clazz: Class, extras: Map?, vararg keys: String): T? { var value: Any? = extras keys.forEach { key -> diff --git a/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt b/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt index 7ea5933..f2f95f8 100644 --- a/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt @@ -9,6 +9,7 @@ import android.graphics.Canvas import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.net.Uri +import android.os.Build import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -310,7 +311,11 @@ internal class MessagesActivity : nManager.cancelAll() val filter = IntentFilter() filter.addAction(WebSocketService.NEW_MESSAGE_BROADCAST) - registerReceiver(receiver, filter) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + registerReceiver(receiver, filter, RECEIVER_EXPORTED) + } else { + registerReceiver(receiver, filter) + } launchCoroutine { updateMissedMessages(viewModel.messages.getLastReceivedMessage()) } diff --git a/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt b/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt index 1084b23..119f99e 100644 --- a/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt +++ b/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt @@ -6,6 +6,7 @@ import android.app.NotificationManager import android.app.PendingIntent import android.app.Service import android.content.Intent +import android.content.pm.ServiceInfo import android.graphics.Color import android.net.ConnectivityManager import android.net.Network @@ -285,7 +286,15 @@ internal class WebSocketService : Service() { notificationBuilder.setContentIntent(pendingIntent) notificationBuilder.color = ContextCompat.getColor(applicationContext, R.color.colorPrimary) - startForeground(NotificationSupport.ID.FOREGROUND, notificationBuilder.build()) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + startForeground( + NotificationSupport.ID.FOREGROUND, + notificationBuilder.build(), + ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE + ) + } else { + startForeground(NotificationSupport.ID.FOREGROUND, notificationBuilder.build()) + } } private fun showNotification( diff --git a/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt b/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt index 26c4516..bd57861 100644 --- a/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt @@ -52,7 +52,8 @@ internal class SettingsActivity : AppCompatActivity(), OnSharedPreferenceChangeL return false } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + if (sharedPreferences == null) return when (key) { getString(R.string.setting_key_theme) -> { ThemeHelper.setTheme( diff --git a/build.gradle b/build.gradle index 70ea2df..530a4b2 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,8 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.0.2' - classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.20' + classpath 'com.android.tools.build:gradle:8.1.3' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -26,12 +26,12 @@ ext { allprojects { repositories { google() - jcenter() + mavenCentral() maven { url "https://jitpack.io/" } } } -task clean(type: Delete) { +tasks.register('clean', Delete) { delete rootProject.buildDir } @@ -45,7 +45,8 @@ static def download(String url, String filename ) { } } } -task downloadSpec { + +tasks.register('downloadSpec') { inputs.property 'version', gotifyVersion doFirst { buildDir.mkdirs() diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e583..7f93135 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e999d40..3fa8f86 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distrubutionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index f127cfd..93e3f59 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME%