Compare commits

..

44 commits

Author SHA1 Message Date
8dc75190b5 Merge pull request 'ver. e1.0.0.b7' (#10) from testtesttest into ophelia_mainline
Reviewed-on: #10
2023-11-11 16:23:07 -05:00
e08986e8c1 ver bump 2023-11-11 16:22:31 -05:00
3d8451b8cf Cherry Pick Patch 3 2023-11-11 15:29:13 -05:00
956095e513 Cherry Pick Patch 1 2023-11-10 22:55:47 -05:00
11913f3f2e Cherry Pick Patch 1 2023-11-07 21:26:05 -05:00
3a8209433f Add Edit working 2023-11-01 20:16:00 -04:00
235a9c400b hooray 2023-10-31 21:24:30 -04:00
6261f2da31 Check state buttons that *finally* fucking work 2023-10-31 18:54:14 -04:00
847b8072c7 Add edit 2023-10-28 23:18:22 -04:00
0dadceb1b8 working on it 2023-10-28 18:01:34 -04:00
05822226af fuck that took way too long 2023-10-28 17:33:06 -04:00
1b43a34586 Tags Added 2023-10-28 15:21:20 -04:00
70468fbb4b tags screen 2023-10-27 23:57:55 -04:00
c92e657038 Add edit 2023-10-23 23:14:11 -04:00
1f3c59c407 Push 2023-10-23 22:07:47 -04:00
25a73f0970 Push 2023-10-23 00:16:10 -04:00
dcc1cb3010 Add edit 2023-10-22 22:25:07 -04:00
7ee1d54964 Push 2023-10-22 17:50:27 -04:00
6eded27a9e Start Pathing 2023-10-21 18:16:05 -04:00
2080658c4d Start Pathing 2023-10-21 17:56:44 -04:00
160610e09c Home screen update 2023-10-21 16:31:12 -04:00
971c1b2a6f Merge pull request 'ver. e1.0.0.b6' (#6) from clean_up into ophelia_mainline
Reviewed-on: #6
2023-10-20 14:25:39 -04:00
1be2a90d53 Merge branch 'ophelia_mainline' into clean_up 2023-10-20 14:25:34 -04:00
a3f65d4fff ver. e1.0.0.b5 2023-10-20 14:24:58 -04:00
2f38327c74 ver. e1.0.0.b5 2023-10-20 14:22:51 -04:00
749534f682 Merge pull request 'clean_up' (#5) from clean_up into ophelia_mainline
Reviewed-on: #5
2023-10-20 14:11:59 -04:00
c93d38627f Code Clean up 2023-10-20 14:10:11 -04:00
aaa5704e5d Code Clean up 2023-10-20 13:56:33 -04:00
1b5726ff37 Code Clean up 2023-10-20 13:56:16 -04:00
dff3e17a4e Code Clean up 2023-10-20 13:52:18 -04:00
60deb40b95 Merge pull request 'azea/AddEditBio' (#4) from azea/AddEditBio into ophelia_mainline
Reviewed-on: #4
2023-10-20 12:43:33 -04:00
56229c7d22 Add and Delete 2023-10-20 12:32:41 -04:00
1ed455aeca Tweaks to briefs display,
lorem ipsum added to description in place of empty string,
theme switched to dark when loading app
2023-10-19 19:49:54 -04:00
295ea6413f Bio Details View 2023-10-19 16:34:21 -04:00
a1ace2dcb6 Some button nonsense. 2023-10-19 10:33:05 -04:00
8b6121715e Added view, need to hook up 2023-10-18 18:38:18 -04:00
d92e177a74 Merge pull request 'Cards' (#3) from azea/BiosToCards into ophelia_mainline
Reviewed-on: #3
2023-10-18 16:36:07 -04:00
9869529c37 Replace list with Card Views, move out of main activity, move repo into db manager object for better access through the view models without passing it through everything 2023-10-18 16:34:19 -04:00
3ddab9d8b1 Code Clean 2023-10-18 00:45:41 -04:00
443745e32e app Ico and splash (art break) 2023-10-18 00:40:46 -04:00
1089745861 I'm FREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE 2023-10-17 22:22:08 -04:00
4f3c9e4971 aaaaaaaaaaaaaaaaaaaa 2023-10-17 21:39:29 -04:00
c55d040ca0 Updating Biolist to actually update data 2023-10-16 22:00:46 -04:00
ebe20655eb Database shenanigans 2023-10-16 21:06:07 -04:00
68 changed files with 2641 additions and 326 deletions

1
.idea/gradle.xml generated
View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>

1
.idea/misc.xml generated
View file

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MarkdownSettingsMigration">

View file

@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.devtools.ksp'
}
android {
@ -12,7 +13,7 @@ android {
minSdk 27
targetSdk 33
versionCode 1
versionName "1.0"
versionName "e1.0.0.b7"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@ -27,11 +28,11 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '17'
}
buildFeatures {
compose true
@ -48,14 +49,24 @@ android {
dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
def activity_version = '1.8.0'
def lifecycle_version = "2.6.2"
def arch_version = "2.2.0"
def roomVersion = '2.3.0'
def nav_version = "2.7.4" //Fragment
def fragment_version = "1.6.1"
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation "androidx.activity:activity-ktx:$activity_version"
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
implementation 'androidx.activity:activity-compose:1.8.0'
implementation platform('androidx.compose:compose-bom:2023.03.00')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.compose.material3:material3:1.1.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
@ -66,4 +77,57 @@ dependencies {
implementation 'androidx.room:room-common:2.5.2'
implementation 'androidx.room:room-ktx:2.5.2'
implementation 'androidx.navigation:navigation-runtime-ktx:2.7.4'
implementation('androidx.constraintlayout:constraintlayout-compose-android:1.1.0-alpha13')
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation "androidx.navigation:navigation-compose:$nav_version"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// ViewModel utilities for Compose
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// Lifecycle utilities for Compose
implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version"
// Kotlin
implementation "androidx.fragment:fragment-ktx:$fragment_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
ksp 'androidx.room:room-compiler:2.5.0'
// Annotation processor
annotationProcessor "androidx.room:room-compiler:$roomVersion"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
// optional - Test helpers for Lifecycle runtime
testImplementation "androidx.lifecycle:lifecycle-runtime-testing:$lifecycle_version"
//Runtime
implementation "androidx.compose.runtime:runtime:1.5.3"
implementation "androidx.compose.runtime:runtime-livedata:1.5.3"
implementation "androidx.compose.runtime:runtime-rxjava2:1.5.3"
}

View file

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".database.polycule.PolyculeApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@ -13,16 +14,23 @@
android:theme="@style/Theme.Ophelia"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name=".view.splash.SplashActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Ophelia">
android:theme="@style/SplashScreenTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
/>
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
</application>
</manifest>

View file

@ -1,58 +1,27 @@
package com.menagerie.ophelia
import android.os.Bundle
import android.view.Window
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.menagerie.ophelia.database.polycule.PolyculeDatabase
import com.menagerie.ophelia.database.polycule.PolyculeApplication
import com.menagerie.ophelia.database.polycule.PolyculeDatabaseManager
import com.menagerie.ophelia.database.polycule.PolyculeRepository
import com.menagerie.ophelia.ui.theme.OpheliaTheme
import com.menagerie.ophelia.view.PolyculeApp
class MainActivity : ComponentActivity() {
private val db by lazy { PolyculeDatabase.getDatabase(this) }
private val polyculeRepository by lazy {
PolyculeRepository(
bioDao = db.bioDao()
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
PolyculeDatabaseManager.polyculeRepository = polyculeRepository
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContent {
OpheliaTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
val repository = (application as PolyculeApplication).repository
PolyculeDatabaseManager.polyculeRepository = repository
Surface {
PolyculeApp()
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
OpheliaTheme {
Greeting("Android")
}
}

View file

@ -1,13 +0,0 @@
package com.menagerie.ophelia.database
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "candidate_table")
data class Candidate(
@PrimaryKey(autoGenerate = true) val id: Int,
@ColumnInfo (name = "name") val word: String
){
}

View file

@ -1,20 +0,0 @@
package com.menagerie.ophelia.database
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow
@Dao
interface CandidateDao {
@Query("SELECT * FROM candidate_table ORDER BY name ASC")
fun getAlphabetisedList(): Flow<List<Candidate>>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(candidate: Candidate)
@Query("DELETE FROM candidate_table")
suspend fun deleteAll()
}

View file

@ -0,0 +1,13 @@
package com.menagerie.ophelia.database.polycule
import android.app.Application
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
class PolyculeApplication : Application() {
private val applicationScope = CoroutineScope(SupervisorJob())
val database by lazy { PolyculeDatabase.getDatabase(this, applicationScope) }
val repository by lazy { PolyculeRepository(database.bioDao()) }
}

View file

@ -0,0 +1,79 @@
package com.menagerie.ophelia.database.polycule
import android.content.Context
import androidx.compose.ui.tooling.preview.datasource.LoremIpsum
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.BioDao
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@Database(
version = 3,
exportSchema = false,
entities = [
Bio::class
],
)
abstract class PolyculeDatabase : RoomDatabase() {
abstract fun bioDao(): BioDao
companion object {
@Volatile
private var INSTANCE: PolyculeDatabase? = null
fun getDatabase(
context: Context,
scope: CoroutineScope,
): PolyculeDatabase {
return INSTANCE ?: synchronized(this)
{
val instance = Room.databaseBuilder(
context.applicationContext,
PolyculeDatabase::class.java,
"polycule.db"
)
.fallbackToDestructiveMigration()
.addCallback(PolyculeDatabaseCallback(scope))
.build()
INSTANCE = instance
instance
}
}
}
private class PolyculeDatabaseCallback(
private val scope: CoroutineScope
) : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { database ->
scope.launch {
//populateDatabase(database.bioDao())
}
}
}
suspend fun populateDatabase(bioDao: BioDao) {
var bio = Bio(
name = "Azea",
)
bioDao.insert(bio)
bio = Bio(
name = "Darkwood Mill",
)
bioDao.insert(bio)
bio = Bio(
name = "Blizzard",
)
bioDao.insert(bio)
}
}
}

View file

@ -0,0 +1,5 @@
package com.menagerie.ophelia.database.polycule
object PolyculeDatabaseManager {
lateinit var polyculeRepository: PolyculeRepository
}

View file

@ -0,0 +1,38 @@
package com.menagerie.ophelia.database.polycule
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.BioDao
import kotlinx.coroutines.flow.Flow
class PolyculeRepository(
private val bioDao: BioDao
) {
suspend fun upsertBio(bio: Bio) {
bioDao.upsert(bio)
}
fun getAlphabetisedBios(): Flow<List<Bio>> {
return bioDao.getAllAlphabetisedBios()
}
fun getBio(bioId: Long): Flow<Bio> {
return bioDao.getBio(bioId)
}
fun getAllBios(): Flow<List<Bio>> {
return bioDao.getAllBios()
}
suspend fun insert(bio: Bio) {
bioDao.insert(bio)
}
suspend fun delete(bio: Bio) {
bioDao.delete(bio)
}
fun hasPolycule() = false
}

View file

@ -0,0 +1,20 @@
package com.menagerie.ophelia.database.polycule.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.menagerie.ophelia.R
@Entity(
tableName = "bio_table",
)
data class Bio(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo(name = "name") var name: String = "",
@ColumnInfo(name = "subject_pronoun") val subjective: String = "",
@ColumnInfo(name = "object_pronoun") val objective: String = "",
@ColumnInfo(name = "possess_pronoun") val possessive: String = "",
@ColumnInfo(name = "reflex_pronoun") val reflexive: String = "",
@ColumnInfo(name="tags") var tags: Int = 0,
@ColumnInfo(name = "pfpRes") val pfpRes: Int = R.drawable.ic_app_logo,
)

View file

@ -0,0 +1,34 @@
package com.menagerie.ophelia.database.polycule.entity
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import androidx.room.Upsert
import kotlinx.coroutines.flow.Flow
@Dao
abstract class BioDao {
@Insert
abstract suspend fun insert(newBio: Bio): Long
@Delete
abstract suspend fun delete(bio: Bio)
@Update
abstract suspend fun update(existingBio: Bio)
@Query("SELECT * FROM bio_table ORDER BY name ASC")
abstract fun getAllAlphabetisedBios(): Flow<List<Bio>>
@Query("SELECT * FROM bio_table")
abstract fun getAllBios(): Flow<List<Bio>>
@Query("SELECT * FROM bio_table WHERE id = :bioId")
abstract fun getBio(bioId: Long): Flow<Bio>
@Upsert
abstract suspend fun upsert(bio: Bio): Long
}

View file

@ -0,0 +1,12 @@
package com.menagerie.ophelia.database.polycule.entity.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asLiveData
import com.menagerie.ophelia.database.polycule.PolyculeDatabaseManager
class BioDetailViewModel(
id: Long
) : ViewModel() {
var bio = PolyculeDatabaseManager.polyculeRepository.getBio(id).asLiveData()
}

View file

@ -0,0 +1,49 @@
package com.menagerie.ophelia.database.polycule.entity.viewmodel
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.menagerie.ophelia.database.polycule.PolyculeDatabaseManager
import com.menagerie.ophelia.database.polycule.entity.Bio
import kotlinx.coroutines.launch
class BioListViewModel() : ViewModel() {
val allBios: LiveData<List<Bio>> =
PolyculeDatabaseManager.polyculeRepository.getAllBios().asLiveData()
fun upsert(bio: Bio) = viewModelScope.launch {
PolyculeDatabaseManager.polyculeRepository.upsertBio(bio)
}
fun delete(bio: Bio) = viewModelScope.launch {
PolyculeDatabaseManager.polyculeRepository.delete(bio)
}
class BioListViewModelFactory() :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(BioListViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return BioListViewModel() as T
}
throw IllegalArgumentException("Unknown ViewModel Class")
}
}
class InputBioViewModel : ViewModel() {
private val _bio: MutableLiveData<Bio> = MutableLiveData(Bio())
val bio: LiveData<Bio> = _bio
fun onNameChange(name: String) {
val newBio = Bio(
name = name,
)
_bio.value = newBio
}
}
}

View file

@ -1,11 +1,65 @@
package com.menagerie.ophelia.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val md_theme_light_primary = Color(0xFF366A21)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFFB6F398)
val md_theme_light_onPrimaryContainer = Color(0xFF052100)
val md_theme_light_secondary = Color(0xFF55624C)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFD8E7CB)
val md_theme_light_onSecondaryContainer = Color(0xFF131F0D)
val md_theme_light_tertiary = Color(0xFF386667)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFBBEBEC)
val md_theme_light_onTertiaryContainer = Color(0xFF002021)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFDFDF6)
val md_theme_light_onBackground = Color(0xFF1A1C18)
val md_theme_light_outline = Color(0xFF73796E)
val md_theme_light_inverseOnSurface = Color(0xFFF1F1EA)
val md_theme_light_inverseSurface = Color(0xFF2F312D)
val md_theme_light_inversePrimary = Color(0xFF9BD67F)
val md_theme_light_surfaceTint = Color(0xFF366A21)
val md_theme_light_outlineVariant = Color(0xFFC3C8BB)
val md_theme_light_scrim = Color(0xFF000000)
val md_theme_light_surface = Color(0xFFD8D8C4)
val md_theme_light_onSurface = Color(0xFF1A1C18)
val md_theme_light_surfaceVariant = Color(0xFFDFE4D7)
val md_theme_light_onSurfaceVariant = Color(0xFF43483F)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
val md_theme_dark_primary = Color(0xFF9BD67F)
val md_theme_dark_onPrimary = Color(0xFF0E3900)
val md_theme_dark_primaryContainer = Color(0xFF1E5108)
val md_theme_dark_onPrimaryContainer = Color(0xFFB6F398)
val md_theme_dark_secondary = Color(0xFFBCCBB0)
val md_theme_dark_onSecondary = Color(0xFF273421)
val md_theme_dark_secondaryContainer = Color(0xFF3D4B36)
val md_theme_dark_onSecondaryContainer = Color(0xFFD8E7CB)
val md_theme_dark_tertiary = Color(0xFFA0CFD0)
val md_theme_dark_onTertiary = Color(0xFF003738)
val md_theme_dark_tertiaryContainer = Color(0xFF1E4E4F)
val md_theme_dark_onTertiaryContainer = Color(0xFFBBEBEC)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF1C1C18)
val md_theme_dark_onBackground = Color(0xFFE3E3DC)
val md_theme_dark_outline = Color(0xFF8D9287)
val md_theme_dark_inverseOnSurface = Color(0xFF1A1C18)
val md_theme_dark_inverseSurface = Color(0xFFE3E3DC)
val md_theme_dark_inversePrimary = Color(0xFF366A21)
val md_theme_dark_surfaceTint = Color(0xFF9BD67F)
val md_theme_dark_outlineVariant = Color(0xFF43483F)
val md_theme_dark_scrim = Color(0xFF000000)
val md_theme_dark_surface = Color(0xFF2B2822)
val md_theme_dark_onSurface = Color(0xFFC6C7C0)
val md_theme_dark_surfaceVariant = Color(0xFF43483F)
val md_theme_dark_onSurfaceVariant = Color(0xFFC3C8BB)
val seed = Color(0xFF5E9546)

View file

@ -1,54 +1,93 @@
package com.menagerie.ophelia.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
primary = md_theme_light_primary,
onPrimary = md_theme_light_onPrimary,
primaryContainer = md_theme_light_primaryContainer,
onPrimaryContainer = md_theme_light_onPrimaryContainer,
secondary = md_theme_light_secondary,
onSecondary = md_theme_light_onSecondary,
secondaryContainer = md_theme_light_secondaryContainer,
onSecondaryContainer = md_theme_light_onSecondaryContainer,
tertiary = md_theme_light_tertiary,
onTertiary = md_theme_light_onTertiary,
tertiaryContainer = md_theme_light_tertiaryContainer,
onTertiaryContainer = md_theme_light_onTertiaryContainer,
error = md_theme_light_error,
errorContainer = md_theme_light_errorContainer,
onError = md_theme_light_onError,
onErrorContainer = md_theme_light_onErrorContainer,
background = md_theme_light_background,
onBackground = md_theme_light_onBackground,
outline = md_theme_light_outline,
inverseOnSurface = md_theme_light_inverseOnSurface,
inverseSurface = md_theme_light_inverseSurface,
inversePrimary = md_theme_light_inversePrimary,
surfaceTint = md_theme_light_surfaceTint,
outlineVariant = md_theme_light_outlineVariant,
scrim = md_theme_light_scrim,
surface = md_theme_light_surface,
onSurface = md_theme_light_onSurface,
surfaceVariant = md_theme_light_surfaceVariant,
onSurfaceVariant = md_theme_light_onSurfaceVariant,
)
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
private val DarkColorScheme = darkColorScheme(
primary = md_theme_dark_primary,
onPrimary = md_theme_dark_onPrimary,
primaryContainer = md_theme_dark_primaryContainer,
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
secondary = md_theme_dark_secondary,
onSecondary = md_theme_dark_onSecondary,
secondaryContainer = md_theme_dark_secondaryContainer,
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
tertiary = md_theme_dark_tertiary,
onTertiary = md_theme_dark_onTertiary,
tertiaryContainer = md_theme_dark_tertiaryContainer,
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
error = md_theme_dark_error,
errorContainer = md_theme_dark_errorContainer,
onError = md_theme_dark_onError,
onErrorContainer = md_theme_dark_onErrorContainer,
background = md_theme_dark_background,
onBackground = md_theme_dark_onBackground,
outline = md_theme_dark_outline,
inverseOnSurface = md_theme_dark_inverseOnSurface,
inverseSurface = md_theme_dark_inverseSurface,
inversePrimary = md_theme_dark_inversePrimary,
surfaceTint = md_theme_dark_surfaceTint,
outlineVariant = md_theme_dark_outlineVariant,
scrim = md_theme_dark_scrim,
surface = md_theme_dark_surface,
onSurface = md_theme_dark_onSurface,
surfaceVariant = md_theme_dark_surfaceVariant,
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
)
@Composable
fun OpheliaTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
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)
}
// dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
// val context = LocalContext.current
// if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
// }
darkTheme -> DarkColorScheme
else -> LightColorScheme

