Browse Source

Initial commit

master
Denis Tereshkin 3 months ago
commit
15e3df6978
  1. 1
      app/.gitignore
  2. 76
      app/build.gradle.kts
  3. 21
      app/proguard-rules.pro
  4. 24
      app/src/androidTest/java/ru/asakul/feel/ExampleInstrumentedTest.kt
  5. 28
      app/src/main/AndroidManifest.xml
  6. 23
      app/src/main/java/ru/asakul/feel/AppViewModelProvider.kt
  7. 15
      app/src/main/java/ru/asakul/feel/FeelApplication.kt
  8. 66
      app/src/main/java/ru/asakul/feel/MainActivity.kt
  9. 13
      app/src/main/java/ru/asakul/feel/data/AppContainer.kt
  10. 15
      app/src/main/java/ru/asakul/feel/data/MoodEntry.kt
  11. 27
      app/src/main/java/ru/asakul/feel/data/MoodEntryDao.kt
  12. 23
      app/src/main/java/ru/asakul/feel/data/MoodEntryDatabase.kt
  13. 15
      app/src/main/java/ru/asakul/feel/data/MoodEntryRepository.kt
  14. 16
      app/src/main/java/ru/asakul/feel/data/OfflineMoodEntryRepository.kt
  15. 44
      app/src/main/java/ru/asakul/feel/domain/Emotions.kt
  16. 9
      app/src/main/java/ru/asakul/feel/domain/MoodLevel.kt
  17. 24
      app/src/main/java/ru/asakul/feel/domain/Reasons.kt
  18. 13
      app/src/main/java/ru/asakul/feel/navigation/FeelDestinations.kt
  19. 34
      app/src/main/java/ru/asakul/feel/navigation/FeelNavHost.kt
  20. 28
      app/src/main/java/ru/asakul/feel/ui/MoodEntryRepr.kt
  21. 137
      app/src/main/java/ru/asakul/feel/ui/mood/MoodEntryScreen.kt
  22. 30
      app/src/main/java/ru/asakul/feel/ui/mood/MoodEntryViewModel.kt
  23. 204
      app/src/main/java/ru/asakul/feel/ui/moodlist/MoodListScreen.kt
  24. 32
      app/src/main/java/ru/asakul/feel/ui/moodlist/MoodListScreenViewModel.kt
  25. 225
      app/src/main/java/ru/asakul/feel/ui/theme/Color.kt
  26. 12
      app/src/main/java/ru/asakul/feel/ui/theme/Shapes.kt
  27. 282
      app/src/main/java/ru/asakul/feel/ui/theme/Theme.kt
  28. 5
      app/src/main/java/ru/asakul/feel/ui/theme/Type.kt
  29. 170
      app/src/main/res/drawable/ic_launcher_background.xml
  30. 30
      app/src/main/res/drawable/ic_launcher_foreground.xml
  31. 6
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  32. 6
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  33. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.webp
  34. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
  35. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.webp
  36. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
  37. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.webp
  38. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
  39. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
  40. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
  41. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
  42. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
  43. 53
      app/src/main/res/values-ru/strings.xml
  44. 10
      app/src/main/res/values/colors.xml
  45. 52
      app/src/main/res/values/strings.xml
  46. 5
      app/src/main/res/values/themes.xml
  47. 13
      app/src/main/res/xml/backup_rules.xml
  48. 19
      app/src/main/res/xml/data_extraction_rules.xml
  49. 17
      app/src/test/java/ru/asakul/feel/ExampleUnitTest.kt

1
app/.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
/build

76
app/build.gradle.kts

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp") version "2.1.0-1.0.29"
id("org.jetbrains.kotlin.plugin.compose")
}
android {
compileSdk = 35
defaultConfig {
applicationId = "ru.asakul.feel"
minSdk = 26
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
compose = true
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
namespace = "ru.asakul.feel"
}
dependencies {
// Import the Compose BOM
implementation(platform("androidx.compose:compose-bom:2024.12.01"))
implementation("androidx.activity:activity-compose:1.9.3")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-tooling")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7")
implementation("androidx.navigation:navigation-compose:2.8.5")
// Testing
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
//Room
implementation("androidx.room:room-runtime:${rootProject.extra["room_version"]}")
ksp("androidx.room:room-compiler:${rootProject.extra["room_version"]}")
implementation("androidx.room:room-ktx:${rootProject.extra["room_version"]}")
testImplementation(kotlin("test"))
}

21
app/proguard-rules.pro vendored

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

24
app/src/androidTest/java/ru/asakul/feel/ExampleInstrumentedTest.kt

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
package ru.asakul.feel
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("ru.asakul.feel", appContext.packageName)
}
}

28
app/src/main/AndroidManifest.xml

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".FeelApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Feel">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Feel">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

23
app/src/main/java/ru/asakul/feel/AppViewModelProvider.kt

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
package ru.asakul.feel
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import ru.asakul.feel.ui.mood.MoodEntryViewModel
import ru.asakul.feel.ui.moodlist.MoodListScreenViewModel
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
MoodEntryViewModel(moodEntryRepository = feelApplication().container.moodEntryRepository)
}
initializer {
MoodListScreenViewModel(moodEntryRepository = feelApplication().container.moodEntryRepository)
}
}
}
fun CreationExtras.feelApplication(): FeelApplication =
(this[AndroidViewModelFactory.APPLICATION_KEY] as FeelApplication)

15
app/src/main/java/ru/asakul/feel/FeelApplication.kt

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
package ru.asakul.feel
import android.app.Application
import ru.asakul.feel.data.AppContainer
import ru.asakul.feel.data.AppDataContainer
class FeelApplication : Application() {
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
container = AppDataContainer(this)
}
}

66
app/src/main/java/ru/asakul/feel/MainActivity.kt

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
package ru.asakul.feel
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
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.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import ru.asakul.feel.ui.mood.MoodEntryViewModel
import ru.asakul.feel.ui.mood.NewMoodEntry
import ru.asakul.feel.ui.theme.AppTheme
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.rememberNavController
import ru.asakul.feel.navigation.FeelNavHost
import ru.asakul.feel.navigation.MainScreen
import ru.asakul.feel.ui.moodlist.MoodListScreen
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AppTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
MyApp(
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
@Composable
fun MyApp(
modifier : Modifier = Modifier) {
var navController = rememberNavController()
Surface (
modifier = modifier
) {
FeelNavHost(
navController,
modifier
)
}
}
@Preview(showBackground = true, widthDp = 400)
@Composable
fun GreetingPreview() {
AppTheme {
MyApp()
}
}

13
app/src/main/java/ru/asakul/feel/data/AppContainer.kt

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
package ru.asakul.feel.data
import android.content.Context
interface AppContainer {
val moodEntryRepository: MoodEntryRepository
}
class AppDataContainer(private val context: Context) : AppContainer {
override val moodEntryRepository: MoodEntryRepository by lazy {
OfflineMoodEntryRepository(MoodEntryDatabase.getDatabase(context).itemDao())
}
}

15
app/src/main/java/ru/asakul/feel/data/MoodEntry.kt

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
package ru.asakul.feel.data
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.sql.Timestamp
@Entity(tableName = "mood_entries")
data class MoodEntry(
@PrimaryKey(autoGenerate = true)
val id: Long,
val timestamp: Long,
val moodLevel: Int,
val emotions: String,
val reasons: String
)

27
app/src/main/java/ru/asakul/feel/data/MoodEntryDao.kt

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
package ru.asakul.feel.data
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import kotlinx.coroutines.flow.Flow
@Dao
interface MoodEntryDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(moodEntry: MoodEntry)
@Update
suspend fun update(moodEntry: MoodEntry)
@Delete
suspend fun delete(moodEntry: MoodEntry)
@Query("SELECT * FROM mood_entries WHERE id = :id")
fun getItem(id: Long): Flow<MoodEntry>
@Query("SELECT * FROM mood_entries ORDER BY timestamp DESC")
fun getAllItems(): Flow<List<MoodEntry>>
}

