diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml new file mode 100644 index 0000000..21e3fd5 --- /dev/null +++ b/.idea/androidTestResultsUserPreferences.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index fb7f553..5e9f12b 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -13,6 +13,9 @@ + + \ No newline at end of file diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..94c96f6 --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,318 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 66d194b..fa8fd14 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -86,46 +86,92 @@ protobuf { } dependencies { - implementation(libs.androidx.material3.adaptive.navigation.suite.android) + + // Android Test Dependencies + androidTestImplementation(libs.testing) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.ui.test.junit4) androidTestImplementation(platform(libs.androidx.compose.bom)) - debugImplementation(libs.androidx.ui.test.manifest) - debugImplementation(libs.androidx.ui.tooling) + + // Activity Compose implementation(libs.androidx.activity.compose) + + // AndroidX Core KTX implementation(libs.androidx.core.ktx) + + // Compose Runtime implementation(libs.androidx.compose.runtime) implementation(libs.androidx.compose.runtime.tracing) implementation(libs.androidx.tracing.ktx) + + // Lifecycle implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtimeCompose) implementation(libs.androidx.lifecycle.runtimeTesting) + + // Material 3 implementation(libs.androidx.material3) implementation(libs.androidx.compose.material3.adaptive) implementation(libs.androidx.compose.material3.adaptive.layout) implementation(libs.androidx.compose.material3.adaptive.navigation) implementation(libs.androidx.compose.material3.windowSizeClass) + implementation(libs.androidx.material3.adaptive.navigation.suite.android) + + // Datastore implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.datastore) + + // Navigation implementation(libs.androidx.navigation.compose) + + // Compose UI implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) + debugImplementation(libs.androidx.ui.test.manifest) + debugImplementation(libs.androidx.ui.tooling) + + // Dagger Hilt implementation(libs.dagger.hilt.android) implementation(libs.dagger.hilt.testing) + + // Room Database + implementation(libs.room.ktx) + implementation(libs.room.paging) + + // Firebase implementation(libs.firebase.analytics) implementation(libs.firebase.auth) + + // ProtoBuf implementation(libs.google.protobuf.java) + + // Hilt Navigation implementation(libs.hilt.navigation.compose) + + // Datetime implementation(libs.kotlinx.datetime) + + // Coroutines implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.android) + + // Kotlin implementation(libs.kotlin.stdlib) + + // Compose BOM implementation(platform(libs.androidx.compose.bom)) + + // Firebase BOM implementation(platform(libs.firebase.bom)) + + // KSP ksp(libs.dagger.hilt.android) ksp(libs.dagger.hilt.compiler) + ksp(libs.room.compiler) + + testImplementation(libs.room.testing) testImplementation(libs.mockk) testImplementation(libs.mockk.android) testImplementation(libs.kotlinx.coroutines.test) diff --git a/app/src/androidTest/java/com/rjwalker/within/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/rjwalker/within/ExampleInstrumentedTest.kt deleted file mode 100644 index 0861ee2..0000000 --- a/app/src/androidTest/java/com/rjwalker/within/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.rjwalker.within - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.rjwalker.within", appContext.packageName) - } -} \ No newline at end of file diff --git a/app/src/androidTest/java/com/rjwalker/within/database/AgendaDaoTest.kt b/app/src/androidTest/java/com/rjwalker/within/database/AgendaDaoTest.kt new file mode 100644 index 0000000..efa50e1 --- /dev/null +++ b/app/src/androidTest/java/com/rjwalker/within/database/AgendaDaoTest.kt @@ -0,0 +1,67 @@ +package com.rjwalker.within.database + +import android.content.Context +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider +import com.rjwalker.within.database.dao.AgendaDao +import com.rjwalker.within.database.model.AgendaEntity +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +class AgendaDaoTest { + + private lateinit var agendaDao: AgendaDao + private lateinit var db: WithinDatabase + + @Before + fun createDb() { + val context = ApplicationProvider.getApplicationContext() + db = Room.inMemoryDatabaseBuilder( + context, + WithinDatabase::class.java, + ).build() + agendaDao = db.agendaDao() + } + + @After + fun closeDb() = db.close() + + @Test + fun agendaDao_filter_items_by_isCompleted() = runTest { + val agendaEntities = listOf( + testAgendaEntity(isCompleted = true), + testAgendaEntity(isCompleted = true), + testAgendaEntity(isCompleted = false), + testAgendaEntity(isCompleted = false), + testAgendaEntity(isCompleted = false), + ) + + agendaDao.insertAllAgenda(agendaEntities) + + val savedAgendaEntities = agendaDao.getAllAgenda() + + TODO("Not yet implemented - Will Complete in future branch") + +// assertEquals(agendaEntities.size, savedAgendaEntities.size) +// +// val completedAgendaEntities = savedAgendaEntities.filter { it.isCompleted } +// +// assertEquals(2, completedAgendaEntities.size) + } + +} + +private fun testAgendaEntity( + id: Int = 0, + isCompleted: Boolean = false +) = AgendaEntity( + id = id, + title = "title", + description = "description", + time = "time", + isCompleted = isCompleted, + weekStartDate = 0 +) \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/data/di/WithinModule.kt b/app/src/main/java/com/rjwalker/within/data/di/WithinModule.kt index 9499c9f..b1672c5 100644 --- a/app/src/main/java/com/rjwalker/within/data/di/WithinModule.kt +++ b/app/src/main/java/com/rjwalker/within/data/di/WithinModule.kt @@ -1,5 +1,7 @@ package com.rjwalker.within.data.di +import com.rjwalker.within.data.repository.AgendaRepository +import com.rjwalker.within.data.repository.HomeAgendaRepository import com.rjwalker.within.data.util.ConnectivityManagerNetworkMonitor import com.rjwalker.within.data.util.NetworkMonitor import com.rjwalker.within.data.util.TimeZoneBroadcastMonitor @@ -20,4 +22,9 @@ abstract class WithinModule { @Binds internal abstract fun binds(impl: TimeZoneBroadcastMonitor): TimeZoneMonitor + @Binds + internal abstract fun bindsAgendaRepository( + agendaRepository: HomeAgendaRepository + ): AgendaRepository + } \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/data/model/Agenda.kt b/app/src/main/java/com/rjwalker/within/data/model/Agenda.kt new file mode 100644 index 0000000..41b1762 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/data/model/Agenda.kt @@ -0,0 +1,10 @@ +package com.rjwalker.within.data.model + +data class Agenda( + val id: Int, + val title: String, + val description: String, + val time: String, + val isCompleted: Boolean, + val weekStartDate: Long +) diff --git a/app/src/main/java/com/rjwalker/within/data/repository/AgendaRepository.kt b/app/src/main/java/com/rjwalker/within/data/repository/AgendaRepository.kt new file mode 100644 index 0000000..79f5642 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/data/repository/AgendaRepository.kt @@ -0,0 +1,14 @@ +package com.rjwalker.within.data.repository + +import com.rjwalker.within.data.model.Agenda +import kotlinx.coroutines.flow.Flow + +interface AgendaRepository { + + fun getAgendas(): Flow> + + fun getAgenda(id: Int): Flow + + fun getAgendaForWeek(weekStartDate: Long): Flow> + +} \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/data/repository/HomeAgendaRepository.kt b/app/src/main/java/com/rjwalker/within/data/repository/HomeAgendaRepository.kt new file mode 100644 index 0000000..b45e947 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/data/repository/HomeAgendaRepository.kt @@ -0,0 +1,27 @@ +package com.rjwalker.within.data.repository + +import com.rjwalker.within.data.model.Agenda +import com.rjwalker.within.database.dao.AgendaDao +import com.rjwalker.within.database.model.AgendaEntity +import com.rjwalker.within.database.model.asExternalModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class HomeAgendaRepository @Inject constructor( + private val agendaDao: AgendaDao +) : AgendaRepository { + override fun getAgendas(): Flow> = + agendaDao.getAllAgenda() + .map { it.map(AgendaEntity::asExternalModel) } + + + override fun getAgenda(id: Int): Flow = + agendaDao.getAgenda(id).map { it.asExternalModel() } + + override fun getAgendaForWeek(weekStartDate: Long): Flow> { + TODO("Not yet implemented") + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/database/WithinDatabase.kt b/app/src/main/java/com/rjwalker/within/database/WithinDatabase.kt new file mode 100644 index 0000000..5a5d247 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/database/WithinDatabase.kt @@ -0,0 +1,16 @@ +package com.rjwalker.within.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.rjwalker.within.database.dao.AgendaDao +import com.rjwalker.within.database.model.AgendaEntity + +@Database(entities = [ + AgendaEntity::class + ], + version = 1 +) + +internal abstract class WithinDatabase : RoomDatabase() { + abstract fun agendaDao(): AgendaDao +} \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/database/dao/AgendaDao.kt b/app/src/main/java/com/rjwalker/within/database/dao/AgendaDao.kt new file mode 100644 index 0000000..b568604 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/database/dao/AgendaDao.kt @@ -0,0 +1,30 @@ +package com.rjwalker.within.database.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Upsert +import com.rjwalker.within.database.model.AgendaEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface AgendaDao { + @Insert + suspend fun insertAgenda(agenda: AgendaEntity) + + @Insert + suspend fun insertAllAgenda(agenda: List) + + @Query(value = "SELECT * FROM agendas WHERE weekStartDate = :weekStartDate") + fun getAgendaForWeek(weekStartDate: Long): List + + @Query(value = "SELECT * FROM agendas WHERE id = :id") + fun getAgenda(id: Int): Flow + + @Query(value = "SELECT * FROM agendas") + fun getAllAgenda(): Flow> + + @Delete + suspend fun deleteAgenda(agenda: AgendaEntity) +} \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/database/di/DaosModule.kt b/app/src/main/java/com/rjwalker/within/database/di/DaosModule.kt new file mode 100644 index 0000000..0c256e9 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/database/di/DaosModule.kt @@ -0,0 +1,17 @@ +package com.rjwalker.within.database.di + +import com.rjwalker.within.database.WithinDatabase +import com.rjwalker.within.database.dao.AgendaDao +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +internal object DaosModule { + @Provides + fun providesAgendaDao( + database: WithinDatabase, + ): AgendaDao = database.agendaDao() +} \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/database/di/DatabaseModule.kt b/app/src/main/java/com/rjwalker/within/database/di/DatabaseModule.kt new file mode 100644 index 0000000..1117310 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/database/di/DatabaseModule.kt @@ -0,0 +1,25 @@ +package com.rjwalker.within.database.di + +import android.content.Context +import androidx.room.Room +import com.rjwalker.within.database.WithinDatabase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object DatabaseModule { + @Provides + @Singleton + fun providesWithinDatabase( + @ApplicationContext context: Context, + ): WithinDatabase = Room.databaseBuilder( + context, + WithinDatabase::class.java, + "within-database" + ).build() +} diff --git a/app/src/main/java/com/rjwalker/within/database/model/AgendaEntity.kt b/app/src/main/java/com/rjwalker/within/database/model/AgendaEntity.kt new file mode 100644 index 0000000..925ce7a --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/database/model/AgendaEntity.kt @@ -0,0 +1,26 @@ +package com.rjwalker.within.database.model + +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.rjwalker.within.data.model.Agenda + +@Entity( + tableName = "agendas" +) +data class AgendaEntity( + @PrimaryKey(autoGenerate = true) val id: Int = 0, + val title: String, + val description: String, + val time: String, + val isCompleted: Boolean, + val weekStartDate: Long +) + +fun AgendaEntity.asExternalModel() = Agenda( + id = id, + title = title, + description = description, + time = time, + isCompleted = isCompleted, + weekStartDate = weekStartDate +) diff --git a/app/src/main/java/com/rjwalker/within/design/components/HomeTabScreen.kt b/app/src/main/java/com/rjwalker/within/design/components/HomeTabScreen.kt new file mode 100644 index 0000000..cd61122 --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/design/components/HomeTabScreen.kt @@ -0,0 +1,99 @@ +package com.rjwalker.within.design.components + +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.material3.Checkbox +import androidx.compose.material3.Icon +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.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.rjwalker.within.R +import com.rjwalker.within.design.icons.WithinIcons + +@Composable +fun HomeTabScreen() { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + ) { + Text( + text = stringResource(id = R.string.todays_agenda), + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.weight(1f) + ) + Icon(imageVector = WithinIcons.EnterArrow, contentDescription = null) + } + } +} + +@Composable +fun AgendaItem( + title: String, + description: String, + time: String, + isCompleted: Boolean +) { + var checked by remember { mutableStateOf(isCompleted) } + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Row { + Text( + text = title, + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.weight(1f) + ) + Text( + text = time, + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.weight(1f) + ) + Checkbox(checked = checked, onCheckedChange = {checked = it} ) + } + Row { + Text( + text = description, + style = MaterialTheme.typography.bodySmall, + modifier = Modifier.weight(1f) + ) + } + + } +} + + + +@ThemePreviews +@Composable +fun HomeTabScreenPreview() { + HomeTabScreen() +} + +@ThemePreviews +@Composable +fun AgendaItemPreview() { + AgendaItem( + title = "Sample Title", + description = "Sample Description", + time = "Sample Time", + isCompleted = false + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/design/components/OnboardingComponent.kt b/app/src/main/java/com/rjwalker/within/design/components/OnboardingComponent.kt new file mode 100644 index 0000000..a55957b --- /dev/null +++ b/app/src/main/java/com/rjwalker/within/design/components/OnboardingComponent.kt @@ -0,0 +1,49 @@ +package com.rjwalker.within.design.components + +import androidx.compose.foundation.background +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.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.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.rjwalker.within.R + +@Composable +fun OnboardingComponent(isUserNew: Boolean) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp) + .background(Color.White), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top + ) { + + Row { + Text( + text = stringResource(id = R.string.welcome_title), + style = MaterialTheme.typography.headlineLarge, + ) + } + Row { + Text(text = stringResource(id = R.string.welcome_body_1)) + } + Row { + Text(text = stringResource(id = R.string.welcome_body_2)) + } + } +} + +@ThemePreviews +@Composable +fun WelcomeComponentPreview() { + OnboardingComponent(isUserNew = true) +} \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/design/components/WithinBottomAppBar.kt b/app/src/main/java/com/rjwalker/within/design/components/WithinBottomAppBar.kt index b694350..cb8ccdf 100644 --- a/app/src/main/java/com/rjwalker/within/design/components/WithinBottomAppBar.kt +++ b/app/src/main/java/com/rjwalker/within/design/components/WithinBottomAppBar.kt @@ -151,10 +151,6 @@ fun WithinNavigationSuiteScaffold( } } -//@ThemePreviews -//@Composable - - class WithinNavigationSuiteScope internal constructor( private val navigationSuiteScope: NavigationSuiteScope, private val navigationSuiteItemColors: NavigationSuiteItemColors diff --git a/app/src/main/java/com/rjwalker/within/design/icons/WithinIcons.kt b/app/src/main/java/com/rjwalker/within/design/icons/WithinIcons.kt index 9f07603..e588311 100644 --- a/app/src/main/java/com/rjwalker/within/design/icons/WithinIcons.kt +++ b/app/src/main/java/com/rjwalker/within/design/icons/WithinIcons.kt @@ -1,11 +1,18 @@ package com.rjwalker.within.design.icons import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowForward +import androidx.compose.material.icons.automirrored.filled.List +import androidx.compose.material.icons.automirrored.rounded.List +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.ArrowForward import androidx.compose.material.icons.filled.Build +import androidx.compose.material.icons.filled.Create import androidx.compose.material.icons.filled.Face import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.Build +import androidx.compose.material.icons.rounded.Create import androidx.compose.material.icons.rounded.Face import androidx.compose.material.icons.rounded.Home @@ -13,8 +20,14 @@ object WithinIcons { val Add = Icons.Rounded.Add val Home = Icons.Rounded.Home val Fire = Icons.Rounded.Build + val Tasks = Icons.AutoMirrored.Rounded.List + val Journal = Icons.Rounded.Create val Friends = Icons.Rounded.Face val HomeFilled = Icons.Filled.Home val FireFilled = Icons.Filled.Build val FriendsFilled = Icons.Filled.Face + val JournalFilled = Icons.Filled.Create + val TasksFilled = Icons.AutoMirrored.Filled.List + val EnterArrow = Icons.AutoMirrored.Filled.ArrowForward + } \ No newline at end of file diff --git a/app/src/main/java/com/rjwalker/within/ui/WithinApp.kt b/app/src/main/java/com/rjwalker/within/ui/WithinApp.kt index 1f17b99..846484e 100644 --- a/app/src/main/java/com/rjwalker/within/ui/WithinApp.kt +++ b/app/src/main/java/com/rjwalker/within/ui/WithinApp.kt @@ -3,6 +3,10 @@ package com.rjwalker.within.ui import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState @@ -17,6 +21,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.rjwalker.within.R +import com.rjwalker.within.design.components.WithinBackground +import com.rjwalker.within.design.components.WithinNavigationBar +import com.rjwalker.within.design.components.WithinNavigationBarItem +import com.rjwalker.within.design.components.WithinTopAppBar +import com.rjwalker.within.design.icons.WithinIcons @Composable fun WithinApp( @@ -25,25 +34,27 @@ fun WithinApp( windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(), ) { - val snackBarHostState = remember { SnackbarHostState() } - val isOffline by appState.isOffline.collectAsStateWithLifecycle() + WithinBackground(modifier = modifier) { + val snackBarHostState = remember { SnackbarHostState() } + val isOffline by appState.isOffline.collectAsStateWithLifecycle() - val notConnectedSnackBar = stringResource(id = R.string.not_connected) - LaunchedEffect(isOffline) { - if (isOffline) { - snackBarHostState.showSnackbar( - message = notConnectedSnackBar, - duration = SnackbarDuration.Indefinite - ) + val notConnectedSnackBar = stringResource(id = R.string.not_connected) + LaunchedEffect(isOffline) { + if (isOffline) { + snackBarHostState.showSnackbar( + message = notConnectedSnackBar, + duration = SnackbarDuration.Indefinite + ) + } } - } - WithinApp( - appState = appState, - snackBarHostState = snackBarHostState, - modifier = modifier, - windowAdaptiveInfo = windowAdaptiveInfo - ) + WithinApp( + appState = appState, + snackBarHostState = snackBarHostState, + modifier = modifier, + windowAdaptiveInfo = windowAdaptiveInfo + ) + } } @@ -55,15 +66,61 @@ internal fun WithinApp( windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(), ) { val currentDestination = appState.currentDestination + val items = listOf(R.string.home, R.string.tasks, R.string.journal) + val icons = listOf( + WithinIcons.Home, + WithinIcons.Tasks, + WithinIcons.Journal + ) + val selectedIcons = listOf( + WithinIcons.HomeFilled, + WithinIcons.TasksFilled, + WithinIcons.JournalFilled + ) - Scaffold { padding -> + Scaffold( + topBar = { + WithinTopAppBar( + titleRes = R.string.app_name, + navigationIcon = Icons.AutoMirrored.Filled.ArrowBack, + navigationIconContentDescription = "Back", + actionIcon = Icons.Filled.Settings, + actionIconContentDescription = "Settings" + ) + }, + bottomBar = { + WithinNavigationBar{ + items.forEachIndexed { index, item -> + WithinNavigationBarItem( + icon = { + Icon( + imageVector = icons[index], + contentDescription = item.toString() + ) + }, + selectedIcon = { + Icon( + imageVector = selectedIcons[index], + contentDescription = item.toString() + ) + }, + label = { Text(stringResource(id = item)) }, + selected = index == 0, + onClick = { } + ) + } + } + } + ) { padding -> Column( Modifier .fillMaxSize() .padding(padding) ) { val destination = appState.currentTopLevelDestination - Text(text = "Hello World!") + + + //WelcomeComponent(isUserNew = true) } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f5285b9..c16c65c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,6 +2,8 @@ Within Login Home + Journal + Tasks AI Profile Sign up" @@ -10,9 +12,13 @@ Back Email Username + Today\'s Agenda: Forgot Password? Already have an account? Need to signup? You are not connected to the internet + Welcome to Within!" + This app\'s main purpose is to become a productive tool for all to achieve any goal they set in life. + We accomplish this by creating supportive tools & a supportive community where everyone can share their ideas to become the best version of themselves and to become the person of their dreams! \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index df0ecb2..d44ba23 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,5 +1,9 @@ - \ No newline at end of file diff --git a/app/src/test/java/com/rjwalker/within/ExampleUnitTest.kt b/app/src/test/java/com/rjwalker/within/ExampleUnitTest.kt deleted file mode 100644 index d3f6223..0000000 --- a/app/src/test/java/com/rjwalker/within/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.rjwalker.within - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index db48462..6e944d0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,8 @@ protobufPlugin = "0.9.4" material3AdaptiveNavigationSuiteAndroid = "1.3.0-rc01" mockk = "1.13.12" turbine = "1.1.0" +room = "2.6.1" +testing = "6.9.6" [libraries] androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } @@ -70,8 +72,15 @@ kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx- kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } +room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } +room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } +room-testing = { group = "androidx.room", name = "room-testing", version.ref = "room" } +room-paging = { group = "androidx.room", name = "room-paging", version.ref = "room" } + + mockk-android = { group = "io.mockk", name = "mockk-android", version.ref = "mockk" } app-cash-turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine" } +testing = { group = "org.testng", name = "testng", version.ref = "testing" } [plugins]