View file

@ -4,17 +4,26 @@ import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontFamily = FontFamily.Serif,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
),
displayLarge = TextStyle(
fontFamily = FontFamily.Cursive,
fontWeight = FontWeight.Bold,
fontSize = 64.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp,
textDecoration = TextDecoration.Underline
),
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,

View file

@ -0,0 +1,67 @@
package com.menagerie.ophelia.view
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.menagerie.ophelia.R
import com.menagerie.ophelia.ui.theme.OpheliaTheme
@Composable
fun HomeScreen(
onClick: () -> Unit,
) {
val text = if(true) R.string.welcome else R.string.welcome_back
HeaderText(text, onClick)
}
@Composable
fun HeaderText(
text: Int,
onClick: () -> Unit
) {
Box(
modifier = Modifier
.fillMaxSize()
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
.align(Alignment.Center),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Spacer(modifier = Modifier.weight(1f))
Text(
text = stringResource(id = R.string.app_name),
style = MaterialTheme.typography.displayLarge
)
Text(
text = stringResource(id = R.string.app_tag)
)
Spacer(modifier = Modifier.weight(1f))
Button(
modifier = Modifier.padding(12.dp),
onClick = onClick
) {
Text(text = stringResource(id = text))
}
}
}
}

View file

@ -0,0 +1,45 @@
package com.menagerie.ophelia.view
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun NewUserStartScreen(
onGo: () -> Unit = {},
) {
Scaffold {
Column {
OpheliaFace(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 12.dp)
)
OpheliaWelcome(modifier = Modifier.weight(1f))
Button(
onClick = onGo,
modifier = Modifier
.padding(12.dp)
.align(Alignment.End)
) {
Text(text = "Go")
}
}
}
}
@Preview
@Composable
fun NewUserPreview(){
NewUserStartScreen()
}

View file

@ -0,0 +1,168 @@
package com.menagerie.ophelia.view
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.modifier.modifierLocalConsumer
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import com.menagerie.ophelia.R
@Composable
fun OpheliaSpanStyle(): SpanStyle {
val fontFamily = FontFamily(
Font(R.font.calligraffitti)
)
return SpanStyle(
letterSpacing = MaterialTheme.typography.bodyLarge.letterSpacing,
fontFamily = fontFamily,
fontSize = MaterialTheme.typography.bodyLarge.fontSize)
}
@Composable
fun OpheliaFace(
modifier: Modifier
) {
Image(
modifier = modifier,
painter = painterResource(id = R.drawable.ophelia_foreground),
contentDescription = OpheliaSays()
)
}
@Composable
fun OpheliaSaysArray(
id: Int,
separator: String = "\n\n"
): AnnotatedString {
return buildAnnotatedString {
pushStyle(OpheliaSpanStyle())
append(stringArrayResource(id = id).joinToString(separator = separator))
toAnnotatedString()
}
}
@Composable
fun OpheliaSays(
say: String
): AnnotatedString {
return buildAnnotatedString {
pushStyle(OpheliaSpanStyle())
append(say)
toAnnotatedString()
}
}
@Composable
fun OpheliaSays(): String {
return stringResource(id = R.string.ophelia_says)
}
@Composable
fun OpheliaWelcome(
modifier: Modifier
) {
Box(
modifier = modifier
.fillMaxSize()
.padding(24.dp)
) {
Text(
text = OpheliaSaysArray(id = R.array.welcome_blurb)
)
}
}
@Composable
fun OpheliaWhatsYourName(
modifier: Modifier
) {
Box(
modifier = modifier
.fillMaxWidth()
.padding(12.dp)
) {
Text(text = OpheliaSaysArray(id = R.array.whats_your_name))
}
}
@Composable
fun OpheliaPronounsIntroduction(
modifier: Modifier,
name: String
) {
Box(
modifier = modifier
.fillMaxWidth()
.padding(12.dp)
) {
Column {
val context = LocalContext.current
Text(text = OpheliaSays(context.resources.getString(R.string.introduction_with_name, name)))
Text(text = OpheliaSaysArray(id = R.array.introduction_to_pronouns))
}
}
}
@Composable
fun OpheliaTagsIntroduction(
modifier: Modifier,
) {
Box(
modifier = modifier
.fillMaxWidth()
.padding(12.dp)
) {
Column {
Text(text = OpheliaSaysArray(R.array.introduction_to_tags))
}
}
}
@Composable
fun OpheliaNewUserFinalCheck(
modifier: Modifier,
){
Box(
modifier = modifier
.fillMaxWidth()
.padding(12.dp)
) {
Column {
Text(text = OpheliaSays(stringResource(id = R.string.final_check_in)))
}
}
}
@Composable
fun OpheliaNewUserPolycule(
modifier: Modifier,
) {
Box(
modifier = modifier
.fillMaxWidth()
.padding(12.dp)
) {
Column {
Text(text = OpheliaSaysArray(id = R.array.introduction_to_polycules))
}
}
}

View file

@ -0,0 +1,108 @@
package com.menagerie.ophelia.view
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.menagerie.ophelia.database.polycule.PolyculeDatabaseManager
import com.menagerie.ophelia.view.biographies.AddBiography
import com.menagerie.ophelia.view.biographies.AddEditBio
import com.menagerie.ophelia.view.biographies.BioDetailsScreen
import com.menagerie.ophelia.view.biographies.EditBiography
import com.menagerie.ophelia.view.newUser.AddNameScreen
import com.menagerie.ophelia.view.newUser.AddPronounsScreen
import com.menagerie.ophelia.view.newUser.AddTagsScreen
import com.menagerie.ophelia.view.newUser.ConfirmBio
import com.menagerie.ophelia.view.polycule.AddPolyculeScreen
import com.menagerie.ophelia.view.polycule.PolyculeHomeView
@Composable
fun PolyculeApp() {
val navController = rememberNavController()
PolyculeNavHost(
navController = navController
)
}
@Composable
fun PolyculeNavHost(
navController: NavHostController
) {
NavHost(
navController = navController,
startDestination = "confirmBio"
) {
polyculeGraph(navController)
welcomeGraph(navController)
composable("home") {
HomeScreen() {
navController.navigate("newUserStart")
}
}
}
}
fun NavGraphBuilder.welcomeGraph(navController: NavHostController) {
composable("newUserStart") {
NewUserStartScreen { navController.navigate("newUserName") }
}
composable("newUserName") {
AddNameScreen { navController.navigate("newUserPronouns") }
}
composable("newUserPronouns") {
AddPronounsScreen { navController.navigate("newUserTags") }
}
composable("newUserTags") {
AddTagsScreen { navController.navigate("confirmBio") }
}
composable("confirmBio") {
ConfirmBio {
navController.popBackStack()
navController.navigate("polyculeHome")
}
}
composable("makePolycule") {
AddPolyculeScreen()
}
}
fun NavGraphBuilder.polyculeGraph(navController: NavController) {
composable("polyculeHome") {
PolyculeHomeView(
onBioClick = {
navController.navigate("bioDetail/${it.id}")
},
onAddClick = {
navController.navigate("addBio") {}
}
)
}
composable(
"bioDetail/{bioId}",
arguments = listOf(navArgument("bioId") {
type = NavType.LongType
})
) {
BioDetailsScreen(
id = it.arguments?.getLong("bioId") ?: 0,
onBackClick = { navController.navigateUp() },
onEditClick = { id -> navController.navigate("editBio/${id}")}
)
}
composable("addBio") {
AddBiography()
}
composable(
"editBio/{bioId}",
arguments = listOf(navArgument("bioId") {
type = NavType.LongType
})
){
EditBiography(bioId = it.arguments?.getLong("bioId") ?: 0) { navController.navigateUp() }
}
}

View file

@ -0,0 +1,341 @@
package com.menagerie.ophelia.view.biographies
import android.annotation.SuppressLint
import android.widget.Toast
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import com.menagerie.ophelia.R
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioDetailViewModel
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioListViewModel
import com.menagerie.ophelia.view.components.InputFieldState
import com.menagerie.ophelia.view.components.fab.FABComponent
import com.menagerie.ophelia.view.newUser.Tags
fun insertBioInDB(bio: Bio?, mBioListViewModel: BioListViewModel) {
bio?.let {
mBioListViewModel.upsert(it)
}
}
@Composable
fun FinishBiography(
bioId: Long,
onGo: () -> Unit
) {
val mBioDetailViewModel = BioDetailViewModel(bioId)
val bio = mBioDetailViewModel.bio.observeAsState().value
if (bio != null) {
val inputViewModel = InputEditViewModel(bio)
val ioBio: Bio by inputViewModel.bio.observeAsState(bio)
AddEditBio(
ioBio = ioBio,
btnLabel = stringResource(id = R.string.finish),
toast = stringResource(id = R.string.bio_finish_toast),
onGo,
)
}
}
@Composable
fun EditBiography(
bioId: Long,
onGo: () -> Unit
) {
val mBioDetailViewModel = BioDetailViewModel(bioId)
val bio = mBioDetailViewModel.bio.observeAsState().value
if (bio != null) {
val inputViewModel = InputEditViewModel(bio)
val ioBio: Bio by inputViewModel.bio.observeAsState(bio)
AddEditBio(
ioBio = ioBio,
btnLabel = stringResource(id = R.string.edit_bio),
toast = stringResource(id = R.string.bio_edit_toast),
onGo,
)
}
}
@Composable
fun AddBiography() {
val inputViewModel = InputAddViewModel()
val ioBio: Bio by inputViewModel.bio.observeAsState(Bio())
AddEditBio(
ioBio = ioBio,
btnLabel = stringResource(id = R.string.edit_bio),
toast = stringResource(id = R.string.bio_edit_toast),
) {
}
}
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun AddEditBio(
ioBio: Bio,
btnLabel: String,
toast: String,
onGo: () -> Unit
) {
val mBioListViewModel: BioListViewModel = viewModel(
factory = BioListViewModel.BioListViewModelFactory()
)
val context = LocalContext.current
var name by remember { mutableStateOf(ioBio.name) }
var sp by remember { mutableStateOf(ioBio.subjective) }
var op by remember { mutableStateOf(ioBio.objective) }
var pp by remember { mutableStateOf(ioBio.possessive) }
var rp by remember { mutableStateOf(ioBio.reflexive) }
var tags by remember { mutableIntStateOf(ioBio.tags) }
Scaffold(
floatingActionButton = {
FABComponent(text = btnLabel, onClick = {
insertBioInDB(
Bio(
id = ioBio.id,
name = name,
subjective = sp,
objective = op,
possessive = pp,
reflexive = rp,
tags = tags,
),
mBioListViewModel
)
onGo()
Toast.makeText(context, toast, Toast.LENGTH_SHORT).show()
})
}
)
{
Column(
modifier = Modifier.padding(12.dp)
) {
val modifier = Modifier
.width(164.dp)
.height(64.dp)
val focusManager = LocalFocusManager.current
InputFieldState(
value = name,
label = "name",
modifier = modifier,
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
)
) { name = it }
Box {
Column {
Row {
InputFieldState(
value = sp,
label = "objective",
modifier = modifier,
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
)
) { sp = it }
Text(
text = " / ",
style = MaterialTheme.typography.displayMedium
)
InputFieldState(
value = op,
label = "subjective",
modifier = modifier,
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
)
) { op = it }
}
Row {
InputFieldState(
value = pp,
label = "possessive",
modifier = modifier,
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
)
) { pp = it }
Text(
text = " / ",
style = MaterialTheme.typography.displayMedium
)
InputFieldState(
value = rp,
label = "reflexive",
modifier = modifier,
keyboardActions = KeyboardActions(
onDone = { focusManager.clearFocus() }
)
) { rp = it }
}
tagsBox(
tags = tags,
modifier = Modifier
.padding(12.dp)
.size(64.dp)
) {
tags = it
}
}
}
}
}
}
@Composable
fun tagsBox(
tags: Int,
modifier: Modifier,
onValChange: (Int) -> Unit
) {
Row {
RememberableButton(
tagList = tags,
tag = Tags.TRANS,
painter = painterResource(id = R.drawable.trans_tag),
modifier = modifier,
onValChange = onValChange)
RememberableButton(
tagList = tags,
tag = Tags.FURRY,
painter = painterResource(id = R.drawable.furry_tag),
modifier = modifier,
onValChange = onValChange)
RememberableButton(
tagList = tags,
tag = Tags.ASEXUAL,
painter = painterResource(id = R.drawable.asexual_tag),
modifier = modifier,
onValChange = onValChange)
}
Row {
RememberableButton(
tagList = tags,
tag = Tags.BDSM,
painter = painterResource(id = R.drawable.bdsm_tag),
modifier = modifier,
onValChange = onValChange)
RememberableButton(
tagList = tags,
tag = Tags.MONO,
painter = painterResource(id = R.drawable.mono_tag),
modifier = modifier,
onValChange = onValChange)
RememberableButton(
tagList = tags,
tag = Tags.ALCOHOL,
painter = painterResource(id = R.drawable.liqour_tag),
modifier = modifier,
onValChange = onValChange)
}
Row {
RememberableButton(
tagList = tags,
tag = Tags.WEED,
painter = painterResource(id = R.drawable.weed_tag),
modifier = modifier,
onValChange = onValChange)
RememberableButton(
tagList = tags,
tag = Tags.THERIAN,
painter = painterResource(id = R.drawable.therian_tag),
modifier = modifier,
onValChange = onValChange)
RememberableButton(
tagList = tags,
tag = Tags.PLURAL,
painter = painterResource(id = R.drawable.plural_tag),
modifier = modifier,
onValChange = onValChange)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RememberableButton(
tagList: Int,
tag: Tags,
modifier: Modifier,
painter: Painter,
onValChange: (Int) -> Unit,
) {
var selected = tagList and tag.value == tag.value
Box {
FilterChip(
selected = selected,
onClick = { onValChange(tagList xor tag.value) },
modifier = modifier,
shape = CircleShape,
label = {
Icon(
modifier = Modifier.padding(horizontal = 4.dp),
painter = painter,
contentDescription = ""
)
},
)
}
}
class InputEditViewModel(
bio: Bio
) : ViewModel() {
private val _bio: MutableLiveData<Bio> = MutableLiveData(bio)
val bio: LiveData<Bio> = _bio
}
class InputAddViewModel() : ViewModel() {
private val _bio: MutableLiveData<Bio> = MutableLiveData(Bio())
val bio: LiveData<Bio> = _bio
}

View file

@ -0,0 +1,103 @@
package com.menagerie.ophelia.view.biographies
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.menagerie.ophelia.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BioCard(
name: String,
image: Int,
onBioClick: () -> Unit,
onDeleteClick: () -> Unit
) {
var expanded by remember { mutableStateOf(false) }
Card(
onClick = onBioClick,
modifier = Modifier
.padding(10.dp)
.fillMaxWidth()
.wrapContentHeight(),
shape = MaterialTheme.shapes.medium,
elevation = CardDefaults.cardElevation(
defaultElevation = 6.dp
),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface
),
border = BorderStroke(1.dp, Color.Black),
) {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Image(
painter = painterResource(id = R.drawable.ic_app_logo),
contentDescription = null,
modifier = Modifier
.size(130.dp)
.padding(8.dp),
contentScale = ContentScale.Fit,
)
Column(modifier = Modifier.padding(8.dp)) {
Text(
text = name,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface,
)
}
Spacer(modifier = Modifier
.weight(1f)
.fillMaxSize())
Box(
modifier = Modifier
.wrapContentSize(Alignment.TopStart)
)
{
IconButton(
onClick = { expanded = true }) {
Icon(
Icons.Default.MoreVert,
contentDescription = ""
)
}
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DropdownMenuItem(text = { Text(text = "Delete") }, onClick = onDeleteClick)
}
}
}
}
}

View file

@ -0,0 +1,47 @@
package com.menagerie.ophelia.view.biographies
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioListViewModel
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun BioCardList(
bioList: List<Bio>,
onBioClick: (Bio) -> Unit = {},
) {
val mBioListViewModel: BioListViewModel = viewModel(
factory = BioListViewModel.BioListViewModelFactory()
)
Box(modifier = Modifier.padding()) {
LazyColumn(
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(8.dp)
) {
items(bioList) { bio ->
BioCard(
name = bio.name,
image = bio.pfpRes,
onBioClick = { onBioClick(bio) },
onDeleteClick = { mBioListViewModel.delete(bio) })
}
}
}
}

View file

@ -0,0 +1,122 @@
package com.menagerie.ophelia.view.biographies
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.menagerie.ophelia.R
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioDetailViewModel
import com.menagerie.ophelia.view.components.fab.FABComponent
import com.menagerie.ophelia.view.components.utils.Dimens
data class BioDetailCallbacks(
val onBackClick: () -> Unit,
val onEditClick: (Long) -> Unit
)
@Composable
fun BioDetailsScreen(
id: Long,
onBackClick: () -> Unit,
onEditClick: (Long) -> Unit,
) {
val mBioDetailViewModel = BioDetailViewModel(id)
val bio = mBioDetailViewModel.bio.observeAsState().value
if (bio != null) {
Surface {
BioDetails(
bio,
BioDetailCallbacks(
onBackClick = onBackClick,
onEditClick = onEditClick,
)
)
}
}
}
@Composable
fun BioDetails(
bio: Bio,
callbacks: BioDetailCallbacks,
modifier: Modifier = Modifier
) {
Box(
modifier
.fillMaxSize()
) {
BioDetailContents(
bio = bio,
onEdit = callbacks.onEditClick
)
}
}
@Composable
fun BioDetailContents(
bio: Bio,
onEdit: (Long) -> Unit,
) {
Column {
InfoDetails(
bio = bio,
onEdit = onEdit,
modifier = Modifier
)
}
}
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun InfoDetails(
bio: Bio,
onEdit: (Long) -> Unit,
modifier: Modifier = Modifier
) {
Scaffold(
floatingActionButton = {
FABComponent(
text = "${stringResource(id = R.string.edit_bio)}",
onClick = { onEdit(bio.id) }
)
}
) {
Column(modifier = modifier.padding(Dimens.PaddingLarge)) {
Text(
text = bio.name,
style = MaterialTheme.typography.displaySmall,
modifier = Modifier
.padding(
start = Dimens.PaddingSmall,
end = Dimens.PaddingSmall,
bottom = Dimens.PaddingNormal
)
.align(Alignment.CenterHorizontally)
)
Box(
Modifier
.align(Alignment.CenterHorizontally)
.padding(
start = Dimens.PaddingSmall,
end = Dimens.PaddingSmall,
bottom = Dimens.PaddingNormal
)
) {
Text(text = "${bio.subjective} / ${bio.objective} / ${bio.possessive} / ${bio.reflexive}")
}
}
}
}

View file

@ -0,0 +1,86 @@
package com.menagerie.ophelia.view.biographies
import android.util.Log
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TagCard(
name: String,
painter: Painter,
details: String,
check: Boolean,
onClick: () -> Unit
) {
var checked by remember { mutableStateOf(check) }
Card(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
.wrapContentHeight(),
shape = MaterialTheme.shapes.medium,
elevation = CardDefaults.cardElevation(
defaultElevation = 6.dp
),
colors = CardDefaults.cardColors(
containerColor =
if (checked) MaterialTheme.colorScheme.primaryContainer
else MaterialTheme.colorScheme.surface
),
border = BorderStroke(1.dp, Color.Black),
onClick = {
checked = !checked
onClick()
},
) {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Image(
painter = painter,
contentDescription = null,
modifier = Modifier
.size(80.dp)
.padding(8.dp),
contentScale = ContentScale.Fit,
)
Column(modifier = Modifier.padding(8.dp)) {
Text(
text = name,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface,
)
//TODO: details blurbs
// Text(
// text = details,
// style = MaterialTheme.typography.headlineSmall,
// color = MaterialTheme.colorScheme.onSurface,
// )
}
}
}
}

View file

@ -0,0 +1,69 @@
package com.menagerie.ophelia.view.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp
@Composable
fun InputFieldComponent(
text: String,
onChange: (String) -> Unit,
modifier: Modifier = Modifier,
singleLine: Boolean = true,
label: String = "Some val",
keyboardActions: KeyboardActions = KeyboardActions.Default,
) {
OutlinedTextField(
value = text,
onValueChange = onChange,
label = { Text(text = label)},
modifier = modifier,
singleLine = singleLine,
keyboardActions = keyboardActions,
)
}
@Composable
fun InputFieldState(
value: String,
label: String,
modifier: Modifier,
keyboardActions: KeyboardActions = KeyboardActions.Default,
onVal: (String) -> Unit,
) {
Column(
modifier = Modifier
) {
InputField(value, label, modifier, onVal, keyboardActions)
Spacer(modifier = Modifier.padding(10.dp))
}
}
@Composable
fun InputField(
text: String,
label: String,
modifier: Modifier,
onValChange: ((String) -> Unit)?,
keyboardActions: KeyboardActions,
) {
if (onValChange != null) {
InputFieldComponent(
text = text,
onChange = onValChange,
label = label,
modifier = modifier,
keyboardActions = keyboardActions,
)
}
}

View file

@ -0,0 +1,20 @@
package com.menagerie.ophelia.view.components.fab
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
@Composable
fun FABComponent(
text: String,
onClick: () -> Unit
) {
ExtendedFloatingActionButton(
onClick = onClick,
elevation = FloatingActionButtonDefaults.elevation(8.dp)
) {
Text(text = text)
}
}

View file

@ -0,0 +1,25 @@
package com.menagerie.ophelia.view.components.utils
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.menagerie.ophelia.R
object Dimens {
val PaddingSmall: Dp
@Composable get() = dimensionResource(R.dimen.margin_small)
val PaddingNormal: Dp
@Composable get() = dimensionResource(R.dimen.margin_normal)
val PaddingLarge: Dp = 24.dp
val PlantDetailAppBarHeight: Dp
@Composable get() = dimensionResource(R.dimen.plant_detail_app_bar_height)
val ToolbarIconPadding = 12.dp
val ToolbarIconSize = 32.dp
}

View file

@ -0,0 +1,61 @@
package com.menagerie.ophelia.view.components.utils
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Shapes
import androidx.compose.material3.Snackbar
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun TextSnackbarContainer(
snackbarText: String,
showSnackbar: Boolean,
onDismissSnackbar: () -> Unit,
modifier: Modifier = Modifier,
snackbarHostState: SnackbarHostState = remember{ SnackbarHostState()},
content: @Composable () -> Unit,
) {
Box(modifier) {
content()
val onDismissState by rememberUpdatedState(onDismissSnackbar)
LaunchedEffect(showSnackbar, snackbarText) {
if (showSnackbar) {
try {
snackbarHostState.showSnackbar(
message = snackbarText,
duration = SnackbarDuration.Short
)
} finally {
onDismissState()
}
}
}
MaterialTheme(shapes = Shapes()) {
SnackbarHost(
hostState = snackbarHostState,
modifier = modifier
.align(Alignment.BottomCenter)
.systemBarsPadding()
.padding(all = 8.dp),
) {
Snackbar(it)
}
}
}
}

View file

@ -0,0 +1,81 @@
package com.menagerie.ophelia.view.newUser
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioListViewModel
import com.menagerie.ophelia.view.OpheliaFace
import com.menagerie.ophelia.view.OpheliaWhatsYourName
import com.menagerie.ophelia.view.biographies.insertBioInDB
import com.menagerie.ophelia.view.components.InputFieldState
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun AddNameScreen(
onGo: () -> Unit,
) {
val inputViewModel = BioListViewModel.InputBioViewModel()
val mBioListViewModel: BioListViewModel = viewModel(
factory = BioListViewModel.BioListViewModelFactory()
)
Scaffold {
Column(
modifier = Modifier.fillMaxSize()
) {
val bio: Bio by inputViewModel.bio.observeAsState(Bio())
OpheliaFace(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 12.dp)
)
LinearProgressIndicator(
progress = 0f,
modifier = Modifier.fillMaxWidth()
)
OpheliaWhatsYourName(modifier = Modifier)
InputFieldState(
value = bio.name,
label = "name",
modifier = Modifier
.width(120.dp)
) { inputViewModel.onNameChange(it) }
Spacer(
modifier = Modifier
.fillMaxSize()
.weight(1f)
)
Button(
modifier = Modifier
.align(Alignment.End),
onClick = {
insertBioInDB(inputViewModel.bio.value, mBioListViewModel)
onGo()
}
) {
Text(text = "Continue")
}
}
}
}