23
app/src/main/java/ru/asakul/feel/data/MoodEntryDatabase.kt

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
package ru.asakul.feel.data
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [MoodEntry::class], version = 1, exportSchema = false)
abstract class MoodEntryDatabase : RoomDatabase() {
abstract fun itemDao(): MoodEntryDao
companion object {
@Volatile
private var Instance: MoodEntryDatabase? = null
fun getDatabase(context: Context): MoodEntryDatabase {
return Instance ?: synchronized(this) {
Room.databaseBuilder(context, MoodEntryDatabase::class.java, "mood_entry_database")
.fallbackToDestructiveMigration().build().also { Instance = it }
}
}
}
}

15
app/src/main/java/ru/asakul/feel/data/MoodEntryRepository.kt

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
package ru.asakul.feel.data
import kotlinx.coroutines.flow.Flow
interface MoodEntryRepository {
fun getAllMoodEntriesStream(): Flow<List<MoodEntry>>
fun getMoodEntryStream(id: Long): Flow<MoodEntry?>
suspend fun insertMoodEntry(item: MoodEntry)
suspend fun deleteMoodEntry(item: MoodEntry)
suspend fun updateMoodEntry(item: MoodEntry)
}

16
app/src/main/java/ru/asakul/feel/data/OfflineMoodEntryRepository.kt

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
package ru.asakul.feel.data
import kotlinx.coroutines.flow.Flow
class OfflineMoodEntryRepository(private val moodEntryDao: MoodEntryDao) : MoodEntryRepository {
override fun getAllMoodEntriesStream(): Flow<List<MoodEntry>> = moodEntryDao.getAllItems()
override fun getMoodEntryStream(id: Long): Flow<MoodEntry?> = moodEntryDao.getItem(id)
override suspend fun insertMoodEntry(item: MoodEntry) = moodEntryDao.insert(item)
override suspend fun deleteMoodEntry(item: MoodEntry) = moodEntryDao.delete(item)
override suspend fun updateMoodEntry(item: MoodEntry) = moodEntryDao.update(item)
}

44
app/src/main/java/ru/asakul/feel/domain/Emotions.kt

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
package ru.asakul.feel.domain
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import ru.asakul.feel.R
class Emotions() {
@Composable
fun allEmotions() = setOf(
stringResource(R.string.happiness),
stringResource(R.string.elation),
stringResource(R.string.calmness),
stringResource(R.string.tranquility),
stringResource(R.string.gratitude),
stringResource(R.string.surprise),
stringResource(R.string.fatigue),
stringResource(R.string.exhaustion),
stringResource(R.string.anger),
stringResource(R.string.sadness),
stringResource(R.string.fear),
stringResource(R.string.panic),
stringResource(R.string.irritation),
stringResource(R.string.apathy),
stringResource(R.string.hope),
stringResource(R.string.relief),
stringResource(R.string.confidence),
stringResource(R.string.satisfaction),
stringResource(R.string.joy),
stringResource(R.string.enthusiasm),
stringResource(R.string.pride),
stringResource(R.string.anxiety),
stringResource(R.string.nervousness),
stringResource(R.string.boldness),
stringResource(R.string.disgust),
stringResource(R.string.jealousy),
stringResource(R.string.guilt),
stringResource(R.string.embarrassment),
stringResource(R.string.disenchantment),
stringResource(R.string.stress),
stringResource(R.string.loneliness)
)
}

9
app/src/main/java/ru/asakul/feel/domain/MoodLevel.kt

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
package ru.asakul.feel.domain
enum class MoodLevel {
VERY_BAD,
BAD,
NORMAL,
GOOD,
AWESOME
}

24
app/src/main/java/ru/asakul/feel/domain/Reasons.kt

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
package ru.asakul.feel.domain
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import ru.asakul.feel.R
class Reasons {
@Composable
fun allReasons() = setOf (
stringResource(R.string.home),
stringResource(R.string.work),
stringResource(R.string.hobby),
stringResource(R.string.family),
stringResource(R.string.society),
stringResource(R.string.exercise),
stringResource(R.string.politics),
stringResource(R.string.weather),
stringResource(R.string.health),
stringResource(R.string.sleep),
stringResource(R.string.food),
stringResource(R.string.money)
)
}

13
app/src/main/java/ru/asakul/feel/navigation/FeelDestinations.kt

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
package ru.asakul.feel.navigation
interface FeelDestination {
val route: String
}
object MainScreen : FeelDestination {
override val route = "main"
}
object NewEntryScreen : FeelDestination {
override val route = "new_entry"
}

34
app/src/main/java/ru/asakul/feel/navigation/FeelNavHost.kt

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
package ru.asakul.feel.navigation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import ru.asakul.feel.ui.mood.NewMoodEntry
import ru.asakul.feel.ui.moodlist.MoodListScreen
@Composable
fun FeelNavHost (
navController: NavHostController,
modifier: Modifier = Modifier
) {
NavHost(
navController = navController,
startDestination = MainScreen.route,
modifier = modifier) {
composable (route = MainScreen.route) {
MoodListScreen(
onNewMoodEntryClick = {
navController.navigate(NewEntryScreen.route)
}
)
}
composable (route = NewEntryScreen.route) {
NewMoodEntry(onDoneClick = {
navController.navigate(MainScreen.route)
})
}
}
}

28
app/src/main/java/ru/asakul/feel/ui/MoodEntryRepr.kt

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
package ru.asakul.feel.ui
import ru.asakul.feel.data.MoodEntry
import java.sql.Timestamp
data class MoodEntryRepr(
val id : Long = 0,
val timestamp: Timestamp = Timestamp(0),
val moodLevel: Int = 0,
val emotions: List<String> = listOf(),
val reasons: List<String> = listOf(),
)
fun MoodEntryRepr.toMoodEntry(): MoodEntry = MoodEntry(
id = id,
timestamp = timestamp.time,
moodLevel = moodLevel,
emotions = emotions.joinToString (","),
reasons = reasons.joinToString (",")
)
fun MoodEntry.toMoodEntryRepr(): MoodEntryRepr = MoodEntryRepr(
id = id,
timestamp = Timestamp(timestamp),
moodLevel = moodLevel,
emotions = emotions.split(","),
reasons = reasons.split(",")
)

