diff --git a/.github/workflows/actions_dev.yml b/.github/workflows/actions_dev.yml deleted file mode 100644 index 87686781..00000000 --- a/.github/workflows/actions_dev.yml +++ /dev/null @@ -1,95 +0,0 @@ -#Default state uncommented, custom state commented in other branches to avoid failures -name: Actions Dev -on: - push: - branches: - - actions_dev -jobs: - actions_dev: - name: Work In Progress - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - -#name: Actions Dev -#on: -# push: -# tags: -# - 'v*' -#jobs: -# release: -# name: Work In Progress -# runs-on: ubuntu-latest -# steps: -# -# - name: Checkout -# uses: actions/checkout@v3 -# -# - name: Set up JDK -# uses: actions/setup-java@v3 -# with: -# distribution: 'temurin' #Eclipse -# java-version: '17' -# -# - name: Make gradlew executable -# run: chmod +x ./gradlew -# -# - name: Run Linters and Test -# run: ./gradlew check -# -# - name: Zip Test Results -# uses: montudor/action-zip@v1 -# with: -# args: zip -qq -r test-reports.zip app/build/reports -# -# - name: Build with Gradle -# run: ./gradlew build -# -# - name: Build Release AAB -# run: ./gradlew bundleRelease -# #path app/build/outputs/bundle/release/app-release.aab -# -# - name: Build Debug APK -# run: ./gradlew assembleDebug --stacktrace -# #path app/build/outputs/apk/debug/app-debug.apk -# -# - name: Build Release APK -# run: ./gradlew assembleRelease --stacktrace -# #path app/build/outputs/apk/release/app-release-unsigned.apk -# -# - name: Rename Release APK -# #skip app-release-unsigned-signed.apk case -# run: mv app/build/outputs/apk/release/app-release-unsigned.apk app/build/outputs/apk/release/app-release.apk -# -# - name: Sign APK -# id: sign_apk -# uses: r0adkll/sign-android-release@v1 -# with: -# releaseDirectory: app/build/outputs/apk/release -# signingKeyBase64: ${{ secrets.KEY_STORE_FILE }} -# keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} -# alias: ${{ secrets.KEY_ALIAS }} -# keyPassword: ${{ secrets.KEY_PASSWORD }} -# -# - name: Sign AAB -# id: sign_aab -# uses: r0adkll/sign-android-release@v1 -# with: -# releaseDirectory: app/build/outputs/bundle/release -# signingKeyBase64: ${{ secrets.KEY_STORE_FILE }} -# keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} -# alias: ${{ secrets.KEY_ALIAS }} -# keyPassword: ${{ secrets.KEY_PASSWORD }} -# #path ${{steps.sign_aab.outputs.signedReleaseFile}} -# -# - name: Release -# uses: softprops/action-gh-release@v1 -# with: -# name: Release ${{ github.ref_name }} -# prerelease: true -# files: | -# app/build/outputs/apk/debug/app-debug.apk -# ${{steps.sign_apk.outputs.signedReleaseFile}} -# ${{steps.sign_aab.outputs.signedReleaseFile}} -# test-reports.zip \ No newline at end of file diff --git a/.github/workflows/dev.yml b/.github/workflows/dominguez.yml similarity index 92% rename from .github/workflows/dev.yml rename to .github/workflows/dominguez.yml index d2ae3187..a7002156 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dominguez.yml @@ -2,7 +2,7 @@ name: Test App on: push: branches: - - dev + - dominguez tags: - '*alpha*' - '*beta*' @@ -43,4 +43,4 @@ jobs: - name: Upload APK uses: actions/upload-artifact@v3 with: - path: app/build/outputs/apk/debug/app-debug.apk \ No newline at end of file + path: app/build/outputs/apk/debug/app-debug.apk diff --git a/README.md b/README.md index 1ebdae9e..90eff89e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![master workflow](https://github.com/Emotional-Wellbeing/App/actions/workflows/master.yml/badge.svg) -![dev workflow](https://github.com/Emotional-Wellbeing/App/actions/workflows/dev.yml/badge.svg) +![dominguez workflow](https://github.com/Emotional-Wellbeing/App/actions/workflows/dominguez.yml/badge.svg) # SBE - App diff --git a/app/build.gradle b/app/build.gradle index 8198e273..b3a11e6b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -77,10 +77,13 @@ dependencies { // Jetpack compose // Kotlin extensions for 'lifecycle' artifact + //noinspection GradleDependency implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" // Compose integration with Lifecycle + //noinspection GradleDependency implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version" // Compose integration with Lifecycle ViewModel + //noinspection GradleDependency implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version" implementation "androidx.activity:activity-compose:$activity_compose_version" @@ -117,6 +120,7 @@ dependencies { implementation "androidx.datastore:datastore-preferences:$datastore_preferences_version" // Settings + //noinspection GradleDependency implementation "com.github.alorma:compose-settings-ui-m3:$compose_settings_version" // Navigation @@ -133,7 +137,9 @@ dependencies { ksp "io.github.raamcosta.compose-destinations:ksp:$compose_destination_version" // Room + //noinspection GradleDependency implementation "androidx.room:room-runtime:$room_version" + //noinspection GradleDependency implementation "androidx.room:room-ktx:$room_version" ksp "androidx.room:room-compiler:$room_version" @@ -160,10 +166,13 @@ dependencies { // Vico // Includes the core logic for charts and other elements. + //noinspection GradleDependency implementation "com.patrykandpatrick.vico:core:$vico_version" // For Jetpack Compose. + //noinspection GradleDependency implementation "com.patrykandpatrick.vico:compose:$vico_version" // For `compose`. Creates a `ChartStyle` based on an M3 Material Theme. + //noinspection GradleDependency implementation "com.patrykandpatrick.vico:compose-m3:$vico_version" // Work Manager diff --git a/app/src/main/java/es/upm/bienestaremocional/data/crypto/Crypto.kt b/app/src/main/java/es/upm/bienestaremocional/data/crypto/Crypto.kt index 619cb00c..01db3579 100644 --- a/app/src/main/java/es/upm/bienestaremocional/data/crypto/Crypto.kt +++ b/app/src/main/java/es/upm/bienestaremocional/data/crypto/Crypto.kt @@ -1,4 +1,4 @@ -package es.upm.bienestaremocional.data +package es.upm.bienestaremocional.data.crypto import java.security.MessageDigest import java.util.UUID diff --git a/app/src/main/java/es/upm/bienestaremocional/data/crypto/SecretKey.kt b/app/src/main/java/es/upm/bienestaremocional/data/crypto/SecretKey.kt index 9e2c9135..12c4afdf 100644 --- a/app/src/main/java/es/upm/bienestaremocional/data/crypto/SecretKey.kt +++ b/app/src/main/java/es/upm/bienestaremocional/data/crypto/SecretKey.kt @@ -7,16 +7,16 @@ import javax.crypto.KeyGenerator import javax.crypto.SecretKey object SecretKey { - private const val secretKeyAlias = "database_key" - private const val provider = "AndroidKeyStore" - private const val algorithm = KeyProperties.KEY_ALGORITHM_AES - private const val cipherMode = KeyProperties.BLOCK_MODE_GCM + private const val SECRET_KEY_ALIAS = "database_key" + private const val PROVIDER = "AndroidKeyStore" + private const val ALGORITHM = KeyProperties.KEY_ALGORITHM_AES + private const val CIPHER_MODE = KeyProperties.BLOCK_MODE_GCM private fun generateSecretKey(): SecretKey { - val keyGenerator = KeyGenerator.getInstance(algorithm, provider) + val keyGenerator = KeyGenerator.getInstance(ALGORITHM, PROVIDER) val spec = KeyGenParameterSpec - .Builder(secretKeyAlias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(cipherMode) + .Builder(SECRET_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(CIPHER_MODE) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build() @@ -26,9 +26,9 @@ object SecretKey { fun getSecretKey(): SecretKey { // Get keyStore instance, no parameters at load stage are needed - val keyStore = KeyStore.getInstance(provider).apply { load(null) } + val keyStore = KeyStore.getInstance(PROVIDER).apply { load(null) } // Get key entry - val secretKeyEntry = keyStore.getEntry(secretKeyAlias, null) as KeyStore.SecretKeyEntry? + val secretKeyEntry = keyStore.getEntry(SECRET_KEY_ALIAS, null) as KeyStore.SecretKeyEntry? // Get the key itself or if is null generate it return secretKeyEntry?.secretKey ?: generateSecretKey() } diff --git a/app/src/main/java/es/upm/bienestaremocional/data/info/AppInfoImpl.kt b/app/src/main/java/es/upm/bienestaremocional/data/info/AppInfoImpl.kt index b224c7c9..e194b694 100644 --- a/app/src/main/java/es/upm/bienestaremocional/data/info/AppInfoImpl.kt +++ b/app/src/main/java/es/upm/bienestaremocional/data/info/AppInfoImpl.kt @@ -7,7 +7,7 @@ import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore -import es.upm.bienestaremocional.data.generateUID +import es.upm.bienestaremocional.data.crypto.generateUID import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map diff --git a/app/src/main/java/es/upm/bienestaremocional/data/phonecalls/PhoneInfo.kt b/app/src/main/java/es/upm/bienestaremocional/data/phonecalls/PhoneInfo.kt index 5616a6ab..7b3f5488 100644 --- a/app/src/main/java/es/upm/bienestaremocional/data/phonecalls/PhoneInfo.kt +++ b/app/src/main/java/es/upm/bienestaremocional/data/phonecalls/PhoneInfo.kt @@ -7,7 +7,7 @@ import android.content.pm.PackageManager import android.database.Cursor import android.provider.CallLog.Calls.* import androidx.core.content.ContextCompat -import es.upm.bienestaremocional.data.securePrivateData +import es.upm.bienestaremocional.data.crypto.securePrivateData class PhoneInfo { diff --git a/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/Level.kt b/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/Level.kt index d9090ff1..b65ddc21 100644 --- a/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/Level.kt +++ b/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/Level.kt @@ -34,24 +34,6 @@ enum class Level( Severe("severe", R.string.severe); companion object { - /** - * Obtain the LevelLabel from their id - * @param id: The id to query - * @return The LevelLabel if the id matches with any LevelLabel or null if doesn't - */ - fun decodeFromId(id: String): Level? { - return when (id) { - Low.id -> Low - Moderate.id -> Moderate - High.id -> High - Minimal.id -> Minimal - Mild.id -> Mild - ModeratelySevere.id -> ModeratelySevere - Severe.id -> Severe - else -> null - } - } - @Composable fun Level.getColor(): Color { return when (this) { diff --git a/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/QuestionnaireDebug.kt b/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/QuestionnaireDebug.kt index c8a04f7a..26454c4c 100644 --- a/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/QuestionnaireDebug.kt +++ b/app/src/main/java/es/upm/bienestaremocional/data/questionnaire/QuestionnaireDebug.kt @@ -3,114 +3,11 @@ package es.upm.bienestaremocional.data.questionnaire import es.upm.bienestaremocional.data.database.entity.daily.DailyDepression import es.upm.bienestaremocional.data.database.entity.daily.DailyLoneliness import es.upm.bienestaremocional.data.database.entity.daily.DailyStress -import es.upm.bienestaremocional.data.database.entity.daily.DailySuicide -import es.upm.bienestaremocional.data.database.entity.daily.DailySymptoms -import es.upm.bienestaremocional.data.database.entity.oneoff.OneOffDepression -import es.upm.bienestaremocional.data.database.entity.oneoff.OneOffLoneliness -import es.upm.bienestaremocional.data.database.entity.oneoff.OneOffStress import es.upm.bienestaremocional.data.questionnaire.daily.DailyDepressionManager import es.upm.bienestaremocional.data.questionnaire.daily.DailyLonelinessManager import es.upm.bienestaremocional.data.questionnaire.daily.DailyStressManager -import es.upm.bienestaremocional.data.questionnaire.daily.DailySuicideManager -import es.upm.bienestaremocional.data.questionnaire.daily.DailySymptomsManager -import es.upm.bienestaremocional.data.questionnaire.oneoff.OneOffDepressionManager -import es.upm.bienestaremocional.data.questionnaire.oneoff.OneOffLonelinessManager -import es.upm.bienestaremocional.data.questionnaire.oneoff.OneOffStressManager import kotlin.random.Random -/** - * Generates an One Off Stress Entry with random data without inserting in database. - * @param createdAt: Entry's timestamp - * @param fulfilled : If questionnaire must be fulfilled or not. If not, a random answer is picked to be uncompleted - * @return Entry - */ -fun generateOneOffStressEntry( - createdAt: Long, - fulfilled: Boolean = true -): OneOffStress { - val oneOffStressManager = OneOffStressManager() - val oneOffStress = OneOffStress(createdAt = createdAt) - - val uncompletedAnswer = if (fulfilled) - null - else - Random.nextInt(oneOffStressManager.numberOfQuestions) - - for (questionIndex in 0 until oneOffStressManager.numberOfQuestions) { - if (questionIndex != uncompletedAnswer) - oneOffStressManager.setAnswer( - questionIndex = questionIndex, - answer = Random.nextInt(0, oneOffStressManager.numberOfAnswers) - ) - } - oneOffStressManager.setEntity(oneOffStress) - return oneOffStress -} - -/** - * Generates an One Off Depression Entry with random data without inserting in database. - * @param createdAt: Entry's timestamp - * @param fulfilled : If questionnaire must be fulfilled or not. If not, a random answer is picked to be uncompleted - * @return Entry - */ -fun generateOneOffDepressionEntry( - createdAt: Long, - fulfilled: Boolean = true -): OneOffDepression { - val oneOffDepressionManager = OneOffDepressionManager() - val oneOffDepression = OneOffDepression(createdAt = createdAt) - - val uncompletedAnswer = if (fulfilled) - null - else - Random.nextInt(oneOffDepressionManager.numberOfQuestions) - - for (questionIndex in 0 until oneOffDepressionManager.numberOfQuestions) { - if (questionIndex != uncompletedAnswer) - oneOffDepressionManager.setAnswer( - questionIndex = questionIndex, - answer = Random.nextInt( - 0, - oneOffDepressionManager.numberOfAnswers - ) - ) - } - oneOffDepressionManager.setEntity(oneOffDepression) - return oneOffDepression -} - -/** - * Generates an One Off Loneliness entry with random data without inserting in database. - * @param createdAt: Entry's timestamp - * @param fulfilled : If questionnaire must be fulfilled or not. If not, a random answer is picked to be uncompleted - * @return Entry - */ -fun generateOneOffLonelinessEntry( - createdAt: Long, - fulfilled: Boolean = true -): OneOffLoneliness { - val oneOffLonelinessManager = OneOffLonelinessManager() - val oneOffLoneliness = OneOffLoneliness(createdAt = createdAt) - - val uncompletedAnswer = if (fulfilled) - null - else - Random.nextInt(oneOffLonelinessManager.numberOfQuestions) - - for (questionIndex in 0 until oneOffLonelinessManager.numberOfQuestions) { - if (questionIndex != uncompletedAnswer) - oneOffLonelinessManager.setAnswer( - questionIndex = questionIndex, - answer = Random.nextInt( - 0, - oneOffLonelinessManager.numberOfAnswers - ) - ) - } - oneOffLonelinessManager.setEntity(oneOffLoneliness) - return oneOffLoneliness -} - /** * Generates an Daily Stress entry with random data without inserting in database. * @param createdAt: Entry's timestamp @@ -207,78 +104,3 @@ fun generateDailyLonelinessEntry( return dailyLoneliness } -/** - * Generates an Daily Suicide entry with random data without inserting in database. - * @param createdAt: Entry's timestamp - * @param fulfilled : If questionnaire must be fulfilled or not. If not, a random answer is picked to be uncompleted - * @return Entry - */ -fun generateDailySuicideEntry( - createdAt: Long, - fulfilled: Boolean = true -): DailySuicide { - val dailySuicideManager = DailySuicideManager() - val dailySuicide = DailySuicide(createdAt = createdAt) - - val differentAnswer = Random.nextInt(dailySuicideManager.numberOfQuestions) - - for (questionIndex in 0 until dailySuicideManager.numberOfQuestions) { - if (fulfilled) { - // Different answer will be the only 0, so previous answers must be 1 - if (questionIndex <= differentAnswer) { - val answer = if (questionIndex < differentAnswer) - 1 - else - 0 - - dailySuicideManager.setAnswer( - questionIndex = questionIndex, - answer = answer - ) - } - } - else { - // If one 0 is present, the entry is fulfilled - if (questionIndex < differentAnswer) - dailySuicideManager.setAnswer( - questionIndex = questionIndex, - answer = 1 - ) - } - } - dailySuicideManager.setEntity(dailySuicide) - return dailySuicide -} - -/** - * Generates an Daily Symptoms entry with random data without inserting in database. - * @param createdAt: Entry's timestamp - * @param fulfilled : If questionnaire must be fulfilled or not. If not, a random answer is picked to be uncompleted - * @return Entry - */ -fun generateDailySymptomsEntry( - createdAt: Long, - fulfilled: Boolean = true -): DailySymptoms { - val dailySymptomsManager = DailySymptomsManager() - val dailySymptoms = DailySymptoms(createdAt = createdAt) - - val uncompletedAnswer = if (fulfilled) - null - else - Random.nextInt(dailySymptomsManager.numberOfQuestions) - - for (questionIndex in 0 until dailySymptomsManager.numberOfQuestions) { - if (questionIndex != uncompletedAnswer) - dailySymptomsManager.setAnswer( - questionIndex = questionIndex, - answer = Random.nextInt( - dailySymptomsManager.answerRange.first, - dailySymptomsManager.answerRange.last + 1 - ) - ) - } - dailySymptomsManager.setEntity(dailySymptoms) - return dailySymptoms -} - diff --git a/app/src/main/java/es/upm/bienestaremocional/di/AppModule.kt b/app/src/main/java/es/upm/bienestaremocional/di/AppModule.kt index 5df7221f..98e406ff 100644 --- a/app/src/main/java/es/upm/bienestaremocional/di/AppModule.kt +++ b/app/src/main/java/es/upm/bienestaremocional/di/AppModule.kt @@ -80,6 +80,7 @@ object AppModule { ): WorkAdministrator = WorkAdministratorImpl(context, logTag) + @Suppress("SameReturnValue") @Provides @Singleton @Named("logTag") diff --git a/app/src/main/java/es/upm/bienestaremocional/domain/processing/Time.kt b/app/src/main/java/es/upm/bienestaremocional/domain/processing/Time.kt index d538093a..ae4513b0 100644 --- a/app/src/main/java/es/upm/bienestaremocional/domain/processing/Time.kt +++ b/app/src/main/java/es/upm/bienestaremocional/domain/processing/Time.kt @@ -142,12 +142,5 @@ fun getStartAndEndOfYesterdayMillisecondTimestamps(): Pair { return Pair(yesterday.lower.toEpochMilliSecond(), yesterday.upper.toEpochMilliSecond()) } -/** - * Convert the range in [ZonedDateTime] to [Pair] containing the same information but in - * millisecond timestamp format - */ -fun Range.toPairMillisecondTimestamps(): Pair = - Pair(lower.toEpochMilliSecond(), upper.toEpochMilliSecond()) - fun Range.lowerStartDayUpperEndDay(): Range = Range(lower.toStartOfTheDay(), upper.toEndOfTheDay()) \ No newline at end of file diff --git a/app/src/main/java/es/upm/bienestaremocional/domain/usecases/InsertOneOffRoundUseCaseImpl.kt b/app/src/main/java/es/upm/bienestaremocional/domain/usecases/InsertOneOffRoundUseCaseImpl.kt index 60060681..f44b6634 100644 --- a/app/src/main/java/es/upm/bienestaremocional/domain/usecases/InsertOneOffRoundUseCaseImpl.kt +++ b/app/src/main/java/es/upm/bienestaremocional/domain/usecases/InsertOneOffRoundUseCaseImpl.kt @@ -1,5 +1,6 @@ package es.upm.bienestaremocional.domain.usecases +import android.util.Log import es.upm.bienestaremocional.data.Measure import es.upm.bienestaremocional.data.database.entity.oneoff.OneOffDepression import es.upm.bienestaremocional.data.database.entity.oneoff.OneOffLoneliness @@ -21,6 +22,7 @@ class InsertOneOffRoundUseCaseImpl( private val oneOffRoundRepository: OneOffRoundRepository ) : InsertOneOffRoundUseCase { override suspend fun insertOneOffRound(): OneOffRound { + Log.d(logTag, "Inserting one off round") val mandatoryMeasures = Measure.get().filter { it.mandatory && it.frequency == Measure.Frequency.DailyAndOneOff diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/component/ChartEntryWithTime.kt b/app/src/main/java/es/upm/bienestaremocional/ui/component/ChartEntryWithTime.kt deleted file mode 100644 index ecaba341..00000000 --- a/app/src/main/java/es/upm/bienestaremocional/ui/component/ChartEntryWithTime.kt +++ /dev/null @@ -1,12 +0,0 @@ -package es.upm.bienestaremocional.ui.component - -import com.patrykandpatrick.vico.core.entry.ChartEntry -import java.time.ZonedDateTime - -class ChartEntryWithTime( - val time: ZonedDateTime, - override val x: Float, - override val y: Float, -) : ChartEntry { - override fun withY(y: Float) = ChartEntryWithTime(time, x, y) -} diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/component/CircularProgessIndicator.kt b/app/src/main/java/es/upm/bienestaremocional/ui/component/CircularProgessIndicator.kt index c8823c68..dc475b43 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/component/CircularProgessIndicator.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/component/CircularProgessIndicator.kt @@ -15,7 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -238,12 +238,13 @@ private fun CircularProgressIndicator( val indicatorThickness: Dp = size.times(indicatorScaleFactor) // Remembers the data value to update it - var dataRemembered by remember { mutableStateOf(minValue) } + var dataRemembered by remember { mutableIntStateOf(minValue) } // This is to animate the foreground indicator val dataUsageAnimate = animateIntAsState( targetValue = dataRemembered, - animationSpec = tween(durationMillis = animationDuration) + animationSpec = tween(durationMillis = animationDuration), + label = "dataUsage" ) // Convert the data to an angle. Max is 360 diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/component/DailyRound.kt b/app/src/main/java/es/upm/bienestaremocional/ui/component/DailyRound.kt index 93fe2c70..23cad57f 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/component/DailyRound.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/component/DailyRound.kt @@ -1,6 +1,5 @@ package es.upm.bienestaremocional.ui.component -import android.content.Context import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext @@ -8,76 +7,8 @@ import androidx.compose.ui.res.stringResource import es.upm.bienestaremocional.R import es.upm.bienestaremocional.data.database.entity.round.DailyRound import es.upm.bienestaremocional.data.database.entity.round.DailyRoundFull -import es.upm.bienestaremocional.data.questionnaire.Level import es.upm.bienestaremocional.utils.formatUnixTimeStamp -/** - * Display [DailyRoundFull]: createdAt, score and level - */ -@Composable -fun ShowDailyRound(element: DailyRoundFull) { - val context = LocalContext.current - - val momentRes = if (element.dailyRound.moment == DailyRound.Moment.Morning) - R.string.daily_morning - else - R.string.daily_night - - Text( - context.getString( - R.string.round_created_formatter, - stringResource(id = momentRes), - formatUnixTimeStamp(element.dailyRound.createdAt) - ) - ) - - element.dailyStress?.let { - Text(stringResource(R.string.stress)) - if (it.completed) { - Text(context.getString(R.string.score_formatter, it.score)) - it.scoreLevel?.let { scoreLevel -> ShowScoreLevel(context, scoreLevel) } - } - else - Text(stringResource(R.string.uncompleted)) - } - - element.dailyDepression?.let { - Text(stringResource(R.string.depression)) - if (it.completed) { - Text(context.getString(R.string.score_formatter, it.score)) - it.scoreLevel?.let { scoreLevel -> ShowScoreLevel(context, scoreLevel) } - } - else - Text(stringResource(R.string.uncompleted)) - } - - element.dailyLoneliness?.let { - Text(stringResource(R.string.loneliness)) - if (it.completed) { - Text(context.getString(R.string.score_formatter, it.score)) - it.scoreLevel?.let { scoreLevel -> ShowScoreLevel(context, scoreLevel) } - } - else - Text(stringResource(R.string.uncompleted)) - } - - element.dailySuicide?.let { - Text(stringResource(R.string.suicide)) - if (it.completed) - Text(stringResource(R.string.completed)) - else - Text(stringResource(R.string.uncompleted)) - } - - element.dailySymptoms?.let { - Text(stringResource(R.string.symptoms)) - if (it.completed) - Text(stringResource(R.string.completed)) - else - Text(stringResource(R.string.uncompleted)) - } -} - /** * Display uncompleted [DailyRoundFull]: createdAt and uncompleted questionnaires */ @@ -129,12 +60,4 @@ fun ShowUncompletedDailyRound(element: DailyRoundFull) { Text("$uncompletedQuestionnairesText: ${uncompleted.joinToString()}") -} - -@Composable -private fun ShowScoreLevel(context: Context, scoreLevel: String) { - Level.decodeFromId(scoreLevel)?.let { - val label = stringResource(it.label) - Text(context.getString(R.string.level_formatter, label)) - } } \ No newline at end of file diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/component/OneOffRound.kt b/app/src/main/java/es/upm/bienestaremocional/ui/component/OneOffRound.kt index 76a1da79..b68ec833 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/component/OneOffRound.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/component/OneOffRound.kt @@ -1,61 +1,13 @@ package es.upm.bienestaremocional.ui.component -import android.content.Context import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import es.upm.bienestaremocional.R import es.upm.bienestaremocional.data.database.entity.round.OneOffRoundFull -import es.upm.bienestaremocional.data.questionnaire.Level import es.upm.bienestaremocional.utils.formatUnixTimeStamp -/** - * Display [OneOffRoundFull]: createdAt, score and level - */ -@Composable -fun ShowOneOffRound(element: OneOffRoundFull) { - val context = LocalContext.current - - Text( - context.getString( - R.string.round_created_formatter, - stringResource(id = R.string.one_off), - formatUnixTimeStamp(element.oneOffRound.createdAt) - ) - ) - - element.oneOffStress.let { - Text(stringResource(R.string.pss_questionnaire)) - if (it.completed) { - Text(context.getString(R.string.score_formatter, it.score)) - it.scoreLevel?.let { scoreLevel -> ShowScoreLevel(context, scoreLevel) } - } - else - Text(stringResource(R.string.uncompleted)) - } - - element.oneOffDepression?.let { - Text(stringResource(R.string.phq_questionnaire)) - if (it.completed) { - Text(context.getString(R.string.score_formatter, it.score)) - it.scoreLevel?.let { scoreLevel -> ShowScoreLevel(context, scoreLevel) } - } - else - Text(stringResource(R.string.uncompleted)) - } - - element.oneOffLoneliness?.let { - Text(stringResource(R.string.ucla_questionnaire)) - if (it.completed) { - Text(context.getString(R.string.score_formatter, it.score)) - it.scoreLevel?.let { scoreLevel -> ShowScoreLevel(context, scoreLevel) } - } - else - Text(stringResource(R.string.uncompleted)) - } -} - /** * Display uncompleted [OneOffRoundFull]: createdAt and uncompleted questionnaires */ @@ -92,12 +44,4 @@ fun ShowUncompletedOneOffRound(element: OneOffRoundFull) { Text("$uncompletedQuestionnairesText: ${uncompleted.joinToString()}") -} - -@Composable -private fun ShowScoreLevel(context: Context, scoreLevel: String) { - Level.decodeFromId(scoreLevel)?.let { - val label = stringResource(it.label) - Text(context.getString(R.string.level_formatter, label)) - } } \ No newline at end of file diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/component/questionnaire/Option.kt b/app/src/main/java/es/upm/bienestaremocional/ui/component/questionnaire/Option.kt index b6818850..60506ea7 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/component/questionnaire/Option.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/component/questionnaire/Option.kt @@ -4,7 +4,6 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -13,17 +12,15 @@ import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Slider -import androidx.compose.material3.SliderDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.graphics.toArgb @@ -49,7 +46,8 @@ fun OptionCard( MaterialTheme.colorScheme.inversePrimary else MaterialTheme.colorScheme.surfaceVariant, - animationSpec = tween(durationMillis = animationDurationMillis) + animationSpec = tween(durationMillis = animationDurationMillis), + label = "color" ) Card( modifier = Modifier @@ -75,7 +73,7 @@ fun OptionSlider( textColor: Color = MaterialTheme.colorScheme.onBackground ) { // Mutable state that stores the float position of the slider - var sliderPosition by remember { mutableStateOf(initialValue?.toFloat() ?: 0f) } + var sliderPosition by remember { mutableFloatStateOf(initialValue?.toFloat() ?: 0f) } val rangeSize = (range.last - range.first) @@ -130,101 +128,6 @@ fun OptionSlider( } } -@Composable -private fun OptionSliderWithLine( - initialValue: Int?, - onAnswer: (Int) -> Unit, - range: IntRange, - textStyle: TextStyle = MaterialTheme.typography.labelMedium, - textColor: Color = MaterialTheme.colorScheme.onBackground -) { - // Mutable state that stores the float position of the slider - var sliderPosition by remember { mutableStateOf(initialValue?.toFloat() ?: 0f) } - - val rangeSize = (range.last - range.first) - - // Wrapper to not expose float type - val onValueChange: (Float) -> Unit = { - onAnswer(it.toInt()) - } - - // Canvas variables - - // Padding to start drawing - val drawPadding = with(LocalDensity.current) { 10.dp.toPx() } - // Size of the font in pixels - val textSize = with(LocalDensity.current) { textStyle.fontSize.toPx() } - // Height of total element - val canvasHeight = 50.dp - - //Canvas object to draw text - val textPaint = android.graphics.Paint().apply { - color = textColor.toArgb() - textAlign = android.graphics.Paint.Align.CENTER - this.textSize = textSize - } - - //Line variables - val lineHeightDp = 10.dp - val lineHeightPx = with(LocalDensity.current) { lineHeightDp.toPx() } - - - - Box(contentAlignment = Alignment.Center) - { - Canvas( - modifier = Modifier - .height(canvasHeight) - .fillMaxWidth() - .padding( - top = canvasHeight - .div(2) - .minus(lineHeightDp.div(2)) - ) - ) { - // Line variables - // Vertical axis is y on canvas - val verticalStart = 0f - - val distance = (size.width.minus(2 * drawPadding)).div(rangeSize) - range.forEachIndexed { index, point -> - - //Draw line marker - drawLine( - color = Color.DarkGray, - start = Offset(x = drawPadding + index.times(distance), y = verticalStart), - end = Offset(x = drawPadding + index.times(distance), y = lineHeightPx) - ) - - // Draw label text - this.drawContext.canvas.nativeCanvas.drawText( - point.toString(), - drawPadding + index.times(distance), - size.height, - textPaint - ) - } - } - Slider( - value = sliderPosition, - onValueChange = { sliderPosition = it }, - modifier = Modifier.fillMaxWidth(), - // ValueRange is float range - valueRange = range.first.toFloat()..range.last.toFloat(), - // We want to make available all the integers between first and last of the range - steps = rangeSize - 1, - // Set tick elements to color transparent in order to hide them - colors = SliderDefaults.colors( - activeTickColor = Color.Transparent, - inactiveTickColor = Color.Transparent - ), - onValueChangeFinished = { - onValueChange(sliderPosition) - } - ) - } -} - @Composable @Preview fun OptionCardNotSelectedPreview() { @@ -299,32 +202,4 @@ fun OptionSliderDarkThemePreview() { ) } } -} - -@Composable -@Preview -fun OptionSliderWithLinePreview() { - BienestarEmocionalTheme { - Surface { - OptionSliderWithLine( - initialValue = 2, - onAnswer = {}, - range = 0..10 - ) - } - } -} - -@Composable -@Preview -fun OptionSliderWithLineDarkThemePreview() { - BienestarEmocionalTheme(darkTheme = true) { - Surface { - OptionSliderWithLine( - initialValue = 2, - onAnswer = {}, - range = 0..10 - ) - } - } } \ No newline at end of file diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/DistanceDisplay.kt b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/DistanceDisplay.kt index fb322026..0dc0c4d7 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/DistanceDisplay.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/DistanceDisplay.kt @@ -12,6 +12,7 @@ import es.upm.bienestaremocional.ui.component.DrawPair import es.upm.bienestaremocional.ui.component.SeriesDateTimeHeading import es.upm.bienestaremocional.ui.theme.BienestarEmocionalTheme import es.upm.bienestaremocional.utils.generateInterval +import java.util.Locale import kotlin.random.Random /** @@ -20,7 +21,7 @@ import kotlin.random.Random */ @Composable fun DistanceRecord.Display(widthSize: WindowWidthSizeClass) { - val distanceFormatted = String.format("%.2f", distance.inKilometers) + val distanceFormatted = String.format(Locale.getDefault(), "%.2f", distance.inKilometers) val unit = stringResource(id = R.string.km) BasicCard { diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/ElevationGainedDisplay.kt b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/ElevationGainedDisplay.kt index 4de8dfd3..d70c88a2 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/ElevationGainedDisplay.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/ElevationGainedDisplay.kt @@ -12,6 +12,7 @@ import es.upm.bienestaremocional.ui.component.DrawPair import es.upm.bienestaremocional.ui.component.SeriesDateTimeHeading import es.upm.bienestaremocional.ui.theme.BienestarEmocionalTheme import es.upm.bienestaremocional.utils.generateInterval +import java.util.Locale import kotlin.random.Random /** @@ -20,7 +21,7 @@ import kotlin.random.Random */ @Composable fun ElevationGainedRecord.Display(widthSize: WindowWidthSizeClass) { - val elevationGainedFormatted = String.format("%.2f", elevation.inMeters) + val elevationGainedFormatted = String.format(Locale.getDefault(),"%.2f", elevation.inMeters) val unit = stringResource(id = R.string.m) BasicCard { SeriesDateTimeHeading( diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/FloorsClimbedDisplay.kt b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/FloorsClimbedDisplay.kt index 8d2aff1b..e1b62cd8 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/FloorsClimbedDisplay.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/FloorsClimbedDisplay.kt @@ -11,6 +11,7 @@ import es.upm.bienestaremocional.ui.component.DrawPair import es.upm.bienestaremocional.ui.component.SeriesDateTimeHeading import es.upm.bienestaremocional.ui.theme.BienestarEmocionalTheme import es.upm.bienestaremocional.utils.generateInterval +import java.util.Locale import kotlin.random.Random /** @@ -19,7 +20,7 @@ import kotlin.random.Random */ @Composable fun FloorsClimbedRecord.Display(widthSize: WindowWidthSizeClass) { - val floorsFormatted = String.format("%.2f", floors) + val floorsFormatted = String.format(Locale.getDefault(),"%.2f", floors) BasicCard { SeriesDateTimeHeading( diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/TotalCaloriesBurnedDisplay.kt b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/TotalCaloriesBurnedDisplay.kt index f8d64aaa..4e5d3951 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/TotalCaloriesBurnedDisplay.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/TotalCaloriesBurnedDisplay.kt @@ -12,6 +12,7 @@ import es.upm.bienestaremocional.ui.component.DrawPair import es.upm.bienestaremocional.ui.component.SeriesDateTimeHeading import es.upm.bienestaremocional.ui.theme.BienestarEmocionalTheme import es.upm.bienestaremocional.utils.generateInterval +import java.util.Locale import kotlin.random.Random /** @@ -20,7 +21,7 @@ import kotlin.random.Random */ @Composable fun TotalCaloriesBurnedRecord.Display(widthSize: WindowWidthSizeClass) { - val kcal = String.format("%.2f", energy.inKilocalories) + val kcal = String.format(Locale.getDefault(),"%.2f", energy.inKilocalories) val unit = stringResource(id = R.string.kcal) BasicCard { SeriesDateTimeHeading( diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/WeightDisplay.kt b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/WeightDisplay.kt index 68650570..31f418f1 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/WeightDisplay.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/component/WeightDisplay.kt @@ -12,6 +12,7 @@ import es.upm.bienestaremocional.ui.component.DrawPair import es.upm.bienestaremocional.ui.component.SeriesDateTimeHeading import es.upm.bienestaremocional.ui.theme.BienestarEmocionalTheme import es.upm.bienestaremocional.utils.generateTime +import java.util.Locale import kotlin.random.Random /** @@ -20,7 +21,7 @@ import kotlin.random.Random */ @Composable fun WeightRecord.Display(widthSize: WindowWidthSizeClass) { - val weightFormatted = String.format("%.2f", weight.inKilograms) + val weightFormatted = String.format(Locale.getDefault(),"%.2f", weight.inKilograms) val unit = stringResource(id = R.string.kg) BasicCard { diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/viewmodel/HealthConnectViewModel.kt b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/viewmodel/HealthConnectViewModel.kt index 6a58e9b1..5d2cdbce 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/viewmodel/HealthConnectViewModel.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/healthconnect/viewmodel/HealthConnectViewModel.kt @@ -19,6 +19,7 @@ import java.io.IOException /** * Implements [HealthConnectViewModel] and add some shared variables */ +@Suppress("EmptyMethod") abstract class HealthConnectViewModel : ViewModel() { /** * Holds UiState to show (or not) data, request permission button, exceptions... diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/CommunityScreen.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/CommunityScreen.kt index ba7f5473..2a488af9 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/CommunityScreen.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/CommunityScreen.kt @@ -1,3 +1,5 @@ +@file:Suppress("KotlinDeprecation") + package es.upm.bienestaremocional.ui.screens.community import androidx.compose.foundation.layout.Arrangement @@ -12,7 +14,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.rememberPagerState import com.ramcosta.composedestinations.annotation.Destination @@ -59,7 +60,6 @@ fun CommunityScreen( ) } -@OptIn(ExperimentalPagerApi::class) @Composable private fun CommunityScreen( navigator: DestinationsNavigator, diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/Measure.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/Measure.kt index f811507f..c09cd048 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/Measure.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/community/Measure.kt @@ -1,3 +1,5 @@ +@file:Suppress("KotlinDeprecation") + package es.upm.bienestaremocional.ui.screens.community import androidx.compose.foundation.layout.Arrangement @@ -19,7 +21,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPagerIndicator import com.google.accompanist.pager.PagerState import es.upm.bienestaremocional.R @@ -28,7 +29,6 @@ import es.upm.bienestaremocional.domain.processing.NullableChartRecord import es.upm.bienestaremocional.ui.component.DoubleMeasureStatus import es.upm.bienestaremocional.ui.component.chart.ActualWeekChart -@OptIn(ExperimentalPagerApi::class) @Composable fun RemoteMeasure( questionnaire: DailyScoredQuestionnaire, diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/HomeScreen.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/HomeScreen.kt index 5346b559..4d172d13 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/HomeScreen.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/HomeScreen.kt @@ -1,3 +1,5 @@ +@file:Suppress("KotlinDeprecation") + package es.upm.bienestaremocional.ui.screens.home import androidx.compose.foundation.layout.Arrangement @@ -23,7 +25,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.rememberPagerState import com.ramcosta.composedestinations.annotation.Destination @@ -67,7 +68,6 @@ fun HomeScreen( } -@OptIn(ExperimentalPagerApi::class) @Composable private fun HomeScreen( navigator: DestinationsNavigator, diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/MeasureSummary.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/MeasureSummary.kt index 2c21dc6f..b9fddd21 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/MeasureSummary.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/home/MeasureSummary.kt @@ -1,3 +1,5 @@ +@file:Suppress("KotlinDeprecation") + package es.upm.bienestaremocional.ui.screens.home import androidx.compose.foundation.layout.Arrangement @@ -20,7 +22,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPagerIndicator import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.rememberPagerState @@ -35,7 +36,6 @@ import es.upm.bienestaremocional.ui.component.ShowAdviceHeadline import es.upm.bienestaremocional.ui.theme.BienestarEmocionalTheme -@OptIn(ExperimentalPagerApi::class) @Composable fun MeasureSummary( navigator: DestinationsNavigator, @@ -219,8 +219,6 @@ fun MeasureSummaryPreviewDarkTheme() { } } } - -@OptIn(ExperimentalPagerApi::class) @Preview @Composable fun MeasureSummaryWithPagerPreview() { @@ -239,7 +237,6 @@ fun MeasureSummaryWithPagerPreview() { } } -@OptIn(ExperimentalPagerApi::class) @Preview @Composable fun MeasureSummaryWithPagerPreviewDarkTheme() { diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/mydata/MyDataScreen.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/mydata/MyDataScreen.kt index ad34fb7b..13eeefea 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/mydata/MyDataScreen.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/mydata/MyDataScreen.kt @@ -12,8 +12,8 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.KeyboardArrowDown -import androidx.compose.material.icons.filled.KeyboardArrowRight import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -124,7 +124,7 @@ private fun CategoryText( val icon = if (selected) Icons.Default.KeyboardArrowDown else - Icons.Default.KeyboardArrowRight + Icons.AutoMirrored.Filled.KeyboardArrowRight Icon(icon, contentDescription = "Expandir") } } diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/onboarding/OnboardingScreen.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/onboarding/OnboardingScreen.kt index 7cd302e2..57404a26 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/onboarding/OnboardingScreen.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/onboarding/OnboardingScreen.kt @@ -1,3 +1,5 @@ +@file:Suppress("KotlinDeprecation") + package es.upm.bienestaremocional.ui.screens.onboarding import androidx.compose.foundation.layout.* @@ -53,7 +55,6 @@ fun OnboardingScreen( } } -@OptIn(ExperimentalPagerApi::class) @Composable private fun OnboardingScreen( heightSize: WindowHeightSizeClass, @@ -93,7 +94,6 @@ private fun OnboardingScreen( /** * Draws a single page of onboarding */ -@OptIn(ExperimentalPagerApi::class) @Composable private fun DrawPage( horizontalPagerContent: HorizontalPagerContent, diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/DailySuicideScreen.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/DailySuicideScreen.kt index 3168866c..6f55a2af 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/DailySuicideScreen.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/DailySuicideScreen.kt @@ -114,7 +114,7 @@ private fun DailySuicideScreen( ) } - if (state !is SuicideScreenState.Summary || state !is SuicideScreenState.Finished) { + if (state !is SuicideScreenState.Summary && state !is SuicideScreenState.Finished) { QuestionnaireLayout( title = title, onSkippingAttempt = onSkippingAttempt, diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/QuestionnaireScreen.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/QuestionnaireScreen.kt index 5fe0743b..c7ad2299 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/QuestionnaireScreen.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/questionnaire/QuestionnaireScreen.kt @@ -1,3 +1,5 @@ +@file:Suppress("KotlinDeprecation") + package es.upm.bienestaremocional.ui.screens.questionnaire import androidx.compose.foundation.layout.* @@ -32,8 +34,6 @@ import es.upm.bienestaremocional.ui.component.questionnaire.Summary import es.upm.bienestaremocional.ui.theme.BienestarEmocionalTheme import kotlinx.coroutines.launch - -@OptIn(ExperimentalPagerApi::class) @Composable fun QuestionnaireStringAnswersScreen( state: QuestionnaireState, @@ -84,7 +84,6 @@ fun QuestionnaireStringAnswersScreen( ) } -@OptIn(ExperimentalPagerApi::class) @Composable fun QuestionnaireStringAnswersScreen( state: QuestionnaireState, @@ -129,7 +128,6 @@ fun QuestionnaireStringAnswersScreen( ) } -@OptIn(ExperimentalPagerApi::class) @Composable fun QuestionnaireNumericAnswersScreen( state: QuestionnaireState, @@ -182,7 +180,6 @@ fun QuestionnaireNumericAnswersScreen( ) } -@OptIn(ExperimentalPagerApi::class) @Composable private fun QuestionnaireScoredScreen( state: QuestionnaireState, @@ -211,7 +208,7 @@ private fun QuestionnaireScoredScreen( } } - if (state !is QuestionnaireState.Summary || state !is QuestionnaireState.Finished) { + if (state !is QuestionnaireState.Summary && state !is QuestionnaireState.Finished) { QuestionnaireLayout( title = title, onSkippingAttempt = onSkippingAttempt, @@ -247,7 +244,6 @@ private fun QuestionnaireScoredScreen( } -@OptIn(ExperimentalPagerApi::class) @Composable private fun QuestionnaireNotScoredScreen( state: QuestionnaireState, @@ -274,7 +270,7 @@ private fun QuestionnaireNotScoredScreen( } - if (state !is QuestionnaireState.Summary || state !is QuestionnaireState.Finished) { + if (state !is QuestionnaireState.Summary && state !is QuestionnaireState.Finished) { QuestionnaireLayout( title = title, onSkippingAttempt = onSkippingAttempt, @@ -301,7 +297,6 @@ private fun QuestionnaireNotScoredScreen( } } -@OptIn(ExperimentalPagerApi::class) @Composable private fun QuestionnaireStringAnswersPage( question: String, @@ -330,7 +325,7 @@ private fun QuestionnaireStringAnswersPage( } -@OptIn(ExperimentalPagerApi::class) + @Composable private fun QuestionnaireNumericAnswersPage( question: String, @@ -364,7 +359,6 @@ private fun QuestionnaireNumericAnswersPage( ) } -@OptIn(ExperimentalPagerApi::class) @Composable private fun QuestionnairePage( question: String, @@ -781,7 +775,6 @@ fun QuestionnaireNumericAnswersWithScoreDarkThemeScreenPreview() { } -@OptIn(ExperimentalPagerApi::class) @Composable @Preview fun QuestionnaireStringAnswersPagePreview() { @@ -803,7 +796,6 @@ fun QuestionnaireStringAnswersPagePreview() { } } -@OptIn(ExperimentalPagerApi::class) @Composable @Preview fun QuestionnaireStringAnswersPageDarkThemePreview() { @@ -825,7 +817,6 @@ fun QuestionnaireStringAnswersPageDarkThemePreview() { } } -@OptIn(ExperimentalPagerApi::class) @Composable @Preview fun QuestionnaireNumericAnswersPagePreview() { @@ -846,7 +837,6 @@ fun QuestionnaireNumericAnswersPagePreview() { } } -@OptIn(ExperimentalPagerApi::class) @Composable @Preview fun QuestionnaireNumericAnswersPageDarkThemePreview() { @@ -867,7 +857,6 @@ fun QuestionnaireNumericAnswersPageDarkThemePreview() { } } -@OptIn(ExperimentalPagerApi::class) @Composable @Preview fun QuestionnairePagePreview() { @@ -885,7 +874,6 @@ fun QuestionnairePagePreview() { } } -@OptIn(ExperimentalPagerApi::class) @Composable @Preview fun QuestionnairePageDarkThemePreview() { diff --git a/app/src/main/java/es/upm/bienestaremocional/ui/screens/uncompleted/UncompletedQuestionnaires.kt b/app/src/main/java/es/upm/bienestaremocional/ui/screens/uncompleted/UncompletedQuestionnaires.kt index fc72b352..3e058b27 100644 --- a/app/src/main/java/es/upm/bienestaremocional/ui/screens/uncompleted/UncompletedQuestionnaires.kt +++ b/app/src/main/java/es/upm/bienestaremocional/ui/screens/uncompleted/UncompletedQuestionnaires.kt @@ -4,9 +4,9 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.TextButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState diff --git a/app/src/main/java/es/upm/bienestaremocional/utils/TimeUtils.kt b/app/src/main/java/es/upm/bienestaremocional/utils/TimeUtils.kt index b3d2e068..44727e54 100644 --- a/app/src/main/java/es/upm/bienestaremocional/utils/TimeUtils.kt +++ b/app/src/main/java/es/upm/bienestaremocional/utils/TimeUtils.kt @@ -2,13 +2,13 @@ package es.upm.bienestaremocional.utils import java.time.Duration import java.time.Instant -import java.time.LocalDate import java.time.ZoneId import java.time.ZoneOffset import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.format.FormatStyle import java.time.temporal.ChronoUnit +import java.util.Locale import kotlin.random.Random /** @@ -22,7 +22,8 @@ fun dateTimeWithOffsetOrDefault(time: Instant, offset: ZoneOffset? = null): Zone ?: run { ZonedDateTime.ofInstant(time, ZoneId.systemDefault()) } fun Duration.formatHoursMinutes() = - String.format("%01dh%02dm", this.toHours() % 24, this.toMinutes() % 60) + String.format(Locale.getDefault(),"%01dh%02dm", this.toHours() % 24, + this.toMinutes() % 60) fun formatDisplayTimeStartEnd( startTime: Instant, @@ -60,9 +61,6 @@ fun formatDateTime( return "$dateLabel: $timeLabel" } -fun formatDate(date: LocalDate): String = - DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(date) - fun formatDate(date: ZonedDateTime): String = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(date) diff --git a/app/src/main/java/es/upm/bienestaremocional/utils/Util.kt b/app/src/main/java/es/upm/bienestaremocional/utils/Util.kt index 6b8808a2..99d1aefa 100644 --- a/app/src/main/java/es/upm/bienestaremocional/utils/Util.kt +++ b/app/src/main/java/es/upm/bienestaremocional/utils/Util.kt @@ -10,8 +10,6 @@ import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState import java.time.Duration import java.time.ZonedDateTime -import kotlin.random.Random -import kotlin.random.nextInt // The minimum android level that can use Health Connect const val MIN_SUPPORTED_SDK = Build.VERSION_CODES.O_MR1 @@ -24,27 +22,6 @@ fun linspace(start: ZonedDateTime, end: ZonedDateTime, numPoints: Int): List { - return generateSequence { - // this lambda is the source of the sequence's values - Random.nextInt(min..max) - } - // make the values distinct, so there's no repeated ints - .distinct() - // only fetch 6 values - // Note: It's very important that the source lambda can provide - // this many distinct values! If not, the stream will - // hang, endlessly waiting for more unique values. - .take(length) - // and collect them into a Set - .toSet() -} - fun android12OrAbove(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S /** diff --git a/app/src/main/res/drawable/event_repeat.xml b/app/src/main/res/drawable/event_repeat.xml deleted file mode 100644 index 42c9c5f3..00000000 --- a/app/src/main/res/drawable/event_repeat.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/app/src/main/res/layout/item_install_application.xml b/app/src/main/res/layout/item_install_application.xml deleted file mode 100644 index 9dd6ddf7..00000000 --- a/app/src/main/res/layout/item_install_application.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index c696a0c6..b56a5c30 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -33,8 +33,8 @@ Sleep Language Exit - Deactivated - Activated + Disabled + Enabled "Manage access and permissions " View data collected by the app Treatment of your data @@ -53,7 +53,7 @@ Designed to help you take care of your emotional wellbeing in an easy and simple way. Created by and for the University. "We help you to monitor your mental health and detect possible symptoms so you can seek help. To do so, we will carry out simple daily questionnaires and more complete questionnaires every two weeks. You can configure the measures to be monitored. - You will receive a notification every time a new quiz is available: at 10am and 10pm daily, and every two weeks at 3pm. However, due to technical limitations these notifications may not appear, so for an optimal user experience open the application regularly. + You will receive a notification every time a new quiz is available: at 9 am and 9 pm daily, and every two weeks at 3pm. For an optimal user experience, open the application regularly. The app may use data such as your mobile usage or heart rate, but you have the full control of your personal data. "You can consult anonymised statistics about your community. Moreover, you can collaborate with the development of the application. @@ -75,7 +75,6 @@ Restart Restart to apply all changes Calories burnt - Level Metadata Id Data origin @@ -165,9 +164,6 @@ Hi! A new one-off questionnaire is available. Click here to do it. Feedback - Questionnaire frequency - One questionnaire at night - One questionnaire at lunch and another at night Additional measures Accept Cancel @@ -176,12 +172,11 @@ Questionnaire not completed Exit questionnaire Are you sure you want to skip the questionnaire? - Score Notifications Permission for notifications Adjust app notifications General app settings - Access Android\'s app settings: Power consumption, notifications… + Access Android\'s app settings Minimal Mild Moderate @@ -190,23 +185,12 @@ Low High No data to display - Daily Morning daily Night daily One Off - Daily rounds - One off rounds %s round created at: %s - Created at: %s - PSS questionnaire - PHQ questionnaire - UCLA questionnaire - Score: %d - %s level Continue How have you been today? - Completed - Uncompleted Granularity Day Week @@ -214,7 +198,6 @@ Time interval No data to display Request permissions - Generate data Uploading… Uploading data in progress… Stress @@ -237,7 +220,6 @@ You have uncompleted questionnaires Review Permissions - App permissions Permission granted. You can disable it in the Android settings menu Call listing permissions Location permissions diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3ce555f0..5d49ab9f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,17 +50,13 @@ Las personas detrás del proyecto Retroalimentación - Frecuencia de los cuestionarios - Un cuestionario a la noche - Un cuestionario al mediodía y otro a la noche Mediciones adicionales Ajustes generales de la aplicación - Accede a los ajustes de la app: Consumo de energía, notificaciones… + Accede a los ajustes de la app Cuestionario Medida - Puntuación Estrés Depresión Soledad @@ -84,7 +80,7 @@ Notificaciones de la aplicación - Recibirás una notificación cada vez que haya un nuevo cuestionario disponible: a las 10 de la mañana y a las 10 de la noche diariamente, y cada dos semanas a las 3 de la tarde. No obstante, por limitaciones técnicas pueden no aparecer dichas notificaciones, por lo que para una óptima experiencia de uso abra la aplicación regularmente. + Recibirás una notificación cada vez que haya un nuevo cuestionario disponible: a las 9:00 y a las 21:00 diariamente, y cada dos semanas a las 15:00. Para una óptima experiencia de uso abra la aplicación regularmente. Tus datos, tu privacidad @@ -178,7 +174,6 @@ Reinicia para aplicar todos los cambios Tienes cuestionarios sin completar Calorias quemadas - Nivel Metadata: Id Origen de datos @@ -196,7 +191,6 @@ ppm No hay datos para mostrar Solicita permisos - Generar datos -- Ejercicio @@ -276,26 +270,14 @@ No hay datos para mostrar - Diaria Diaria de mañana Diaria de noche Puntual - Rondas diarias - Rondas puntuales Ronda %s creada en %s - Creada en: %s - Cuestionario PSS - Cuestionario PHQ - Cuestionario UCLA - Puntuación: %d - Nivel %s - Completado - Incompletado Continuar ¿Cómo has estado hoy? Permisos - Permisos de la aplicación Permiso concedido. Puede deshabilitarlo en el menú de configuración de Android Permisos de listado de llamadas Permisos de ubicación @@ -312,6 +294,4 @@ Si dispone de una pulsera compatible con Salud Conectada, por favor revise los permisos para acceder a los datos de la pulsera. Cuando esté listo, pulse el botón para ir a la ventana principal. - Title - 0 Kb \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0d654d47..97f8ad8c 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,6 @@ plugins { id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false } -task clean(type: Delete) { +tasks.register('clean', Delete) { delete rootProject.buildDir } \ No newline at end of file