View file

@ -0,0 +1,158 @@
package com.menagerie.ophelia.view.newUser
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
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.size
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.Button
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioDetailViewModel
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioListViewModel
import com.menagerie.ophelia.view.OpheliaFace
import com.menagerie.ophelia.view.OpheliaPronounsIntroduction
import com.menagerie.ophelia.view.components.InputField
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun AddPronounsScreen(
onGo : () -> Unit
) {
val mBioDetailViewModel = BioDetailViewModel(1)
val mBioListViewModel: BioListViewModel = viewModel(
factory = BioListViewModel.BioListViewModelFactory()
)
val bio = mBioDetailViewModel.bio.observeAsState().value
Scaffold {
if (bio != null) {
Column {
OpheliaFace(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 12.dp)
)
LinearProgressIndicator(
progress = .33f,
modifier = Modifier.fillMaxWidth()
)
OpheliaPronounsIntroduction(modifier = Modifier.weight(1f), name = bio.name)
PronounBox(Modifier.weight(1f)) {
val updateBio = Bio(
id = bio.id,
name = bio.name,
subjective = it[0],
objective = it[1],
possessive = it[2],
reflexive = it[3],
)
mBioListViewModel.upsert(updateBio)
onGo()
}
}
}
}
}
@Composable
fun PronounBox(
modifier: Modifier,
onClick: (List<String>) -> Unit,
) {
var subject by remember { mutableStateOf("") }
var objec by remember { mutableStateOf("") }
var possess by remember { mutableStateOf("") }
var reflex by remember { mutableStateOf("") }
Box(modifier = Modifier.fillMaxWidth())
{
Column {
val focusManager = LocalFocusManager.current
Row {
InputField(
text = subject,
label = "subjective",
modifier = modifier,
onValChange = { subject = it },
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
),
)
Text(
text = " / ",
style = MaterialTheme.typography.displayMedium
)
InputField(
text = objec,
label = "objective",
modifier = modifier,
onValChange = { objec = it },
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
),
)
}
Row {
InputField(
text = possess,
label = "possessive",
modifier = modifier,
onValChange = { possess = it },
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
),
)
Text(
text = " / ",
style = MaterialTheme.typography.displayMedium
)
InputField(
text = reflex,
label = "reflexive",
modifier = modifier,
onValChange = { reflex = it },
keyboardActions = KeyboardActions(
onDone = { focusManager.clearFocus() }
),
)
}
Spacer(
modifier = Modifier.size(60.dp)
)
Button(
onClick = {
onClick(listOf(subject, objec, possess, reflex))
},
modifier = Modifier
.align(
alignment = Alignment.End
)
.padding(8.dp)
) {
Text(text = "Continue")
}
}
}
}

View file

@ -0,0 +1,195 @@
package com.menagerie.ophelia.view.newUser
import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.menagerie.ophelia.R
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioDetailViewModel
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioListViewModel
import com.menagerie.ophelia.view.OpheliaFace
import com.menagerie.ophelia.view.OpheliaTagsIntroduction
import com.menagerie.ophelia.view.biographies.TagCard
enum class Tags(val value: Int)
{
TRANS(1),
FURRY(2),
ASEXUAL(4),
BDSM(8),
MONO(16),
ALCOHOL(32),
WEED(64),
THERIAN(128),
PLURAL(256),
}
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun AddTagsScreen(
onGo : () -> Unit
) {
Scaffold {
Column {
OpheliaFace(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 12.dp)
)
LinearProgressIndicator(
progress = .66f,
modifier = Modifier.fillMaxWidth()
)
OpheliaTagsIntroduction(modifier = Modifier.weight(1f))
MakeDefaultTagCards(modifier = Modifier.weight(2f))
Button(
onClick = onGo,
modifier = Modifier
.weight(.25f)
.align(Alignment.End)) {
Text(text = "Continue")
}
}
}
}
@Composable
fun MakeDefaultTagCards(
modifier: Modifier,
) {
var flags by remember { mutableIntStateOf(0) }
val mBioDetailViewModel = BioDetailViewModel(1)
val mBioListViewModel: BioListViewModel = viewModel(
factory = BioListViewModel.BioListViewModelFactory()
)
val bio = mBioDetailViewModel.bio.observeAsState().value
if (bio != null) {
val updateBio = Bio(
id = bio.id,
name = bio.name,
subjective = bio.subjective,
objective = bio.objective,
possessive = bio.possessive,
reflexive = bio.reflexive,
tags = flags
)
mBioListViewModel.upsert(updateBio)
Box(modifier = modifier) {
LazyColumn {
item {
TagCard(
name = "Transgender",
painter = painterResource(id = R.drawable.trans_tag),
details = "",
check = flags and Tags.TRANS.value == Tags.TRANS.value
) {
flags = flags xor Tags.TRANS.value
}
}
item {
TagCard(
name = "Furry",
painter = painterResource(id = R.drawable.furry_tag),
details = "",
check = flags and Tags.FURRY.value == Tags.FURRY.value
) {
flags = flags xor Tags.FURRY.value
}
}
item {
TagCard(
name = "Therian",
painter = painterResource(id = R.drawable.therian_tag),
details = "",
check = flags and Tags.THERIAN.value == Tags.THERIAN.value
) {
flags = flags xor Tags.THERIAN.value
}
}
item {
TagCard(
name = "Monogamous",
painter = painterResource(id = R.drawable.mono_tag),
details = "",
check = flags and Tags.MONO.value == Tags.MONO.value
) {
flags = flags xor Tags.MONO.value
}
}
item {
TagCard(
name = "BDSM",
painter = painterResource(id = R.drawable.bdsm_tag),
details = "",
check = flags and Tags.BDSM.value == Tags.BDSM.value
) {
flags = flags xor Tags.BDSM.value
}
}
item {
TagCard(
name = "Plural",
painter = painterResource(id = R.drawable.plural_tag),
details = "",
check = flags and Tags.PLURAL.value == Tags.PLURAL.value
) {
flags = flags xor Tags.PLURAL.value
}
}
item {
TagCard(
name = "Asexual",
painter = painterResource(id = R.drawable.asexual_tag),
details = "",
check = flags and Tags.ASEXUAL.value == Tags.ASEXUAL.value
) {
flags = flags xor Tags.ASEXUAL.value
}
}
item {
TagCard(
name = "Alcohol",
painter = painterResource(id = R.drawable.liqour_tag),
details = "",
check = flags and Tags.ALCOHOL.value == Tags.ALCOHOL.value
) {
flags = flags xor Tags.ALCOHOL.value
}
}
item {
TagCard(
name = "Weed",
painter = painterResource(id = R.drawable.weed_tag),
details = "",
check = flags and Tags.WEED.value == Tags.WEED.value
) {
flags = flags xor Tags.WEED.value
}
}
}
}
}
}

View file

@ -0,0 +1,40 @@
package com.menagerie.ophelia.view.newUser
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.menagerie.ophelia.view.OpheliaFace
import com.menagerie.ophelia.view.OpheliaNewUserFinalCheck
import com.menagerie.ophelia.view.biographies.FinishBiography
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun ConfirmBio(
onGo: () -> Unit
) {
Scaffold {
Column {
OpheliaFace(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 12.dp)
)
LinearProgressIndicator(
progress = 1f,
modifier = Modifier.fillMaxWidth()
)
OpheliaNewUserFinalCheck(modifier = Modifier)
FinishBiography(
bioId = 1,
onGo = onGo,
)
}
}
}

View file

@ -0,0 +1,29 @@
package com.menagerie.ophelia.view.polycule
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.menagerie.ophelia.view.OpheliaFace
import com.menagerie.ophelia.view.OpheliaNewUserPolycule
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun AddPolyculeScreen(
) {
Scaffold {
Column {
OpheliaFace(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 12.dp)
)
OpheliaNewUserPolycule(modifier = Modifier)
//TODO : Polycules
}
}
}

View file

