diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 56120ebe..877c0e80 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -7,10 +7,10 @@ plugins {
}
android {
- namespace = "dev.meloda.fast"
+ namespace = "dev.meloda.fastvk"
defaultConfig {
- applicationId = "dev.meloda.fast"
+ applicationId = "dev.meloda.fastvk"
versionCode = libs.versions.versionCode.get().toInt()
versionName = libs.versions.versionName.get()
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d57ff13c..5a3a7bf3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
tools:targetApi="tiramisu">
@@ -38,13 +38,13 @@
diff --git a/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt b/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt
index 8670d011..be50f87b 100644
--- a/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt
+++ b/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt
@@ -86,6 +86,8 @@ class MainViewModelImpl(
BaseError.SessionExpired -> {
isNeedToReplaceWithAuth.update { true }
}
+
+ is BaseError.SimpleError -> Unit // TODO: 21-Mar-25, Danil Nikolaev: show error in ui
}
}
diff --git a/app/src/main/kotlin/dev/meloda/fast/service/OnlineService.kt b/app/src/main/kotlin/dev/meloda/fast/service/OnlineService.kt
index 98556cae..354a1de4 100644
--- a/app/src/main/kotlin/dev/meloda/fast/service/OnlineService.kt
+++ b/app/src/main/kotlin/dev/meloda/fast/service/OnlineService.kt
@@ -95,11 +95,6 @@ class OnlineService : Service() {
}.also { coroutine -> coroutine.invokeOnCompletion { onlineJob = null } }
}
- override fun onLowMemory() {
- Log.d(STATE_TAG, "onLowMemory")
- super.onLowMemory()
- }
-
override fun onDestroy() {
Log.d(STATE_TAG, "onDestroy")
diff --git a/core/common/src/main/kotlin/dev/meloda/fast/common/util/AndroidUtils.kt b/core/common/src/main/kotlin/dev/meloda/fast/common/util/AndroidUtils.kt
index 0f684a77..c88f3019 100644
--- a/core/common/src/main/kotlin/dev/meloda/fast/common/util/AndroidUtils.kt
+++ b/core/common/src/main/kotlin/dev/meloda/fast/common/util/AndroidUtils.kt
@@ -86,7 +86,7 @@ object AndroidUtils {
action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
Settings.ACTION_SECURITY_SETTINGS
} else {
- data = Uri.parse("package:dev.meloda.fast")
+ data = Uri.parse("package:dev.meloda.fastvk")
Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES
}
})
diff --git a/core/model/src/main/kotlin/dev/meloda/fast/model/BaseError.kt b/core/model/src/main/kotlin/dev/meloda/fast/model/BaseError.kt
index b2a8cb64..86cc6e2f 100644
--- a/core/model/src/main/kotlin/dev/meloda/fast/model/BaseError.kt
+++ b/core/model/src/main/kotlin/dev/meloda/fast/model/BaseError.kt
@@ -6,4 +6,6 @@ import androidx.compose.runtime.Immutable
sealed class BaseError {
data object SessionExpired : BaseError()
+
+ data class SimpleError(val message: String) : BaseError()
}
diff --git a/core/model/src/main/kotlin/dev/meloda/fast/model/api/data/VkVideoData.kt b/core/model/src/main/kotlin/dev/meloda/fast/model/api/data/VkVideoData.kt
index 8e9f3d5d..01bbfa3b 100644
--- a/core/model/src/main/kotlin/dev/meloda/fast/model/api/data/VkVideoData.kt
+++ b/core/model/src/main/kotlin/dev/meloda/fast/model/api/data/VkVideoData.kt
@@ -1,7 +1,7 @@
package dev.meloda.fast.model.api.data
-import dev.meloda.fast.model.api.domain.VkVideoDomain
import com.squareup.moshi.JsonClass
+import dev.meloda.fast.model.api.domain.VkVideoDomain
@JsonClass(generateAdapter = true)
data class VkVideoData(
@@ -12,7 +12,7 @@ data class VkVideoData(
val duration: Int,
val date: Int,
val comments: Int?,
- val description: String,
+ val description: String?,
val player: String?,
val added: Int?,
val type: String,
@@ -20,9 +20,9 @@ data class VkVideoData(
val access_key: String?,
val owner_id: Int,
val is_favorite: Boolean?,
- val image: List,
+ val image: List?,
val first_frame: List?,
- val files: File?,
+ val files: File?
) : VkAttachmentData {
@JsonClass(generateAdapter = true)
@@ -67,7 +67,7 @@ data class VkVideoData(
fun toDomain() = VkVideoDomain(
id = id,
ownerId = owner_id,
- images = image.map { it.asVideoImage() },
+ images = image.orEmpty().map { it.asVideoImage() },
firstFrames = first_frame,
accessKey = access_key,
title = title
diff --git a/core/network/src/main/kotlin/dev/meloda/fast/network/ResponseConverterFactory.kt b/core/network/src/main/kotlin/dev/meloda/fast/network/ResponseConverterFactory.kt
index d4af413e..3168077d 100644
--- a/core/network/src/main/kotlin/dev/meloda/fast/network/ResponseConverterFactory.kt
+++ b/core/network/src/main/kotlin/dev/meloda/fast/network/ResponseConverterFactory.kt
@@ -46,8 +46,13 @@ class ResponseConverterFactory(private val converter: JsonConverter) : Converter
return successModel
},
onFailure = { failure ->
- if(failure is JsonDataException) {
- throw failure
+ if (failure is JsonDataException) {
+ throw ApiException(
+ RestApiError(
+ errorCode = -1,
+ errorMsg = failure.message.orEmpty()
+ )
+ )
}
val isUnit = successType == Unit::class.java
diff --git a/core/network/src/main/kotlin/dev/meloda/fast/network/VkErrorCode.kt b/core/network/src/main/kotlin/dev/meloda/fast/network/VkErrorCode.kt
index 42aaae91..b15d2734 100644
--- a/core/network/src/main/kotlin/dev/meloda/fast/network/VkErrorCode.kt
+++ b/core/network/src/main/kotlin/dev/meloda/fast/network/VkErrorCode.kt
@@ -1,6 +1,7 @@
package dev.meloda.fast.network
enum class VkErrorCode(val code: Int) {
+ WTF(-1),
UNKNOWN_ERROR(1),
APP_DISABLED(2),
UNKNOWN_METHOD(3),
diff --git a/core/network/src/main/kotlin/dev/meloda/fast/network/di/NetworkModule.kt b/core/network/src/main/kotlin/dev/meloda/fast/network/di/NetworkModule.kt
index cb608c13..936671dc 100644
--- a/core/network/src/main/kotlin/dev/meloda/fast/network/di/NetworkModule.kt
+++ b/core/network/src/main/kotlin/dev/meloda/fast/network/di/NetworkModule.kt
@@ -6,7 +6,6 @@ import com.slack.eithernet.integration.retrofit.ApiResultCallAdapterFactory
import com.slack.eithernet.integration.retrofit.ApiResultConverterFactory
import com.squareup.moshi.Moshi
import dev.meloda.fast.common.AppConstants
-import dev.meloda.fast.common.model.LogLevel
import dev.meloda.fast.datastore.AppSettings
import dev.meloda.fast.network.JsonConverter
import dev.meloda.fast.network.MoshiConverter
@@ -57,12 +56,8 @@ val networkModule = module {
.followSslRedirects(true)
.addInterceptor(
HttpLoggingInterceptor().apply {
- level = when (AppSettings.Debug.networkLogLevel) {
- LogLevel.NONE -> HttpLoggingInterceptor.Level.NONE
- LogLevel.BASIC -> HttpLoggingInterceptor.Level.BASIC
- LogLevel.HEADERS -> HttpLoggingInterceptor.Level.HEADERS
- LogLevel.BODY -> HttpLoggingInterceptor.Level.BODY
- }
+ level =
+ HttpLoggingInterceptor.Level.entries[AppSettings.Debug.networkLogLevel.ordinal]
}
)
.build()
diff --git a/core/ui/src/main/kotlin/dev/meloda/fast/ui/components/ErrorView.kt b/core/ui/src/main/kotlin/dev/meloda/fast/ui/components/ErrorView.kt
index 1d43f793..32b3db31 100644
--- a/core/ui/src/main/kotlin/dev/meloda/fast/ui/components/ErrorView.kt
+++ b/core/ui/src/main/kotlin/dev/meloda/fast/ui/components/ErrorView.kt
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -22,7 +23,9 @@ fun ErrorView(
onButtonClick: (() -> Unit)? = null,
) {
Column(
- modifier = modifier.fillMaxSize(),
+ modifier = modifier
+ .fillMaxSize()
+ .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
diff --git a/core/ui/src/main/res/values-ru/strings.xml b/core/ui/src/main/res/values-ru/strings.xml
index b099304a..ec25a7be 100644
--- a/core/ui/src/main/res/values-ru/strings.xml
+++ b/core/ui/src/main/res/values-ru/strings.xml
@@ -133,6 +133,7 @@
Ваша история
Динамические цвета
Цвета для приложения будут извлечены из ваших обоев на главном экране
+ Использовать системный шрифт
Язык приложения
Текущий: %1$s
Системный
@@ -177,6 +178,7 @@
Основное
Использовать имена контактов
Приложение будет использовать доступные имена контактов для пользователей
+ Включить тактильную отдачу
Внешний вид
Многострочные заголовки и сообщения
Заголовок чата и текст сообщения смогут занимать несколько строчек
@@ -184,9 +186,11 @@
Fast текст
LongPoll в фоне
Ваши сообщения будут обновляться, даже если приложение находится в фоне
+ Использовать анимации везде, где возможно
Активность
Быть «в сети»
Статус «в сети» будет отправляться каждые 5 минут
+ Экспериментальные - ОЧЕНЬ нестабильные
Отладка
Отключить
Приложение не сможет обновлять сообщения в фоне без доступа к уведомлениям
@@ -198,4 +202,14 @@
Уведомления без категории
Сервис обновления сообщений
Уведомления сервиса обновлений сообщений
+ Показывать кнопку эмоджи
+ Показывать кнопку эмоджи на панели чата
+ Показывать время в сервисных сообщениях
+ Использовать размытие
+ Добавлять размытие везде, где возможно.\\nРаботает только с 12 версии Android
+ Больше анимаций
+ Подтверждение
+ Вы уверены? Процесс ввода капчи будет отменён
+ Вы уверены? Процесс ввода кода-подтверждения будет отменён
+ Авторизоваться
diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml
index a1cbf61e..d5a48e61 100644
--- a/core/ui/src/main/res/values/strings.xml
+++ b/core/ui/src/main/res/values/strings.xml
@@ -204,6 +204,8 @@
Dynamic colors
The colors for the app will be extracted from your home screen wallpaper
+ Use system font
+
Application Language
Current: %1$s
@@ -235,6 +237,9 @@
General
Use contact names
App will use available contact names for users
+ Show emoji button
+ Show emoji button in chat panel
+ Enable haptic
Appearance
Multiline titles and messages
The title of the conversation and the text of the message can take up multiple lines
@@ -242,9 +247,18 @@
Fast text
LongPoll in background
Your messages will be updating even when app is not on the screen
+ Show time in action messages
+ Use blur
+ Adds blur wherever possible.\nWorks on android 12 and newer
+ More animations
+ Use animations wherever possible
+
Activity
Send online status
Online status will be sent every five minutes
+
+ Experimental - VERY unstable
+
Debug
The app won\'t be able to update messages in the background without access to notifications
Disable
diff --git a/feature/chatmaterials/src/main/kotlin/dev/meloda/fast/chatmaterials/presentation/ChatMaterialsScreen.kt b/feature/chatmaterials/src/main/kotlin/dev/meloda/fast/chatmaterials/presentation/ChatMaterialsScreen.kt
index bc73daef..f7acddf4 100644
--- a/feature/chatmaterials/src/main/kotlin/dev/meloda/fast/chatmaterials/presentation/ChatMaterialsScreen.kt
+++ b/feature/chatmaterials/src/main/kotlin/dev/meloda/fast/chatmaterials/presentation/ChatMaterialsScreen.kt
@@ -62,8 +62,8 @@ import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import dev.chrisbanes.haze.HazeState
-import dev.chrisbanes.haze.haze
-import dev.chrisbanes.haze.hazeChild
+import dev.chrisbanes.haze.hazeEffect
+import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import dev.chrisbanes.haze.materials.HazeMaterials
import dev.meloda.fast.chatmaterials.ChatMaterialsViewModel
@@ -137,7 +137,7 @@ fun ChatMaterialsScreen(
)
}
- val titles = listOf("Photos", "Videos", "Audios", "Files", "Links")
+ val titles = listOf("Photos", "Videos", "Audios")//, "Files", "Links")
val listState = rememberLazyListState()
val gridState = rememberLazyGridState()
@@ -179,7 +179,7 @@ fun ChatMaterialsScreen(
modifier = Modifier
.then(
if (currentTheme.enableBlur) {
- Modifier.hazeChild(
+ Modifier.hazeEffect(
state = hazeState,
style = hazeStyle
)
@@ -311,7 +311,7 @@ fun ChatMaterialsScreen(
modifier = Modifier
.then(
if (currentTheme.enableBlur) {
- Modifier.haze(state = hazeState)
+ Modifier.hazeSource(state = hazeState)
} else {
Modifier
}
@@ -346,7 +346,7 @@ fun ChatMaterialsScreen(
modifier = Modifier
.then(
if (currentTheme.enableBlur) {
- Modifier.haze(state = hazeState)
+ Modifier.hazeSource(state = hazeState)
} else {
Modifier
}
diff --git a/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/ConversationsViewModel.kt b/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/ConversationsViewModel.kt
index 35a4fad3..5806134d 100644
--- a/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/ConversationsViewModel.kt
+++ b/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/ConversationsViewModel.kt
@@ -134,6 +134,7 @@ class ConversationsViewModelImpl(
}
override fun onRefresh() {
+ baseError.setValue { null }
loadConversations(offset = 0)
}
@@ -273,17 +274,7 @@ class ConversationsViewModelImpl(
conversationsUseCase.getConversations(count = LOAD_COUNT, offset = offset)
.listenValue(viewModelScope) { state ->
state.processState(
- error = { error ->
- if (error is State.Error.ApiError) {
- when (error.errorCode) {
- VkErrorCode.USER_AUTHORIZATION_FAILED -> {
- baseError.setValue { BaseError.SessionExpired }
- }
-
- else -> Unit
- }
- }
- },
+ error = ::handleError,
success = { response ->
val itemsCountSufficient = response.size == LOAD_COUNT
canPaginate.setValue { itemsCountSufficient }
@@ -339,6 +330,40 @@ class ConversationsViewModelImpl(
}
}
+ private fun handleError(error: State.Error) {
+ when (error) {
+ is State.Error.ApiError -> {
+ when (error.errorCode) {
+ VkErrorCode.USER_AUTHORIZATION_FAILED -> {
+ baseError.setValue { BaseError.SessionExpired }
+ }
+
+ else -> {
+ baseError.setValue {
+ BaseError.SimpleError(message = error.errorMessage)
+ }
+ }
+ }
+ }
+ State.Error.ConnectionError -> {
+ baseError.setValue {
+ BaseError.SimpleError(message = "Connection error")
+ }
+ }
+ State.Error.InternalError -> {
+ baseError.setValue {
+ BaseError.SimpleError(message = "Internal error")
+ }
+ }
+ State.Error.UnknownError -> {
+ baseError.setValue {
+ BaseError.SimpleError(message = "Unknown error")
+ }
+ }
+ else -> Unit
+ }
+ }
+
private fun deleteConversation(peerId: Int) {
conversationsUseCase.delete(peerId).listenValue(viewModelScope) { state ->
state.processState(
diff --git a/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt b/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt
index cf19746b..e7c42f1a 100644
--- a/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt
+++ b/feature/conversations/src/main/kotlin/dev/meloda/fast/conversations/presentation/ConversationsScreen.kt
@@ -339,12 +339,24 @@ fun ConversationsScreen(
}
) { padding ->
when {
- baseError is BaseError.SessionExpired -> {
- ErrorView(
- text = "Session expired",
- buttonText = "Log out",
- onButtonClick = onSessionExpiredLogOutButtonClicked
- )
+ baseError != null -> {
+ when (baseError) {
+ is BaseError.SessionExpired -> {
+ ErrorView(
+ text = "Session expired",
+ buttonText = "Log out",
+ onButtonClick = onSessionExpiredLogOutButtonClicked
+ )
+ }
+
+ is BaseError.SimpleError -> {
+ ErrorView(
+ text = baseError.message,
+ buttonText = "Try again",
+ onButtonClick = onRefresh
+ )
+ }
+ }
}
screenState.isLoading && screenState.conversations.isEmpty() -> FullScreenLoader()
diff --git a/feature/settings/src/main/kotlin/dev/meloda/fast/settings/SettingsViewModel.kt b/feature/settings/src/main/kotlin/dev/meloda/fast/settings/SettingsViewModel.kt
index 00f3028b..b94909bb 100644
--- a/feature/settings/src/main/kotlin/dev/meloda/fast/settings/SettingsViewModel.kt
+++ b/feature/settings/src/main/kotlin/dev/meloda/fast/settings/SettingsViewModel.kt
@@ -278,14 +278,14 @@ class SettingsViewModelImpl(
)
val generalShowEmojiButton = SettingsItem.Switch(
key = SettingsKeys.KEY_SHOW_EMOJI_BUTTON,
- title = UiText.Simple("Show emoji button"),
- text = UiText.Simple("Show emoji button in chat panel"),
+ title = UiText.Resource(UiR.string.settings_general_show_emoji_button_title),
+ text = UiText.Resource(UiR.string.settings_general_show_emoji_button_summary),
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
)
val generalEnableHaptic = SettingsItem.Switch(
key = SettingsKeys.KEY_ENABLE_HAPTIC,
defaultValue = SettingsKeys.DEFAULT_ENABLE_HAPTIC,
- title = UiText.Simple("Enable haptic")
+ title = UiText.Resource(UiR.string.settings_general_enable_haptic_title)
)
val appearanceTitle = SettingsItem.Title(
@@ -342,7 +342,7 @@ class SettingsViewModelImpl(
val appearanceUseSystemFont = SettingsItem.Switch(
key = SettingsKeys.KEY_USE_SYSTEM_FONT,
defaultValue = SettingsKeys.DEFAULT_USE_SYSTEM_FONT,
- title = UiText.Simple("Use system font")
+ title = UiText.Resource(UiR.string.settings_appearance_use_system_font_title)
)
val appearanceLanguage = SettingsItem.TitleText(
key = SettingsKeys.KEY_APPEARANCE_LANGUAGE,
@@ -379,7 +379,7 @@ class SettingsViewModelImpl(
val experimentalTitle = SettingsItem.Title(
key = "experimental",
- title = UiText.Simple("Experimental - VERY unstable")
+ title = UiText.Resource(UiR.string.settings_experimental_title)
)
val experimentalLongPollBackground = SettingsItem.Switch(
key = SettingsKeys.KEY_LONG_POLL_IN_BACKGROUND,
@@ -390,19 +390,20 @@ class SettingsViewModelImpl(
val experimentalShowTimeInActionMessages = SettingsItem.Switch(
key = SettingsKeys.KEY_SHOW_TIME_IN_ACTION_MESSAGES,
defaultValue = SettingsKeys.DEFAULT_SHOW_TIME_IN_ACTION_MESSAGES,
- title = UiText.Simple("Show time in action messages")
+ title = UiText.Resource(UiR.string.settings_features_show_time_in_action_messages_title)
)
val experimentalUseBlur = SettingsItem.Switch(
key = SettingsKeys.KEY_USE_BLUR,
defaultValue = SettingsKeys.DEFAULT_USE_BLUR,
- title = UiText.Simple("Use blur"),
- text = UiText.Simple("Adds blur wherever possible\nWorks on android 12 and newer"),
+ title = UiText.Resource(UiR.string.settings_experimental_use_blur_title),
+ text = UiText.Resource(UiR.string.settings_experimental_use_blur_summary),
+ isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
)
val enableAnimations = SettingsItem.Switch(
key = SettingsKeys.KEY_MORE_ANIMATIONS,
defaultValue = SettingsKeys.DEFAULT_MORE_ANIMATIONS,
- title = UiText.Simple("More animations"),
- text = UiText.Simple("Use animations wherever possible")
+ title = UiText.Resource(UiR.string.settings_experimental_more_animations_title),
+ text = UiText.Resource(UiR.string.settings_experimental_more_animations_summary)
)
val debugTitle = SettingsItem.Title(
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 16d75de2..643477f7 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -5,22 +5,22 @@ compileSdk = "35"
versionCode = "9"
versionName = "0.1.6"
-agp = "8.7.3"
+agp = "8.9.0"
converterMoshi = "2.11.0"
eithernet = "2.0.0"
-haze = "1.1.1"
-kotlin = "2.1.0"
-ksp = "2.1.0-1.0.29"
+haze = "1.5.1"
+kotlin = "2.1.10"
+ksp = "2.1.10-1.0.31"
-compose-bom = "2024.12.01"
-koin = "4.0.1"
+compose-bom = "2025.03.00"
+koin = "4.0.2"
-accompanist = "0.37.0"
+accompanist = "0.37.2"
coil = "2.7.0"
coroutines = "1.10.1"
junit = "4.13.2"
chucker = "4.1.0"
-guava = "33.4.0-jre"
+guava = "33.4.5-jre"
lifecycle = "2.8.7"
core-ktx = "1.15.0"
material = "1.12.0"
@@ -33,10 +33,10 @@ nanokt = "1.2.0"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.0"
-androidx-navigation = "2.8.5"
-serialization = "1.7.3"
+androidx-navigation = "2.8.9"
+serialization = "1.8.0"
rebugger = "1.0.0-rc03"
-moduleGraph = "2.7.1"
+moduleGraph = "2.8.0"
[libraries]
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 41d9927a..2c352119 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 f22a7691..cea7a793 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Mon Oct 28 18:41:43 MSK 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c7873..f5feea6d 100644
--- a/gradlew
+++ b/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,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/platforms/jvm/plugins-application/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 +82,12 @@ 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 -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +134,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 +201,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" \
@@ -205,6 +217,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32..9d21a218 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal