Skip to content

Commit

Permalink
Update Compose, Coil, AnimatedNavHost, and Datastore
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarr21 committed Oct 28, 2021
1 parent b64576a commit 0f2b92f
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 152 deletions.
42 changes: 20 additions & 22 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
val composeVersion = "1.0.0"
val accompanistVersion = "0.20.0"
val composeVersion = "1.0.4"
val coroutinesVersion = "1.3.8"
val flipperVersion = "0.55.0"
val hiltVersion = "2.36"
val kotlinVersion = "1.5.10"
val kotlinVersion = "1.5.31"
val roomVersion = "2.3.0"

plugins {
Expand All @@ -13,12 +14,12 @@ plugins {
}

android {
compileSdkVersion(30)
compileSdkVersion(31)
buildToolsVersion = "30.0.3"
defaultConfig {
applicationId = "io.github.jbarr21.appdialer"
minSdkVersion(23)
targetSdkVersion(30)
targetSdkVersion(31)
versionCode = 2
versionName = "0.0.3"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -57,40 +58,37 @@ android {
dependencies {
kapt("androidx.room:room-compiler:2.3.0")
kapt("com.google.dagger:hilt-android-compiler:$hiltVersion")
kapt("androidx.lifecycle:lifecycle-compiler:2.3.1")
kapt("androidx.lifecycle:lifecycle-compiler:2.4.0")

implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
implementation("androidx.activity:activity-compose:1.3.0-beta02")
implementation("androidx.activity:activity-ktx:1.3.0-beta02")
implementation("androidx.appcompat:appcompat:1.3.0")
implementation("androidx.activity:activity-compose:1.4.0")
implementation("androidx.appcompat:appcompat:1.3.1")
implementation("androidx.compose.ui:ui:$composeVersion")
implementation("androidx.compose.ui:ui-tooling:$composeVersion")
implementation("androidx.compose.foundation:foundation:$composeVersion")
implementation("androidx.compose.material:material:$composeVersion")
implementation("androidx.compose.material:material-icons-core:$composeVersion")
implementation("androidx.compose.material:material-icons-extended:$composeVersion")
implementation("androidx.core:core-ktx:1.5.0")
implementation("androidx.datastore:datastore-preferences:1.0.0-alpha01")
implementation("androidx.core:core-ktx:1.7.0")
implementation("androidx.datastore:datastore-preferences:1.0.0")
implementation("androidx.hilt:hilt-navigation-compose:1.0.0-alpha03")
implementation("com.google.dagger:hilt-android:$hiltVersion")
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
implementation("androidx.lifecycle:lifecycle-runtime:2.3.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.1")
implementation("androidx.lifecycle:lifecycle-viewmodel:2.3.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1")
implementation("androidx.navigation:navigation-compose:2.4.0-alpha03")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0")
implementation("androidx.navigation:navigation-compose:2.4.0-alpha10")
implementation("androidx.palette:palette:1.0.0")
implementation("androidx.room:room-ktx:$roomVersion")
implementation("androidx.room:room-runtime:$roomVersion")
implementation("com.google.accompanist:accompanist-coil:0.11.1")
implementation("com.google.accompanist:accompanist-insets-ui:0.11.1")
implementation("com.google.accompanist:accompanist-swiperefresh:0.11.1")
implementation("com.google.accompanist:accompanist-systemuicontroller:0.11.1")
implementation("com.google.android.material:material:1.3.0")
implementation("com.google.accompanist:accompanist-insets-ui:$accompanistVersion")
implementation("com.google.accompanist:accompanist-navigation-animation:$accompanistVersion")
implementation("com.google.accompanist:accompanist-swiperefresh:$accompanistVersion")
implementation("com.google.accompanist:accompanist-systemuicontroller:$accompanistVersion")
implementation("com.google.android.material:material:1.4.0")
implementation("com.jakewharton:process-phoenix:2.0.0")
implementation("com.jakewharton.timber:timber:4.7.1")
implementation("io.coil-kt:coil:1.2.2")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("com.squareup.okhttp3:okhttp:4.9.2")
implementation("io.coil-kt:coil-compose:1.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")

debugImplementation("com.facebook.flipper:flipper:$flipperVersion")
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.AppDialer"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".ui.RootActivity">
<activity android:name=".ui.RootActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import io.github.jbarr21.appdialer.data.UserPreferencesRepo
import io.github.jbarr21.appdialer.data.db.AppDatabase
import io.github.jbarr21.appdialer.util.ActivityLauncher
import io.github.jbarr21.appdialer.util.AppIconFetcher
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
Expand Down Expand Up @@ -60,4 +62,8 @@ object AppModule {

@Provides
fun userManager(application: Application) = application.getSystemService<UserManager>()!!

@Singleton
@Provides
fun userPreferencesRepo(application: Application) = UserPreferencesRepo(application)
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package io.github.jbarr21.appdialer.data

import android.app.Application
import androidx.datastore.preferences.Preferences
import androidx.datastore.preferences.createDataStore
import androidx.datastore.preferences.edit
import androidx.datastore.preferences.emptyPreferences
import androidx.datastore.preferences.preferencesKey
import android.content.Context
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import timber.log.Timber
import java.io.IOException
import javax.inject.Inject

class UserPreferencesRepo @Inject constructor(private val application: Application) {
class UserPreferencesRepo(private val application: Application) {

private val dataStore = application.createDataStore(name = "user")
private val Context.dataStore by preferencesDataStore(name = "user")

private object Keys {
val USE_HAPTIC_FEEDBACK = preferencesKey<Boolean>("use_haptic_feedback")
val USE_PERSISTENT_SERVICE = preferencesKey<Boolean>("use_persistent_service")
val USE_HAPTIC_FEEDBACK = booleanPreferencesKey("use_haptic_feedback")
val USE_PERSISTENT_SERVICE = booleanPreferencesKey("use_persistent_service")
}

val userPreferencesFlow = dataStore.data
val userPreferencesFlow = application.dataStore.data
.catch { exception ->
if (exception is IOException) {
Timber.e(exception, "Error reading preferences")
Expand All @@ -47,13 +47,13 @@ class UserPreferencesRepo @Inject constructor(private val application: Applicati
suspend fun usePersistentService() = getValue(Keys.USE_PERSISTENT_SERVICE, false)

private suspend fun <T> updatePreference(key: Preferences.Key<T>, value: T) {
dataStore.edit { preferences ->
application.dataStore.edit { preferences ->
preferences[key] = value
}
}

private suspend fun <T> getValue(key: Preferences.Key<T>, defaultValue: T? = null): T {
return this.dataStore.data
return application.dataStore.data
.map { preferences -> preferences[key] ?: defaultValue }
.first()!!
}
Expand Down
17 changes: 11 additions & 6 deletions app/src/main/kotlin/io/github/jbarr21/appdialer/ui/AppDialerApp.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package io.github.jbarr21.appdialer.ui

import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.runtime.Composable
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.composable
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import io.github.jbarr21.appdialer.ui.info.InfoScreen
import io.github.jbarr21.appdialer.ui.main.MainScreen
import io.github.jbarr21.appdialer.ui.settings.SettingsScreen

@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AppDialerApp() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Screen.Main.toString()) {
val navController = rememberAnimatedNavController()
AnimatedNavHost(
navController = navController,
startDestination = Screen.Main.toString(),
) {
composable(Screen.Main.toString()) { MainScreen(hiltViewModel(), navController) }
composable(Screen.Settings.toString()) { SettingsScreen(hiltViewModel(), navController) }
composable(Screen.Info.toString()) { InfoScreen(hiltViewModel(), navController) }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
Expand Down Expand Up @@ -35,7 +34,8 @@ fun MainAppBottomSheet(
Surface(
color = Color.Black.copy(alpha = 0.5f),
modifier = Modifier
.fillMaxSize()
.fillMaxWidth()
.wrapContentHeight()
.clickable(onClick = onDismiss) // indication = null, interactionState = InteractionState()
) {
Surface(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package io.github.jbarr21.appdialer.ui.main

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.BottomSheetScaffold
import androidx.compose.material.BottomSheetValue
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.SnackbarHost
import androidx.compose.material.SnackbarHostState
import androidx.compose.material.ModalBottomSheetLayout
import androidx.compose.material.ModalBottomSheetState
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.Surface
import androidx.compose.material.rememberBottomSheetScaffoldState
import androidx.compose.material.rememberBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
Expand All @@ -21,47 +27,61 @@ import androidx.navigation.NavController
import io.github.jbarr21.appdialer.ui.AppTheme
import io.github.jbarr21.appdialer.ui.main.apps.AppGrid
import io.github.jbarr21.appdialer.ui.main.dialer.DialerGrid
import kotlinx.coroutines.launch

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun MainScreen(
viewModel: MainViewModel = viewModel(),
navController: NavController
) {
val snackbarHostState = remember { SnackbarHostState() }
val context = LocalContext.current

Surface(color = MaterialTheme.colors.background, modifier = Modifier.fillMaxSize()) {
Box {
AppGrid(
apps = viewModel.filteredApps,
query = viewModel.queryText,
isRefreshing = viewModel.isRefreshing,
onClick = { viewModel.onAppClicked(context, it) },
onLongClick = viewModel.onAppLongClicked,
onRefresh = { viewModel.loadApps(false) }
)
Box(modifier = Modifier.align(alignment = Alignment.BottomCenter)) {
DialerGrid(
buttons = viewModel.dialerLabels,
buttonColors = viewModel.buttonColors,
onClick = viewModel.onDialerClicked,
onLongClick = { viewModel.onDialerLongClickedDecorated(it, navController, snackbarHostState) }
)
val scope = rememberCoroutineScope()
val sheetState = ModalBottomSheetState(ModalBottomSheetValue.Hidden)
ModalBottomSheetLayout(
scrimColor = Color.Black.copy(alpha = 0.5f),
sheetState = sheetState,
sheetContent = {
if (viewModel.selectedApp.value != null) {
MainAppBottomSheet(
viewModel.selectedApp.value!!,
viewModel.appLongClickActions,
onActionClick = { viewModel.selectedApp.value = null },
onDismiss = { viewModel.onAppLongClicked(null, sheetState) }
)
} else {
Box(modifier = Modifier.defaultMinSize(minHeight = 1.dp))
}
}
SnackbarHost(
hostState = snackbarHostState,
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
.align(alignment = Alignment.TopCenter)
) {
val scaffoldState = rememberBottomSheetScaffoldState(
bottomSheetState = rememberBottomSheetState(BottomSheetValue.Expanded)
)
viewModel.selectedApp.value?.let {
MainAppBottomSheet(
it,
viewModel.appLongClickActions,
onActionClick = { viewModel.selectedApp.value = null },
onDismiss = { viewModel.onAppLongClicked(null) }
BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetShape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp),
sheetPeekHeight = 96.dp,
sheetContent = {
DialerGrid(
buttons = viewModel.dialerLabels,
buttonColors = viewModel.buttonColors,
onClick = viewModel.onDialerClicked,
onLongClick = { viewModel.onDialerLongClickedDecorated(it, navController) })
}
) {
AppGrid(
apps = viewModel.filteredApps,
query = viewModel.queryText,
isRefreshing = viewModel.isRefreshing,
onClick = { viewModel.onAppClicked(context, it) },
onLongClick = {
val app = viewModel.onAppLongClicked(it, sheetState)
app?.let {
scope.launch { sheetState.show() }
}
},
onRefresh = { viewModel.loadApps(false) }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package io.github.jbarr21.appdialer.ui.main

import android.app.Activity
import android.content.Context
import androidx.compose.material.SnackbarHostState
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ModalBottomSheetState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
Expand Down Expand Up @@ -82,9 +83,11 @@ class MainViewModel @Inject constructor(
(context as Activity).finishAndRemoveTask()
}

val onAppLongClicked: (App?) -> Unit = {
@ExperimentalMaterialApi
fun onAppLongClicked(app: App?, sheetState: ModalBottomSheetState): App? {
vibrator.vibrate()
selectedApp.value = it
selectedApp.value = app
return app
}

val onDialerClicked: (DialerButton) -> Unit = {
Expand All @@ -103,7 +106,7 @@ class MainViewModel @Inject constructor(
}
}

fun onDialerLongClickedDecorated(button: DialerButton, navController: NavController, snackbarHostState: SnackbarHostState) {
fun onDialerLongClickedDecorated(button: DialerButton, navController: NavController) {
onDialerLongClicked(button, navController)
if (button.isInfoButton) {
navController.navigate(Screen.Info.toString())
Expand Down
Loading

0 comments on commit 0f2b92f

Please sign in to comment.