@ -0,0 +1,93 @@
package com.menagerie.ophelia.view.polycule
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import com.menagerie.ophelia.database.polycule.entity.Bio
import com.menagerie.ophelia.database.polycule.entity.viewmodel.BioListViewModel
import com.menagerie.ophelia.view.biographies.BioCardList
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PolyculeHomeView(
modifier: Modifier = Modifier,
onBioClick: (Bio) -> Unit = {},
onAddClick: () -> Unit,
) {
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold(
modifier = modifier,
topBar = {
PolyculeTopAppBar(
onFilterClick = { },
scrollBehavior = scrollBehavior
)
}
) {
PolyculeHomeScreen(
onBioClick = onBioClick,
onAddClick = onAddClick,
modifier = modifier.padding(it)
)
}
}
@Composable
fun PolyculeHomeScreen(
onBioClick: (Bio) -> Unit,
onAddClick: () -> Unit = {},
modifier: Modifier,
) {
val mBioListViewModel: BioListViewModel = viewModel(
factory = BioListViewModel.BioListViewModelFactory()
)
val items = mBioListViewModel.allBios.observeAsState(listOf()).value
Column(
modifier = modifier
) {
BioCardList(bioList = items, onBioClick = onBioClick)
FloatingActionButton(
onClick = onAddClick
) {
Icon(Icons.Filled.Add, "Add Bio")
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PolyculeTopAppBar(
onFilterClick: () -> Unit,
modifier: Modifier = Modifier,
scrollBehavior: TopAppBarScrollBehavior,
) {
TopAppBar(
title = {
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
) {
}
},
modifier = modifier.statusBarsPadding(),
actions = {},
scrollBehavior = scrollBehavior
)
}

View file

@ -0,0 +1,36 @@
package com.menagerie.ophelia.view.splash
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.lifecycleScope
import com.menagerie.ophelia.MainActivity
import kotlinx.coroutines.delay
@SuppressLint("CustomSplashScreen")
class SplashActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { true }
}
super.onCreate(savedInstanceState)
//TODO : Figure out how to update this properly
lifecycleScope.launchWhenCreated {
delay(1500)
val intent = Intent(
this@SplashActivity,
MainActivity::class.java
)
startActivity(intent)
finish()
}
}
}

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M15.73,3H8.27L3,8.27v7.46L8.27,21h7.46L21,15.73V8.27L15.73,3zM17,15.74L15.74,17 12,13.26 8.26,17 7,15.74 10.74,12 7,8.26 8.26,7 12,10.74 15.74,7 17,8.26 13.26,12 17,15.74z"/>
</vector>

View file

@ -0,0 +1,7 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M10.1,15.9l1.42,-1.42C8.79,12.05 7,10.41 7,8.85C7,7.8 7.8,7 8.85,7c1.11,0 1.54,0.65 2.68,2h0.93c1.12,-1.31 1.53,-2 2.68,-2c0.87,0 1.55,0.54 1.77,1.32c0.35,-0.04 0.68,-0.06 1,-0.06c0.36,0 0.7,0.03 1.03,0.08C18.7,6.43 17.13,5 15.15,5c-0.12,0 -0.23,0.03 -0.35,0.04C14.92,4.71 15,4.37 15,4c0,-1.66 -1.34,-3 -3,-3S9,2.34 9,4c0,0.37 0.08,0.71 0.2,1.04C9.08,5.03 8.97,5 8.85,5C6.69,5 5,6.69 5,8.85C5,11.27 7.04,13.16 10.1,15.9z"/>
<path android:fillColor="@android:color/white" android:pathData="M22.5,16.24c-0.32,-0.18 -0.66,-0.29 -1,-0.35c0.07,-0.1 0.15,-0.18 0.21,-0.28c1.08,-1.87 0.46,-4.18 -1.41,-5.26c-2.09,-1.21 -4.76,-0.39 -8.65,0.9l0.52,1.94c3.47,-1.14 5.79,-1.88 7.14,-1.1c0.91,0.53 1.2,1.61 0.68,2.53c-0.56,0.96 -1.33,1 -3.07,1.32l-0.47,0.81c0.58,1.62 0.97,2.33 0.39,3.32c-0.53,0.91 -1.61,1.2 -2.53,0.68c-0.06,-0.03 -0.11,-0.09 -0.17,-0.13c-0.3,0.67 -0.64,1.24 -1.03,1.73c0.07,0.04 0.13,0.09 0.2,0.14c1.87,1.08 4.18,0.46 5.26,-1.41c0.06,-0.1 0.09,-0.21 0.14,-0.32c0.22,0.27 0.48,0.51 0.8,0.69c1.43,0.83 3.27,0.34 4.1,-1.1S23.93,17.06 22.5,16.24z"/>
<path android:fillColor="@android:color/white" android:pathData="M12.32,14.01c-0.74,3.58 -1.27,5.95 -2.62,6.73c-0.91,0.53 -2,0.24 -2.53,-0.68c-0.56,-0.96 -0.2,-1.66 0.39,-3.32L7.1,15.93c-1.7,-0.31 -2.5,-0.33 -3.07,-1.32c-0.53,-0.91 -0.24,-2 0.68,-2.53c0.09,-0.05 0.19,-0.08 0.29,-0.11c-0.35,-0.56 -0.64,-1.17 -0.82,-1.85c-0.16,0.07 -0.32,0.14 -0.48,0.23c-1.87,1.08 -2.49,3.39 -1.41,5.26c0.06,0.1 0.14,0.18 0.21,0.28c-0.34,0.06 -0.68,0.17 -1,0.35c-1.43,0.83 -1.93,2.66 -1.1,4.1s2.66,1.93 4.1,1.1c0.32,-0.18 0.58,-0.42 0.8,-0.69c0.05,0.11 0.08,0.22 0.14,0.32c1.08,1.87 3.39,2.49 5.26,1.41c2.09,-1.21 2.71,-3.93 3.55,-7.94L12.32,14.01z"/>
</vector>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/purple_200"/>
</item>
<item>
<bitmap
android:gravity="center"
android:src="@drawable/ic_app_logo"/>
</item>
</layer-list>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/purple_200"/>
</item>
<item
android:width="140dp"
android:height="180dp"
android:drawable="@drawable/ic_app_logo"
android:gravity="center" />
</layer-list>

View file

@ -0,0 +1,9 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4.5,9.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
<path android:fillColor="@android:color/white" android:pathData="M9,5.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
<path android:fillColor="@android:color/white" android:pathData="M15,5.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
<path android:fillColor="@android:color/white" android:pathData="M19.5,9.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
<path android:fillColor="@android:color/white" android:pathData="M17.34,14.86c-0.87,-1.02 -1.6,-1.89 -2.48,-2.91 -0.46,-0.54 -1.05,-1.08 -1.75,-1.32 -0.11,-0.04 -0.22,-0.07 -0.33,-0.09 -0.25,-0.04 -0.52,-0.04 -0.78,-0.04s-0.53,0 -0.79,0.05c-0.11,0.02 -0.22,0.05 -0.33,0.09 -0.7,0.24 -1.28,0.78 -1.75,1.32 -0.87,1.02 -1.6,1.89 -2.48,2.91 -1.31,1.31 -2.92,2.76 -2.62,4.79 0.29,1.02 1.02,2.03 2.33,2.32 0.73,0.15 3.06,-0.44 5.54,-0.44h0.18c2.48,0 4.81,0.58 5.54,0.44 1.31,-0.29 2.04,-1.31 2.33,-2.32 0.31,-2.04 -1.3,-3.49 -2.61,-4.8z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View file

@ -1,170 +0,0 @@
<?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>

View file

@ -1,30 +0,0 @@
<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>

View file

@ -0,0 +1,6 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3,14c0,1.3 0.84,2.4 2,2.82V20H3v2h6v-2H7v-3.18C8.16,16.4 9,15.3 9,14V6H3V14zM5,8h2v3H5V8z"/>
<path android:fillColor="@android:color/white" android:pathData="M20.63,8.54l-0.95,-0.32C19.28,8.09 19,7.71 19,7.28V3c0,-0.55 -0.45,-1 -1,-1h-3c-0.55,0 -1,0.45 -1,1v4.28c0,0.43 -0.28,0.81 -0.68,0.95l-0.95,0.32C11.55,8.82 11,9.58 11,10.44V20c0,1.1 0.9,2 2,2h7c1.1,0 2,-0.9 2,-2v-9.56C22,9.58 21.45,8.82 20.63,8.54zM16,4h1v1h-1V4zM13,10.44l0.95,-0.32C15.18,9.72 16,8.57 16,7.28V7h1v0.28c0,1.29 0.82,2.44 2.05,2.85L20,10.44V12h-7V10.44zM20,20h-7v-2h7V20z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,12c0,-1.1 -0.9,-2 -2,-2V7c0,-1.1 -0.9,-2 -2,-2H8C6.9,5 6,5.9 6,7v3c-1.1,0 -2,0.9 -2,2v5h1.33L6,19h1l0.67,-2h8.67L17,19h1l0.67,-2H20V12zM16,10h-3V7h3V10zM8,7h3v3H8V7zM6,12h12v3H6V12z"/>
</vector>

View file

