@ -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")) |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -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 |
||||||
@ -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) |
||||||
|
} |
||||||
|
} |
||||||
@ -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> |
||||||
@ -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) |
||||||
@ -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) |
||||||
|
} |
||||||
|
} |
||||||
@ -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() |
||||||
|
} |
||||||
|
} |
||||||
@ -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()) |
||||||
|
} |
||||||
|
} |
||||||
@ -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 |
||||||
|
) |
||||||
@ -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>> |
||||||
|
} |
||||||
@ -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 } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -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) |
||||||
|
} |
||||||
@ -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) |
||||||
|
} |
||||||
@ -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) |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
package ru.asakul.feel.domain |
||||||
|
|
||||||
|
enum class MoodLevel { |
||||||
|
VERY_BAD, |
||||||
|
BAD, |
||||||
|
NORMAL, |
||||||
|
GOOD, |
||||||
|
AWESOME |
||||||
|
} |
||||||
@ -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) |
||||||
|
) |
||||||
|
} |
||||||
@ -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" |
||||||
|
} |
||||||
@ -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) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -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(",") |
||||||
|
) |
||||||
@ -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)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -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 |
||||||
|
) |
||||||
@ -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") |
||||||
|
) |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
@ -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()) |
||||||
@ -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) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -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) |
||||||
|
) |
||||||
@ -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 |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,5 @@ |
|||||||
|
package ru.asakul.feel.ui.theme |
||||||
|
|
||||||
|
import androidx.compose.material3.Typography |
||||||
|
|
||||||
|
val AppTypography = Typography() |
||||||
@ -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> |
||||||
@ -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> |
||||||
@ -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> |
||||||
@ -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> |
||||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 982 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
@ -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> |
||||||
@ -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> |
||||||
@ -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> |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<style name="Theme.Feel" parent="android:Theme.Material.Light.NoActionBar" /> |
||||||
|
</resources> |
||||||
@ -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> |
||||||
@ -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> |
||||||
@ -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) |
||||||
|
} |
||||||
|
} |
||||||