137
app/src/main/java/ru/asakul/feel/ui/mood/MoodEntryScreen.kt

@ -0,0 +1,137 @@ @@ -0,0 +1,137 @@
package ru.asakul.feel.ui.mood
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.InputChip
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.launch
import ru.asakul.feel.AppViewModelProvider
import ru.asakul.feel.R
import ru.asakul.feel.domain.Emotions
import ru.asakul.feel.domain.Reasons
import ru.asakul.feel.ui.mood.MoodEntryViewModel
import kotlin.collections.minus
import kotlin.collections.plus
@Composable
fun MoodLevelSelector(
modifier : Modifier = Modifier,
onMoodLevelSelected : (Int) -> Unit) {
var selectedLevel by rememberSaveable { mutableIntStateOf(0) }
Surface(modifier = modifier.padding(4.dp).background(MaterialTheme.colorScheme.primary)) {
Row(modifier = Modifier.padding(4.dp)) {
for (level in 1..5) {
if (level != selectedLevel) {
OutlinedButton(
{
onMoodLevelSelected(level)
selectedLevel = level
},
modifier = Modifier.padding(4.dp),
) { Text("$level") }
} else {
Button(
onClick = {
onMoodLevelSelected(level)
selectedLevel = level
},
modifier = Modifier.padding(4.dp),
) {
Text("$level")
}
}
}
}
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun TagSelector(
tags : Set<String>,
modifier : Modifier = Modifier,
onSelectedChange : (Set<String>) -> Unit
) {
var selectedTags by rememberSaveable { mutableStateOf(setOf<String>()) }
FlowRow (modifier = modifier) {
for (tag in tags) {
val isSelected = tag in selectedTags
InputChip(
onClick = {
if (isSelected)
selectedTags -= tag else
selectedTags += tag
onSelectedChange(selectedTags)
},
label = { Text(tag) },
selected = isSelected,
modifier = Modifier.padding(2.dp)
)
}
}
}
@Composable
fun NewMoodEntry(
onDoneClick: () -> Unit,
modifier : Modifier = Modifier,
viewModel: MoodEntryViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val coroutineScope = rememberCoroutineScope ()
Row (modifier.fillMaxWidth().padding(4.dp),
horizontalArrangement = Arrangement.Center){
Column (
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.verticalScroll(rememberScrollState())){
Text (stringResource(R.string.how_s_your_mood_right_now))
MoodLevelSelector(onMoodLevelSelected = { viewModel.updateUiState(viewModel.moodEntryState.moodEntry.copy(
moodLevel = it
))})
Text (stringResource(R.string.what_do_you_feel))
TagSelector(Emotions().allEmotions(), onSelectedChange = {
viewModel.updateUiState(viewModel.moodEntryState.moodEntry.copy(
emotions = it.toList()
))
})
Text(stringResource(R.string.why_do_you_feel_that_way))
TagSelector(Reasons().allReasons(), onSelectedChange = {
viewModel.updateUiState(viewModel.moodEntryState.moodEntry.copy(
reasons = it.toList()
))
})
Button(onClick = {
coroutineScope.launch {
viewModel.saveMoodEntry()
onDoneClick()
}
}) {
Text(stringResource(R.string.done))
}
}
}
}

30
app/src/main/java/ru/asakul/feel/ui/mood/MoodEntryViewModel.kt

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
package ru.asakul.feel.ui.mood
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import ru.asakul.feel.data.MoodEntry
import ru.asakul.feel.data.MoodEntryRepository
import ru.asakul.feel.ui.MoodEntryRepr
import ru.asakul.feel.ui.toMoodEntry
import java.sql.Timestamp
import java.time.Instant
class MoodEntryViewModel(val moodEntryRepository: MoodEntryRepository) : ViewModel() {
var moodEntryState by mutableStateOf(MoodEntryUiState(MoodEntryRepr()))
private set
fun updateUiState(moodEntryRepr: MoodEntryRepr) {
moodEntryState = MoodEntryUiState(moodEntry = moodEntryRepr)
}
suspend fun saveMoodEntry() {
moodEntryRepository.insertMoodEntry(moodEntryState.moodEntry
.toMoodEntry().copy(timestamp = Instant.now().toEpochMilli()))
}
}
data class MoodEntryUiState(
val moodEntry: MoodEntryRepr
)

204
app/src/main/java/ru/asakul/feel/ui/moodlist/MoodListScreen.kt

@ -0,0 +1,204 @@ @@ -0,0 +1,204 @@
package ru.asakul.feel.ui.moodlist
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.VerticalAlignmentLine
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.launch
import ru.asakul.feel.AppViewModelProvider
import ru.asakul.feel.R
import ru.asakul.feel.ui.MoodEntryRepr
import ru.asakul.feel.ui.theme.AppTheme
import ru.asakul.feel.ui.theme.Shapes
import java.sql.Timestamp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MoodListScreen(
onNewMoodEntryClick: () -> Unit,
modifier: Modifier = Modifier,
viewModel: MoodListScreenViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val moodListUiState by viewModel.moodEntryList.collectAsState()
val coroutineScope = rememberCoroutineScope()
Scaffold(
modifier = modifier,
floatingActionButton = {
FloatingActionButton(
onClick = onNewMoodEntryClick,
shape = MaterialTheme.shapes.medium,
modifier = Modifier
.padding(20.dp)
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringResource(R.string.add_entry)
)
}
}
) {
innerPadding ->
MoodListBody(
onDeleteClicked = {
coroutineScope.launch {
viewModel.deleteMoodEntry(it)
}
},
itemList = moodListUiState.moodEntryList,
contentPadding = innerPadding)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MoodListBody(
onDeleteClicked: (Long) -> Unit,
contentPadding: PaddingValues,
itemList: List<MoodEntryRepr>,
modifier: Modifier = Modifier) {
val listState = rememberLazyListState()
LazyColumn(
state = listState,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
items(items = itemList, key = { it.id }) { item ->
MoodListItem(
onDeleteClicked = onDeleteClicked,
item = item)
}
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun MoodListItem(
onDeleteClicked: (Long) -> Unit,
item: MoodEntryRepr,
modifier: Modifier = Modifier) {
Column(
modifier = modifier.padding(5.dp)
) {
Row(
modifier = Modifier.fillMaxWidth()
) {
Card(
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
border = BorderStroke(1.dp, Color.White),
modifier = Modifier.padding(1.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Row (modifier = Modifier.padding(10.dp),
verticalAlignment = Alignment.CenterVertically) {
Text(item.timestamp.toString(), style = MaterialTheme.typography.titleLarge)
Spacer(Modifier.weight(1f))
Text("${item.moodLevel}", style = MaterialTheme.typography.titleLarge)
IconButton(onClick = {onDeleteClicked(item.id)},
modifier = Modifier.width(32.dp)){
Icon(
imageVector = Icons.Default.Delete,
contentDescription = stringResource(R.string.delete_entry)
)
}
}
Row {
FlowRow(modifier = Modifier.padding(12.dp)) {
for (emotion in item.emotions) {
TagItem(
text = emotion,
color = MaterialTheme.colorScheme.tertiaryContainer
)
}
for (reason in item.reasons) {
TagItem(
text = reason,
color = MaterialTheme.colorScheme.primaryContainer
)
}
}
}
}
}
}
}
@Composable
fun TagItem(
modifier: Modifier = Modifier,
text: String,
color: Color) {
Surface (
shape = MaterialTheme.shapes.small,
modifier = modifier.padding(2.dp),
color = color,
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline)
) {
Text(text, modifier =
Modifier.padding(3.dp)
)
}
}
@Preview(showBackground = true)
@Composable
fun MoodListPreview() {
AppTheme {
MoodListBody(
onDeleteClicked = {},
contentPadding = PaddingValues(2.dp),
itemList = listOf(
MoodEntryRepr(
0,
Timestamp(12),
4,
listOf("Foo", "Bar"),
listOf("Bax", "Banana")
)
)
)
}
}

32
app/src/main/java/ru/asakul/feel/ui/moodlist/MoodListScreenViewModel.kt

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
package ru.asakul.feel.ui.moodlist
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import ru.asakul.feel.data.MoodEntryRepository
import ru.asakul.feel.ui.MoodEntryRepr
import ru.asakul.feel.ui.toMoodEntryRepr
class MoodListScreenViewModel(val moodEntryRepository: MoodEntryRepository) : ViewModel() {
val moodEntryList : StateFlow<MoodListScreenUiState> = moodEntryRepository
.getAllMoodEntriesStream().map {
MoodListScreenUiState(it.map { me -> me.toMoodEntryRepr() })
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = MoodListScreenUiState()
)
suspend fun deleteMoodEntry(id: Long) {
val item = moodEntryRepository.getMoodEntryStream(id).first()
if (item != null) {
moodEntryRepository.deleteMoodEntry(item)
}
}
}
data class MoodListScreenUiState(val moodEntryList: List<MoodEntryRepr> = listOf())

225
app/src/main/java/ru/asakul/feel/ui/theme/Color.kt

@ -0,0 +1,225 @@ @@ -0,0 +1,225 @@
package ru.asakul.feel.ui.theme
import androidx.compose.ui.graphics.Color
val primaryLight = Color(0xFF4E5B92)
val onPrimaryLight = Color(0xFFFFFFFF)
val primaryContainerLight = Color(0xFFDDE1FF)
val onPrimaryContainerLight = Color(0xFF364379)
val secondaryLight = Color(0xFF36693E)
val onSecondaryLight = Color(0xFFFFFFFF)
val secondaryContainerLight = Color(0xFFB7F1B9)
val onSecondaryContainerLight = Color(0xFF1D5128)
val tertiaryLight = Color(0xFF75546F)
val onTertiaryLight = Color(0xFFFFFFFF)
val tertiaryContainerLight = Color(0xFFFFD7F4)
val onTertiaryContainerLight = Color(0xFF5C3D56)
val errorLight = Color(0xFFBA1A1A)
val onErrorLight = Color(0xFFFFFFFF)
val errorContainerLight = Color(0xFFFFDAD6)
val onErrorContainerLight = Color(0xFF93000A)
val backgroundLight = Color(0xFFFBF8FF)
val onBackgroundLight = Color(0xFF1A1B21)
val surfaceLight = Color(0xFFFBF8FF)
val onSurfaceLight = Color(0xFF1A1B21)
val surfaceVariantLight = Color(0xFFE2E1EC)
val onSurfaceVariantLight = Color(0xFF45464F)
val outlineLight = Color(0xFF767680)
val outlineVariantLight = Color(0xFFC6C5D0)
val scrimLight = Color(0xFF000000)
val inverseSurfaceLight = Color(0xFF2F3036)
val inverseOnSurfaceLight = Color(0xFFF2F0F7)
val inversePrimaryLight = Color(0xFFB8C4FF)
val surfaceDimLight = Color(0xFFDBD9E0)
val surfaceBrightLight = Color(0xFFFBF8FF)
val surfaceContainerLowestLight = Color(0xFFFFFFFF)
val surfaceContainerLowLight = Color(0xFFF4F2FA)
val surfaceContainerLight = Color(0xFFEFEDF4)
val surfaceContainerHighLight = Color(0xFFE9E7EF)
val surfaceContainerHighestLight = Color(0xFFE3E1E9)
val primaryLightMediumContrast = Color(0xFF253267)
val onPrimaryLightMediumContrast = Color(0xFFFFFFFF)
val primaryContainerLightMediumContrast = Color(0xFF5D6AA2)
val onPrimaryContainerLightMediumContrast = Color(0xFFFFFFFF)
val secondaryLightMediumContrast = Color(0xFF083F19)
val onSecondaryLightMediumContrast = Color(0xFFFFFFFF)
val secondaryContainerLightMediumContrast = Color(0xFF45784B)
val onSecondaryContainerLightMediumContrast = Color(0xFFFFFFFF)
val tertiaryLightMediumContrast = Color(0xFF4A2C45)
val onTertiaryLightMediumContrast = Color(0xFFFFFFFF)
val tertiaryContainerLightMediumContrast = Color(0xFF85627E)
val onTertiaryContainerLightMediumContrast = Color(0xFFFFFFFF)
val errorLightMediumContrast = Color(0xFF740006)
val onErrorLightMediumContrast = Color(0xFFFFFFFF)
val errorContainerLightMediumContrast = Color(0xFFCF2C27)
val onErrorContainerLightMediumContrast = Color(0xFFFFFFFF)
val backgroundLightMediumContrast = Color(0xFFFBF8FF)
val onBackgroundLightMediumContrast = Color(0xFF1A1B21)
val surfaceLightMediumContrast = Color(0xFFFBF8FF)
val onSurfaceLightMediumContrast = Color(0xFF101116)
val surfaceVariantLightMediumContrast = Color(0xFFE2E1EC)
val onSurfaceVariantLightMediumContrast = Color(0xFF35363E)
val outlineLightMediumContrast = Color(0xFF51525B)
val outlineVariantLightMediumContrast = Color(0xFF6C6C76)
val scrimLightMediumContrast = Color(0xFF000000)
val inverseSurfaceLightMediumContrast = Color(0xFF2F3036)
val inverseOnSurfaceLightMediumContrast = Color(0xFFF2F0F7)
val inversePrimaryLightMediumContrast = Color(0xFFB8C4FF)
val surfaceDimLightMediumContrast = Color(0xFFC7C5CD)
val surfaceBrightLightMediumContrast = Color(0xFFFBF8FF)
val surfaceContainerLowestLightMediumContrast = Color(0xFFFFFFFF)
val surfaceContainerLowLightMediumContrast = Color(0xFFF4F2FA)
val surfaceContainerLightMediumContrast = Color(0xFFE9E7EF)
val surfaceContainerHighLightMediumContrast = Color(0xFFDDDCE3)
val surfaceContainerHighestLightMediumContrast = Color(0xFFD2D1D8)
val primaryLightHighContrast = Color(0xFF1A285C)
val onPrimaryLightHighContrast = Color(0xFFFFFFFF)
val primaryContainerLightHighContrast = Color(0xFF39467B)
val onPrimaryContainerLightHighContrast = Color(0xFFFFFFFF)
val secondaryLightHighContrast = Color(0xFF003411)
val onSecondaryLightHighContrast = Color(0xFFFFFFFF)
val secondaryContainerLightHighContrast = Color(0xFF20532A)
val onSecondaryContainerLightHighContrast = Color(0xFFFFFFFF)
val tertiaryLightHighContrast = Color(0xFF3F223A)
val onTertiaryLightHighContrast = Color(0xFFFFFFFF)
val tertiaryContainerLightHighContrast = Color(0xFF5E3F59)
val onTertiaryContainerLightHighContrast = Color(0xFFFFFFFF)
val errorLightHighContrast = Color(0xFF600004)
val onErrorLightHighContrast = Color(0xFFFFFFFF)
val errorContainerLightHighContrast = Color(0xFF98000A)
val onErrorContainerLightHighContrast = Color(0xFFFFFFFF)
val backgroundLightHighContrast = Color(0xFFFBF8FF)
val onBackgroundLightHighContrast = Color(0xFF1A1B21)
val surfaceLightHighContrast = Color(0xFFFBF8FF)
val onSurfaceLightHighContrast = Color(0xFF000000)
val surfaceVariantLightHighContrast = Color(0xFFE2E1EC)
val onSurfaceVariantLightHighContrast = Color(0xFF000000)
val outlineLightHighContrast = Color(0xFF2A2C34)
val outlineVariantLightHighContrast = Color(0xFF484951)
val scrimLightHighContrast = Color(0xFF000000)
val inverseSurfaceLightHighContrast = Color(0xFF2F3036)
val inverseOnSurfaceLightHighContrast = Color(0xFFFFFFFF)
val inversePrimaryLightHighContrast = Color(0xFFB8C4FF)
val surfaceDimLightHighContrast = Color(0xFFB9B8BF)
val surfaceBrightLightHighContrast = Color(0xFFFBF8FF)
val surfaceContainerLowestLightHighContrast = Color(0xFFFFFFFF)
val surfaceContainerLowLightHighContrast = Color(0xFFF2F0F7)
val surfaceContainerLightHighContrast = Color(0xFFE3E1E9)
val surfaceContainerHighLightHighContrast = Color(0xFFD5D3DB)
val surfaceContainerHighestLightHighContrast = Color(0xFFC7C5CD)
val primaryDark = Color(0xFFB8C4FF)
val onPrimaryDark = Color(0xFF1F2D61)
val primaryContainerDark = Color(0xFF364379)
val onPrimaryContainerDark = Color(0xFFDDE1FF)
val secondaryDark = Color(0xFF9CD49F)
val onSecondaryDark = Color(0xFF003913)
val secondaryContainerDark = Color(0xFF1D5128)
val onSecondaryContainerDark = Color(0xFFB7F1B9)
val tertiaryDark = Color(0xFFE4BAD9)
val onTertiaryDark = Color(0xFF43273F)
val tertiaryContainerDark = Color(0xFF5C3D56)
val onTertiaryContainerDark = Color(0xFFFFD7F4)
val errorDark = Color(0xFFFFB4AB)
val onErrorDark = Color(0xFF690005)
val errorContainerDark = Color(0xFF93000A)
val onErrorContainerDark = Color(0xFFFFDAD6)
val backgroundDark = Color(0xFF121318)
val onBackgroundDark = Color(0xFFE3E1E9)
val surfaceDark = Color(0xFF121318)
val onSurfaceDark = Color(0xFFE3E1E9)
val surfaceVariantDark = Color(0xFF45464F)
val onSurfaceVariantDark = Color(0xFFC6C5D0)
val outlineDark = Color(0xFF90909A)
val outlineVariantDark = Color(0xFF45464F)
val scrimDark = Color(0xFF000000)
val inverseSurfaceDark = Color(0xFFE3E1E9)
val inverseOnSurfaceDark = Color(0xFF2F3036)
val inversePrimaryDark = Color(0xFF4E5B92)
val surfaceDimDark = Color(0xFF121318)
val surfaceBrightDark = Color(0xFF38393F)
val surfaceContainerLowestDark = Color(0xFF0D0E13)
val surfaceContainerLowDark = Color(0xFF1A1B21)
val surfaceContainerDark = Color(0xFF1F1F25)
val surfaceContainerHighDark = Color(0xFF292A2F)
val surfaceContainerHighestDark = Color(0xFF34343A)
val primaryDarkMediumContrast = Color(0xFFD5DAFF)
val onPrimaryDarkMediumContrast = Color(0xFF132155)
val primaryContainerDarkMediumContrast = Color(0xFF818EC8)
val onPrimaryContainerDarkMediumContrast = Color(0xFF000000)
val secondaryDarkMediumContrast = Color(0xFFB1EAB3)
val onSecondaryDarkMediumContrast = Color(0xFF002D0D)
val secondaryContainerDarkMediumContrast = Color(0xFF689D6C)
val onSecondaryContainerDarkMediumContrast = Color(0xFF000000)
val tertiaryDarkMediumContrast = Color(0xFFFBD0EF)
val onTertiaryDarkMediumContrast = Color(0xFF381C34)
val tertiaryContainerDarkMediumContrast = Color(0xFFAB85A2)
val onTertiaryContainerDarkMediumContrast = Color(0xFF000000)
val errorDarkMediumContrast = Color(0xFFFFD2CC)
val onErrorDarkMediumContrast = Color(0xFF540003)
val errorContainerDarkMediumContrast = Color(0xFFFF5449)
val onErrorContainerDarkMediumContrast = Color(0xFF000000)
val backgroundDarkMediumContrast = Color(0xFF121318)
val onBackgroundDarkMediumContrast = Color(0xFFE3E1E9)
val surfaceDarkMediumContrast = Color(0xFF121318)
val onSurfaceDarkMediumContrast = Color(0xFFFFFFFF)
val surfaceVariantDarkMediumContrast = Color(0xFF45464F)
val onSurfaceVariantDarkMediumContrast = Color(0xFFDCDBE6)
val outlineDarkMediumContrast = Color(0xFFB1B1BB)
val outlineVariantDarkMediumContrast = Color(0xFF8F8F99)
val scrimDarkMediumContrast = Color(0xFF000000)
val inverseSurfaceDarkMediumContrast = Color(0xFFE3E1E9)
val inverseOnSurfaceDarkMediumContrast = Color(0xFF292A2F)
val inversePrimaryDarkMediumContrast = Color(0xFF38457A)
val surfaceDimDarkMediumContrast = Color(0xFF121318)
val surfaceBrightDarkMediumContrast = Color(0xFF44444A)
val surfaceContainerLowestDarkMediumContrast = Color(0xFF06070C)
val surfaceContainerLowDarkMediumContrast = Color(0xFF1D1D23)
val surfaceContainerDarkMediumContrast = Color(0xFF27272D)
val surfaceContainerHighDarkMediumContrast = Color(0xFF323238)
val surfaceContainerHighestDarkMediumContrast = Color(0xFF3D3D43)
val primaryDarkHighContrast = Color(0xFFEEEFFF)
val onPrimaryDarkHighContrast = Color(0xFF000000)
val primaryContainerDarkHighContrast = Color(0xFFB3C0FD)
val onPrimaryContainerDarkHighContrast = Color(0xFF00072D)
val secondaryDarkHighContrast = Color(0xFFC5FEC6)
val onSecondaryDarkHighContrast = Color(0xFF000000)
val secondaryContainerDarkHighContrast = Color(0xFF98D09B)
val onSecondaryContainerDarkHighContrast = Color(0xFF000F02)
val tertiaryDarkHighContrast = Color(0xFFFFEAF7)
val onTertiaryDarkHighContrast = Color(0xFF000000)
val tertiaryContainerDarkHighContrast = Color(0xFFE0B6D5)
val onTertiaryContainerDarkHighContrast = Color(0xFF190318)
val errorDarkHighContrast = Color(0xFFFFECE9)
val onErrorDarkHighContrast = Color(0xFF000000)
val errorContainerDarkHighContrast = Color(0xFFFFAEA4)
val onErrorContainerDarkHighContrast = Color(0xFF220001)
val backgroundDarkHighContrast = Color(0xFF121318)
val onBackgroundDarkHighContrast = Color(0xFFE3E1E9)
val surfaceDarkHighContrast = Color(0xFF121318)
val onSurfaceDarkHighContrast = Color(0xFFFFFFFF)
val surfaceVariantDarkHighContrast = Color(0xFF45464F)
val onSurfaceVariantDarkHighContrast = Color(0xFFFFFFFF)
val outlineDarkHighContrast = Color(0xFFF0EFFA)
val outlineVariantDarkHighContrast = Color(0xFFC2C2CC)
val scrimDarkHighContrast = Color(0xFF000000)
val inverseSurfaceDarkHighContrast = Color(0xFFE3E1E9)
val inverseOnSurfaceDarkHighContrast = Color(0xFF000000)
val inversePrimaryDarkHighContrast = Color(0xFF38457A)
val surfaceDimDarkHighContrast = Color(0xFF121318)
val surfaceBrightDarkHighContrast = Color(0xFF4F4F56)
val surfaceContainerLowestDarkHighContrast = Color(0xFF000000)
val surfaceContainerLowDarkHighContrast = Color(0xFF1F1F25)
val surfaceContainerDarkHighContrast = Color(0xFF2F3036)
val surfaceContainerHighDarkHighContrast = Color(0xFF3B3B41)
val surfaceContainerHighestDarkHighContrast = Color(0xFF46464C)

12
app/src/main/java/ru/asakul/feel/ui/theme/Shapes.kt

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
package ru.asakul.feel.ui.theme
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp
val Shapes = Shapes(
extraSmall = CutCornerShape(topEnd = 8.dp, bottomStart = 8.dp),
small = CutCornerShape(topEnd = 8.dp, bottomStart = 8.dp),
medium = CutCornerShape(topEnd = 16.dp, bottomStart = 16.dp)
)

282
app/src/main/java/ru/asakul/feel/ui/theme/Theme.kt

@ -0,0 +1,282 @@ @@ -0,0 +1,282 @@
package ru.asakul.feel.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.Typography
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import ru.asakul.feel.ui.theme.AppTypography
private val lightScheme = lightColorScheme(
primary = primaryLight,
onPrimary = onPrimaryLight,
primaryContainer = primaryContainerLight,
onPrimaryContainer = onPrimaryContainerLight,
secondary = secondaryLight,
onSecondary = onSecondaryLight,
secondaryContainer = secondaryContainerLight,
onSecondaryContainer = onSecondaryContainerLight,
tertiary = tertiaryLight,
onTertiary = onTertiaryLight,
tertiaryContainer = tertiaryContainerLight,
onTertiaryContainer = onTertiaryContainerLight,
error = errorLight,
onError = onErrorLight,
errorContainer = errorContainerLight,
onErrorContainer = onErrorContainerLight,
background = backgroundLight,
onBackground = onBackgroundLight,
surface = surfaceLight,
onSurface = onSurfaceLight,
surfaceVariant = surfaceVariantLight,
onSurfaceVariant = onSurfaceVariantLight,
outline = outlineLight,
outlineVariant = outlineVariantLight,
scrim = scrimLight,
inverseSurface = inverseSurfaceLight,
inverseOnSurface = inverseOnSurfaceLight,
inversePrimary = inversePrimaryLight,
surfaceDim = surfaceDimLight,
surfaceBright = surfaceBrightLight,
surfaceContainerLowest = surfaceContainerLowestLight,
surfaceContainerLow = surfaceContainerLowLight,
surfaceContainer = surfaceContainerLight,
surfaceContainerHigh = surfaceContainerHighLight,
surfaceContainerHighest = surfaceContainerHighestLight,
)
private val darkScheme = darkColorScheme(
primary = primaryDark,
onPrimary = onPrimaryDark,
primaryContainer = primaryContainerDark,
onPrimaryContainer = onPrimaryContainerDark,
secondary = secondaryDark,
onSecondary = onSecondaryDark,
secondaryContainer = secondaryContainerDark,
onSecondaryContainer = onSecondaryContainerDark,
tertiary = tertiaryDark,
onTertiary = onTertiaryDark,
tertiaryContainer = tertiaryContainerDark,
onTertiaryContainer = onTertiaryContainerDark,
error = errorDark,
onError = onErrorDark,
errorContainer = errorContainerDark,
onErrorContainer = onErrorContainerDark,
background = backgroundDark,
onBackground = onBackgroundDark,
surface = surfaceDark,
onSurface = onSurfaceDark,
surfaceVariant = surfaceVariantDark,
onSurfaceVariant = onSurfaceVariantDark,
outline = outlineDark,
outlineVariant = outlineVariantDark,
scrim = scrimDark,
inverseSurface = inverseSurfaceDark,
inverseOnSurface = inverseOnSurfaceDark,
inversePrimary = inversePrimaryDark,
surfaceDim = surfaceDimDark,
surfaceBright = surfaceBrightDark,
surfaceContainerLowest = surfaceContainerLowestDark,
surfaceContainerLow = surfaceContainerLowDark,
surfaceContainer = surfaceContainerDark,
surfaceContainerHigh = surfaceContainerHighDark,
surfaceContainerHighest = surfaceContainerHighestDark,
)
private val mediumContrastLightColorScheme = lightColorScheme(
primary = primaryLightMediumContrast,
onPrimary = onPrimaryLightMediumContrast,
primaryContainer = primaryContainerLightMediumContrast,
onPrimaryContainer = onPrimaryContainerLightMediumContrast,
secondary = secondaryLightMediumContrast,
onSecondary = onSecondaryLightMediumContrast,
secondaryContainer = secondaryContainerLightMediumContrast,
onSecondaryContainer = onSecondaryContainerLightMediumContrast,
tertiary = tertiaryLightMediumContrast,
onTertiary = onTertiaryLightMediumContrast,
tertiaryContainer = tertiaryContainerLightMediumContrast,
onTertiaryContainer = onTertiaryContainerLightMediumContrast,
error = errorLightMediumContrast,
onError = onErrorLightMediumContrast,
errorContainer = errorContainerLightMediumContrast,
onErrorContainer = onErrorContainerLightMediumContrast,
background = backgroundLightMediumContrast,
onBackground = onBackgroundLightMediumContrast,
surface = surfaceLightMediumContrast,
onSurface = onSurfaceLightMediumContrast,
surfaceVariant = surfaceVariantLightMediumContrast,
onSurfaceVariant = onSurfaceVariantLightMediumContrast,
outline = outlineLightMediumContrast,
outlineVariant = outlineVariantLightMediumContrast,
scrim = scrimLightMediumContrast,
inverseSurface = inverseSurfaceLightMediumContrast,
inverseOnSurface = inverseOnSurfaceLightMediumContrast,
inversePrimary = inversePrimaryLightMediumContrast,
surfaceDim = surfaceDimLightMediumContrast,
surfaceBright = surfaceBrightLightMediumContrast,
surfaceContainerLowest = surfaceContainerLowestLightMediumContrast,
surfaceContainerLow = surfaceContainerLowLightMediumContrast,
surfaceContainer = surfaceContainerLightMediumContrast,
surfaceContainerHigh = surfaceContainerHighLightMediumContrast,
surfaceContainerHighest = surfaceContainerHighestLightMediumContrast,
)
private val highContrastLightColorScheme = lightColorScheme(
primary = primaryLightHighContrast,
onPrimary = onPrimaryLightHighContrast,
primaryContainer = primaryContainerLightHighContrast,
onPrimaryContainer = onPrimaryContainerLightHighContrast,
secondary = secondaryLightHighContrast,
onSecondary = onSecondaryLightHighContrast,
secondaryContainer = secondaryContainerLightHighContrast,
onSecondaryContainer = onSecondaryContainerLightHighContrast,
tertiary = tertiaryLightHighContrast,
onTertiary = onTertiaryLightHighContrast,
tertiaryContainer = tertiaryContainerLightHighContrast,
onTertiaryContainer = onTertiaryContainerLightHighContrast,
error = errorLightHighContrast,
onError = onErrorLightHighContrast,
errorContainer = errorContainerLightHighContrast,
onErrorContainer = onErrorContainerLightHighContrast,
background = backgroundLightHighContrast,
onBackground = onBackgroundLightHighContrast,
surface = surfaceLightHighContrast,
onSurface = onSurfaceLightHighContrast,
surfaceVariant = surfaceVariantLightHighContrast,
onSurfaceVariant = onSurfaceVariantLightHighContrast,
outline = outlineLightHighContrast,
outlineVariant = outlineVariantLightHighContrast,
scrim = scrimLightHighContrast,
inverseSurface = inverseSurfaceLightHighContrast,
inverseOnSurface = inverseOnSurfaceLightHighContrast,
inversePrimary = inversePrimaryLightHighContrast,
surfaceDim = surfaceDimLightHighContrast,
surfaceBright = surfaceBrightLightHighContrast,
surfaceContainerLowest = surfaceContainerLowestLightHighContrast,
surfaceContainerLow = surfaceContainerLowLightHighContrast,
surfaceContainer = surfaceContainerLightHighContrast,
surfaceContainerHigh = surfaceContainerHighLightHighContrast,
surfaceContainerHighest = surfaceContainerHighestLightHighContrast,
)
private val mediumContrastDarkColorScheme = darkColorScheme(
primary = primaryDarkMediumContrast,
onPrimary = onPrimaryDarkMediumContrast,
primaryContainer = primaryContainerDarkMediumContrast,
onPrimaryContainer = onPrimaryContainerDarkMediumContrast,
secondary = secondaryDarkMediumContrast,
onSecondary = onSecondaryDarkMediumContrast,
secondaryContainer = secondaryContainerDarkMediumContrast,
onSecondaryContainer = onSecondaryContainerDarkMediumContrast,
tertiary = tertiaryDarkMediumContrast,
onTertiary = onTertiaryDarkMediumContrast,
tertiaryContainer = tertiaryContainerDarkMediumContrast,
onTertiaryContainer = onTertiaryContainerDarkMediumContrast,
error = errorDarkMediumContrast,
onError = onErrorDarkMediumContrast,
errorContainer = errorContainerDarkMediumContrast,
onErrorContainer = onErrorContainerDarkMediumContrast,
background = backgroundDarkMediumContrast,
onBackground = onBackgroundDarkMediumContrast,
surface = surfaceDarkMediumContrast,
onSurface = onSurfaceDarkMediumContrast,
surfaceVariant = surfaceVariantDarkMediumContrast,
onSurfaceVariant = onSurfaceVariantDarkMediumContrast,
outline = outlineDarkMediumContrast,
outlineVariant = outlineVariantDarkMediumContrast,
scrim = scrimDarkMediumContrast,
inverseSurface = inverseSurfaceDarkMediumContrast,
inverseOnSurface = inverseOnSurfaceDarkMediumContrast,
inversePrimary = inversePrimaryDarkMediumContrast,
surfaceDim = surfaceDimDarkMediumContrast,
surfaceBright = surfaceBrightDarkMediumContrast,
surfaceContainerLowest = surfaceContainerLowestDarkMediumContrast,
surfaceContainerLow = surfaceContainerLowDarkMediumContrast,
surfaceContainer = surfaceContainerDarkMediumContrast,
surfaceContainerHigh = surfaceContainerHighDarkMediumContrast,
surfaceContainerHighest = surfaceContainerHighestDarkMediumContrast,
)
private val highContrastDarkColorScheme = darkColorScheme(
primary = primaryDarkHighContrast,
onPrimary = onPrimaryDarkHighContrast,
primaryContainer = primaryContainerDarkHighContrast,
onPrimaryContainer = onPrimaryContainerDarkHighContrast,
secondary = secondaryDarkHighContrast,
onSecondary = onSecondaryDarkHighContrast,
secondaryContainer = secondaryContainerDarkHighContrast,
onSecondaryContainer = onSecondaryContainerDarkHighContrast,
tertiary = tertiaryDarkHighContrast,
onTertiary = onTertiaryDarkHighContrast,
tertiaryContainer = tertiaryContainerDarkHighContrast,
onTertiaryContainer = onTertiaryContainerDarkHighContrast,
error = errorDarkHighContrast,
onError = onErrorDarkHighContrast,
errorContainer = errorContainerDarkHighContrast,
onErrorContainer = onErrorContainerDarkHighContrast,
background = backgroundDarkHighContrast,
onBackground = onBackgroundDarkHighContrast,
surface = surfaceDarkHighContrast,
onSurface = onSurfaceDarkHighContrast,
surfaceVariant = surfaceVariantDarkHighContrast,
onSurfaceVariant = onSurfaceVariantDarkHighContrast,
outline = outlineDarkHighContrast,
outlineVariant = outlineVariantDarkHighContrast,
scrim = scrimDarkHighContrast,
inverseSurface = inverseSurfaceDarkHighContrast,
inverseOnSurface = inverseOnSurfaceDarkHighContrast,
inversePrimary = inversePrimaryDarkHighContrast,
surfaceDim = surfaceDimDarkHighContrast,
surfaceBright = surfaceBrightDarkHighContrast,
surfaceContainerLowest = surfaceContainerLowestDarkHighContrast,
surfaceContainerLow = surfaceContainerLowDarkHighContrast,
surfaceContainer = surfaceContainerDarkHighContrast,
surfaceContainerHigh = surfaceContainerHighDarkHighContrast,
surfaceContainerHighest = surfaceContainerHighestDarkHighContrast,
)
@Immutable
data class ColorFamily(
val color: Color,
val onColor: Color,
val colorContainer: Color,
val onColorContainer: Color
)
val unspecified_scheme = ColorFamily(
Color.Unspecified, Color.Unspecified, Color.Unspecified, Color.Unspecified
)
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable() () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> darkScheme
else -> lightScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = AppTypography,
content = content,
shapes = Shapes
)
}

5
app/src/main/java/ru/asakul/feel/ui/theme/Type.kt

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
package ru.asakul.feel.ui.theme
import androidx.compose.material3.Typography
val AppTypography = Typography()

170
app/src/main/res/drawable/ic_launcher_background.xml

@ -0,0 +1,170 @@ @@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

30
app/src/main/res/drawable/ic_launcher_foreground.xml

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

6
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

6
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
app/src/main/res/mipmap-mdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

53
app/src/main/res/values-ru/strings.xml

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Feel</string>
<string name="how_s_your_mood_right_now">Как твое настроение сейчас?</string>
<string name="what_do_you_feel">Что ты чувствуешь?</string>
<string name="why_do_you_feel_that_way">Почему ты это чувствуешь?</string>
<string name="happiness">Счастье</string>
<string name="elation">Восторг</string>
<string name="calmness">Спокойствие</string>
<string name="done">Готово</string>
<string name="tranquility">Спокойствие</string>
<string name="gratitude">Благодарность</string>
<string name="surprise">Удивление</string>
<string name="fatigue">Усталость</string>
<string name="exhaustion">Истощение</string>
<string name="anger">Гнев</string>
<string name="sadness">Грусть</string>
<string name="fear">Страх</string>
<string name="panic">Паника</string>
<string name="irritation">Разрдражение</string>
<string name="apathy">Апатия</string>
<string name="hope">Надежда</string>
<string name="relief">Облегчение</string>
<string name="confidence">Уверенность</string>
<string name="satisfaction">Удовлетворение</string>
<string name="joy">Радость</string>
<string name="enthusiasm">Энтузиазм</string>
<string name="pride">Гордость</string>
<string name="anxiety">Беспокойство</string>
<string name="nervousness">Нервозность</string>
<string name="boldness">Смелость</string>
<string name="disgust">Отвращение</string>
<string name="jealousy">Ревность</string>
<string name="guilt">Вина</string>
<string name="embarrassment">Смущение</string>
<string name="disenchantment">Разочарование</string>
<string name="stress">Стресс</string>
<string name="loneliness">Одиночество</string>
<string name="home">Дом</string>
<string name="work">Работа</string>
<string name="hobby">Хобби</string>
<string name="family">Семья</string>
<string name="society">Общество</string>
<string name="exercise">Упражнения</string>
<string name="politics">Политика</string>
<string name="weather">Погода</string>
<string name="health">Здоровье</string>
<string name="sleep">Сон</string>
<string name="food">Еда</string>
<string name="money">Деньги</string>
<string name="add_entry">Add entry</string>
<string name="delete_entry">Delete entry</string>
</resources>

10
app/src/main/res/values/colors.xml

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

52
app/src/main/res/values/strings.xml

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
<resources>
<string name="app_name">Feel</string>
<string name="how_s_your_mood_right_now">How\'s your mood right now?</string>
<string name="what_do_you_feel">What do you feel?</string>
<string name="why_do_you_feel_that_way">Why do you feel that way?</string>
<string name="happiness">Happiness</string>
<string name="elation">Elation</string>
<string name="calmness">Calmness</string>
<string name="done">Done</string>
<string name="tranquility">Tranquility</string>
<string name="gratitude">Gratitude</string>
<string name="surprise">Surprise</string>
<string name="fatigue">Fatigue</string>
<string name="exhaustion">Exhaustion</string>
<string name="anger">Anger</string>
<string name="sadness">Sadness</string>
<string name="fear">Fear</string>
<string name="panic">Panic</string>
<string name="irritation">Irritation</string>
<string name="apathy">Apathy</string>
<string name="hope">Hope</string>
<string name="relief">Relief</string>
<string name="confidence">Confidence</string>
<string name="satisfaction">Satisfaction</string>
<string name="joy">Joy</string>
<string name="enthusiasm">Enthusiasm</string>
<string name="pride">Pride</string>
<string name="anxiety">Anxiety</string>
<string name="nervousness">Nervousness</string>
<string name="boldness">Boldness</string>
<string name="disgust">Disgust</string>
<string name="jealousy">Jealousy</string>
<string name="guilt">Guilt</string>
<string name="embarrassment">Embarrassment</string>
<string name="disenchantment">Disenchantment</string>
<string name="stress">Stress</string>
<string name="loneliness">Loneliness</string>
<string name="home">Home</string>
<string name="work">Work</string>
<string name="hobby">Hobby</string>
<string name="family">Family</string>
<string name="society">Society</string>
<string name="exercise">Exercise</string>
<string name="politics">Politics</string>
<string name="weather">Weather</string>
<string name="health">Health</string>
<string name="sleep">Sleep</string>
<string name="food">Food</string>
<string name="money">Money</string>
<string name="add_entry">Add entry</string>
<string name="delete_entry">Delete entry</string>
</resources>

5
app/src/main/res/values/themes.xml

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Feel" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

13
app/src/main/res/xml/backup_rules.xml

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older than API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

19
app/src/main/res/xml/data_extraction_rules.xml

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

17
app/src/test/java/ru/asakul/feel/ExampleUnitTest.kt

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
package ru.asakul.feel
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
Loading…
Cancel
Save