@ -0,0 +1,10 @@
<?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="#7dae7d"
android:pathData="M0,0h108v108h-108z" />
</vector>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,9 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M22,9l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0l0,-2z"/>
<path android:fillColor="@android:color/white" android:pathData="M8,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4S4,5.79 4,8S5.79,12 8,12z"/>
<path android:fillColor="@android:color/white" android:pathData="M8,13c-2.67,0 -8,1.34 -8,4v3h16v-3C16,14.34 10.67,13 8,13z"/>
<path android:fillColor="@android:color/white" android:pathData="M12.51,4.05C13.43,5.11 14,6.49 14,8s-0.57,2.89 -1.49,3.95C14.47,11.7 16,10.04 16,8S14.47,4.3 12.51,4.05z"/>
<path android:fillColor="@android:color/white" android:pathData="M16.53,13.83C17.42,14.66 18,15.7 18,17v3h2v-3C20,15.55 18.41,14.49 16.53,13.83z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,7.77L18.39,18H5.61L12,7.77M12,4L2,20h20L12,4z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,8c1.93,0 3.5,1.57 3.5,3.5S13.93,15 12,15s-3.5,-1.57 -3.5,-3.5S10.07,8 12,8zM16.53,8.38l3.97,-3.96V7h2V1h-6v2h2.58l-3.97,3.97C14.23,6.36 13.16,6 12,6c-1.16,0 -2.23,0.36 -3.11,0.97L8.24,6.32l1.41,-1.41L8.24,3.49L6.82,4.9L4.92,3H7.5V1h-6v6h2V4.42l1.91,1.9L3.99,7.74l1.41,1.41l1.41,-1.41l0.65,0.65C6.86,9.27 6.5,10.34 6.5,11.5c0,2.7 1.94,4.94 4.5,5.41L11,19H9v2h2v2h2v-2h2v-2h-2l0,-2.09c2.56,-0.47 4.5,-2.71 4.5,-5.41C17.5,10.34 17.14,9.27 16.53,8.38z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,20H2v-2h5.75l0,0C7.02,15.19 4.81,12.99 2,12.26C2.64,12.1 3.31,12 4,12C8.42,12 12,15.58 12,20zM22,12.26C21.36,12.1 20.69,12 20,12c-2.93,0 -5.48,1.58 -6.88,3.93c0.29,0.66 0.53,1.35 0.67,2.07c0.13,0.65 0.2,1.32 0.2,2h2h6v-2h-5.75C16.98,15.19 19.19,12.99 22,12.26zM15.64,11.02c0.78,-2.09 2.23,-3.84 4.09,-5C15.44,6.16 12,9.67 12,14c0,0.01 0,0.02 0,0.02C12.95,12.75 14.2,11.72 15.64,11.02zM11.42,8.85C10.58,6.66 8.88,4.89 6.7,4C8.14,5.86 9,8.18 9,10.71c0,0.21 -0.03,0.41 -0.04,0.61c0.43,0.24 0.83,0.52 1.22,0.82C10.39,10.96 10.83,9.85 11.42,8.85z"/>
</vector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderPackage="com.google.android.gms"
app:fontProviderQuery="Alex Brush"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

Binary file not shown.

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderPackage="com.google.android.gms"
app:fontProviderQuery="Calligraffitti"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
<font
android:fontStyle="normal"
android:fontWeight="400"
android:font="@font/alex_brush"/>
</font-family>

View file

@ -1,6 +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" />
<background android:drawable="@drawable/ophelia_background" />
<foreground android:drawable="@drawable/ophelia_foreground" />
<monochrome android:drawable="@drawable/ophelia_foreground" />
</adaptive-icon>

View file

@ -1,6 +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" />
<background android:drawable="@drawable/ophelia_background" />
<foreground android:drawable="@drawable/ophelia_foreground" />
<monochrome android:drawable="@drawable/ophelia_foreground" />
</adaptive-icon>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph">
</navigation>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Ophelia" parent="android:ThemeOverlay.Material.Dark.ActionBar" />
<style name="SplashScreenTheme" parent="Theme.Ophelia">
<item name="windowSplashScreenBackground">@color/purple_200</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/bg_splash_12</item>
<item name="windowSplashScreenAnimationDuration">800</item>
<item name="postSplashScreenTheme">@style/Theme.Ophelia</item>
</style>
</resources>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Per Material Design specs: -->
<!-- https://material.io/design/components/buttons-floating-action-button.html#specs -->
<dimen name="fab_margin">16dp</dimen>
<!-- Padding on the bottom of a screen so that the FAB won't overlap scrolled text. -->
<dimen name="fab_bottom_padding">72dp</dimen>
<dimen name="plant_detail_app_bar_height">278dp</dimen>
<dimen name="margin_normal">16dp</dimen>
<dimen name="margin_small">8dp</dimen>
<dimen name="margin_extra_small">4dp</dimen>
<dimen name="padding_large">48dp</dimen>
<dimen name="plant_item_image_height">95dp</dimen>
<dimen name="card_side_margin">12dp</dimen>
<dimen name="card_bottom_margin">26dp</dimen>
<dimen name="card_elevation">2dp</dimen>
<dimen name="card_corner_radius">12dp</dimen>
<!-- elevation for Plant Detail toolbar - used to convert to pixels when hiding/showing -->
<dimen name="toolbar_elevation">5dp</dimen>
<!-- Plant List Header margin -->
<dimen name="header_margin">24dp</dimen>
<dimen name="gallery_header_margin">72dp</dimen>
<!-- minimum height of plant detail page so that the collapsing toolbar can be shown on every page -->
<dimen name="plant_description_min_height">555dp</dimen>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="com_google_android_gms_fonts_certs">
<item>@array/com_google_android_gms_fonts_certs_dev</item>
<item>@array/com_google_android_gms_fonts_certs_prod</item>
</array>
<string-array name="com_google_android_gms_fonts_certs_dev">
<item>
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
</item>
</string-array>
<string-array name="com_google_android_gms_fonts_certs_prod">
<item>
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
</item>
</string-array>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="preloaded_fonts" translatable="false">
<item>@font/alex_brush</item>
<item>@font/calligraffitti</item>
</array>
</resources>

View file

@ -1,3 +1,68 @@
<resources>
##App Main
<string name="app_name">Ophelia</string>
<string name="app_tag">A Polycule Pocket-dex</string>
<string name="welcome">Get Started</string>
<string name="welcome_back">Welcome Back</string>
##Routes
<string name="route_polyculeHome">polyculeHome</string>
<string name="route_home">home</string>
##Bio
<string name="add_bio">Add Bio</string>
<string name="edit_bio">Edit Bio</string>
<string name="finish">Finish</string>
<string name="bio_load">Bio Loaded</string>
<string name="open_context_menu">Open context menu</string>
<string name="name">Name</string>
<string name="bio_add_toast">New Bio Added!</string>
<string name="bio_edit_toast">Bio Edited!</string>
<string name="bio_finish_toast">Welcome Aboard!</string>
##Tags
<string name="mono">Monogamous</string>
<string name="plural">Plural</string>
<string name="furry">Furry</string>
<string name="therian">Therian</string>
<string name="bdsm">BDSM</string>
<string name="alcohol">Alcohol</string>
<string name="weed">Weed</string>
<string name="asexual">Asexual</string>
<string name="trans">Transgender</string>
##Ophelia
<string name = "ophelia_says">Ophelia Says</string>
<string name = "final_check_in">What do you think; looks like you?</string>
<string-array name="welcome_blurb">
<item>Hi!</item>
<item>I\'m Ophelia, a Polycule companion system designed to help you keep track of your metas, reference a charter, and find things in common with your polycule.</item>
<item>I\'m meant to work dynamically with how polyamory works for you, so what all those words mean will be something we work out together later.</item>
<item>First, I need to get to know "you".</item>
<item>Click Go to get started.</item>
</string-array>
<string-array name="whats_your_name">
<item>I\'m Ophelia, what\'s your name\?</item>
<item>Your Name is how you\'ll be addressed in the app, and is the primary way you\'ll be referred to in polycules.</item>
<item>But don\'t worry; your name, like everything about you, can be changed at any time!</item>
</string-array>
<string name="introduction_with_name">"Nice to meet you,%1$s!</string>
<string-array name="introduction_to_pronouns">
<item>Personal Pronouns are words used to refer to a person without always using their name.</item>
<item>Since Pronouns are a personal choice, I want to leave them as open as possible for you!</item>
<item>We\'re dealing with four Personal Pronouns, and using mine as an example: She (subjective) / Her (objective) / Hers (possessive) / Herself (reflexive)</item>
<item>Your Pronouns will be used when referring to you in specific contexts, and are displayed alongside your name in most contexts.</item>
</string-array>
<string-array name="introduction_to_tags">
<item>Tags are a way to highlight important things about yourself.</item>
<item>They also lead to more detailed parts of you bio, where you can flesh out specific parts of your bio.</item>
</string-array>
<string-array name="introduction_to_polycules">
<item>Great!</item>
<item>Now, there\'s just one more thing! We need to create a polycule for you. A "polycule" for our purposes is defined as a group of people with a shared relationship process.</item>
<item>A person may be in a polycule with any number of people, including just themselves, and in any number of polycules.</item>
<item>All we need to get started is a name:</item>
</string-array>
</resources>

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Ophelia" parent="android:Theme.Material.Light.NoActionBar" />
<style name="SplashScreenTheme" parent="Theme.Ophelia">
<item name="android:windowBackground">@drawable/bg_splash</item>
</style>
</resources>

View file

@ -1,5 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.1.2' apply false
id 'com.android.application' version '8.1.3' apply false
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
}