Skip to content

Commit

Permalink
Merge activities, add underlining to query, & add Info screen
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarr21 committed Jun 17, 2021
1 parent 97012f2 commit afcfac1
Show file tree
Hide file tree
Showing 29 changed files with 690 additions and 446 deletions.
16 changes: 2 additions & 14 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,15 @@
android:name=".app.AppDialerApplication"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:theme="@style/Theme.AppDialer"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".ui.main.MainActivity"
android:theme="@style/AppTheme.NoActionBar">
<activity android:name=".ui.RootActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ui.settings.SettingsActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="appdialer" android:host="settings" />
</intent-filter>
</activity>
<receiver android:name=".service.BootCompletedReceiver" android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
Expand Down
20 changes: 9 additions & 11 deletions app/src/main/kotlin/io/github/jbarr21/appdialer/app/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,29 @@ import coil.ImageLoader
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.components.SingletonComponent
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(ApplicationComponent::class)
@InstallIn(SingletonComponent::class)
@Module
object AppModule {

@Singleton
@Provides
fun activityLauncher(
application: Application,
launcherApps: LauncherApps
): ActivityLauncher = ActivityLauncher(application, launcherApps)

@Provides
fun activityManager(application: Application) = application.getSystemService<ActivityManager>()!!

@Singleton
@Provides
fun appDatabase(application: Application): AppDatabase {
return Room.databaseBuilder(application, AppDatabase::class.java, "apps").build()
}

@Singleton
@Provides
fun imageCache(am: ActivityManager, application: Application): LruCache<String, Drawable> {
val largeHeap = application.applicationInfo.flags and FLAG_LARGE_HEAP !== 0
Expand All @@ -43,23 +45,19 @@ object AppModule {
return LruCache<String, Drawable>(maxSize)
}

@Singleton
@Provides
fun imageLoader(application: Application, appIconFetcher: AppIconFetcher): ImageLoader {
return ImageLoader.Builder(application).componentRegistry {
add(appIconFetcher)
}.build()
}

@Singleton
@Provides
fun launcherApps(application: Application) = application.getSystemService<LauncherApps>()!!

@Singleton
@Provides
fun packageManager(application: Application) = application.packageManager

@Singleton
@Provides
fun userManager(application: Application) = application.getSystemService<UserManager>()!!
}
29 changes: 29 additions & 0 deletions app/src/main/kotlin/io/github/jbarr21/appdialer/data/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import android.content.Intent.ACTION_MAIN
import android.graphics.Color.TRANSPARENT
import android.net.Uri
import android.os.UserHandle
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import io.github.jbarr21.appdialer.ui.main.dialer.DialerModule
import io.github.jbarr21.appdialer.util.AppIconFetcher.Companion.PARAM_ACTIVITY_NAME
import io.github.jbarr21.appdialer.util.AppIconFetcher.Companion.PARAM_USER_ID
import io.github.jbarr21.appdialer.util.AppIconFetcher.Companion.SCHEME_PNAME
Expand All @@ -30,6 +35,30 @@ data class App(
return user == other.user && packageName == other.packageName && activityName == other.activityName
}

fun annotatedLabel(query: String): AnnotatedString {
val keyMappings = DialerModule.keyMappings()
var matching = 0
while (matching < query.length && matching < label.length
&& keyMappings.keyForValueContainingChar(label[matching]) == keyMappings.keyForValueContainingChar(query[matching])) {
matching++
}

return AnnotatedString.Builder().apply {
label.substring(0, matching).let {
if (it.isNotEmpty()) {
pushStyle(SpanStyle(textDecoration = TextDecoration.Underline, fontWeight = FontWeight.Bold))
append(it)
pop()
}
}
append(label.substring(minOf(matching, label.length)))
}.toAnnotatedString()
}

private fun Map<Int, String>.keyForValueContainingChar(ch: Char): Int {
return entries.firstOrNull { (_, letters) -> ch.toLowerCase() in letters.toLowerCase() }?.key ?: -1
}

companion object {
fun iconUri(packageName: String, activityName: String, user: UserHandle): Uri {
return Uri.parse("$SCHEME_PNAME://$packageName?$PARAM_ACTIVITY_NAME=$activityName&$PARAM_USER_ID=${user.id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,15 @@ class AppRepo @Inject constructor(
return withContext(Dispatchers.IO) {
if (useCache) {
val cachedApps = loadAppsFromCache()
if (cachedApps.isNotEmpty()) return@withContext cachedApps
if (cachedApps.isNotEmpty()) {
this@AppRepo.cachedApps.clear()
this@AppRepo.cachedApps.addAll(cachedApps)
return@withContext cachedApps
}
}
val pmApps = loadAppsFromPackageManager()
this@AppRepo.cachedApps.clear()
this@AppRepo.cachedApps.addAll(pmApps)
return@withContext pmApps
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ data class DialerButton(
) {
val isClearButton = "clear" in label.toString().toLowerCase()
val isInfoButton = "i" in label.toString().toLowerCase()
val isRefreshButton = "r" in label.toString().toLowerCase()

}

fun List<DialerButton>.asText() = map { it.letters.first().toString() }.joinToString(separator = "")
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import android.os.IBinder
import dagger.hilt.android.AndroidEntryPoint
import io.github.jbarr21.appdialer.R
import io.github.jbarr21.appdialer.data.UserPreferencesRepo
import io.github.jbarr21.appdialer.ui.main.MainActivity
import io.github.jbarr21.appdialer.ui.RootActivity
import io.github.jbarr21.appdialer.util.Channels
import timber.log.Timber
import javax.inject.Inject
Expand Down Expand Up @@ -51,7 +51,7 @@ class KeepAliveService : Service() {
}

private fun createNotification(): Notification {
val pendingIntent: PendingIntent = Intent(this, MainActivity::class.java).let { intent ->
val pendingIntent: PendingIntent = Intent(this, RootActivity::class.java).let { intent ->
PendingIntent.getActivity(this, 0, intent, 0)
}

Expand Down
20 changes: 20 additions & 0 deletions app/src/main/kotlin/io/github/jbarr21/appdialer/ui/AppDialerApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.jbarr21.appdialer.ui

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 io.github.jbarr21.appdialer.ui.info.InfoScreen
import io.github.jbarr21.appdialer.ui.main.MainScreen
import io.github.jbarr21.appdialer.ui.settings.SettingsScreen

@Composable
fun AppDialerApp() {
val navController = rememberNavController()
NavHost(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) }
}
}
24 changes: 24 additions & 0 deletions app/src/main/kotlin/io/github/jbarr21/appdialer/ui/RootActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.jbarr21.appdialer.ui

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.core.view.WindowCompat
import com.google.accompanist.insets.ProvideWindowInsets
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class RootActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
ProvideWindowInsets {
AppTheme {
AppDialerApp()
}
}
}
}
}
15 changes: 15 additions & 0 deletions app/src/main/kotlin/io/github/jbarr21/appdialer/ui/Screen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.jbarr21.appdialer.ui

sealed class Screen(val route: String) {
object Main : Screen("main")
object Settings : Screen("settings")
object Info : Screen("info")

companion object {
val items = listOf(
Main,
Settings,
Info
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.github.jbarr21.appdialer.ui.common

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
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
import androidx.navigation.NavController
import com.google.accompanist.insets.statusBarsPadding
import io.github.jbarr21.appdialer.ui.AppTheme

@Composable
fun AppDialerTopBar(
title: String,
navController: NavController,
showStatusBar: Boolean = true,
actions: @Composable RowScope.() -> Unit = {}
) {
val appBarColor = Color(0xFF2D2D2D)
TopAppBar(
title = { Text(title) },
backgroundColor = appBarColor,
contentColor = MaterialTheme.colors.onSurface,
modifier = if (showStatusBar) Modifier
.background(appBarColor)
.statusBarsPadding() else Modifier.padding(0.dp),
actions = actions,
navigationIcon = navController.previousBackStackEntry?.let {
{
IconButton(onClick = { navController.popBackStack() }) {
Icon(Icons.Default.ArrowBack, contentDescription = null)
}
}
}
)
}

@Preview
@Composable
fun AppDialerTopBarPreview() {
AppTheme(darkTheme = true) {
AppDialerTopBar(title = "AppDialer", NavController(LocalContext.current))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.github.jbarr21.appdialer.ui.info

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.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
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import io.github.jbarr21.appdialer.ui.AppTheme
import io.github.jbarr21.appdialer.ui.common.AppDialerTopBar

@Composable
fun InfoScreen(viewModel: InfoViewModel = viewModel(), navController: NavController) {
Scaffold(topBar = { AppDialerTopBar(title = "AppDialer Info", navController = navController) }) {
InfoContent(viewModel.appStats)
}
}

@Composable
fun InfoContent(appStats: AppStats) {
Surface(modifier = Modifier.fillMaxSize()) {
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(32.dp)) {
if (appStats.isLoaded) {
with (appStats) {
listOf("Total = $totalCount",
"Unique = $uniqueAppCount",
"Main = $mainAppCount",
"Work = $workAppCount"
).let {
Text(it.joinToString("\n"))
}
}
} else {
CircularProgressIndicator()
}
}
}
}

@Preview
@Composable
fun InfoScreenPreview() {
AppTheme(darkTheme = true) {
InfoContent(AppStats(142, 121, 100, 42))
}
}

@Preview
@Composable
fun InfoScreenLoadingPreview() {
AppTheme(darkTheme = true) {
InfoContent(AppStats(-1, -1, -1, -1))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.github.jbarr21.appdialer.ui.info

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.jbarr21.appdialer.data.AppRepo
import io.github.jbarr21.appdialer.data.isMain
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class InfoViewModel @Inject constructor(private val appRepo: AppRepo) : ViewModel() {

var appStats by mutableStateOf(AppStats(-1, -1, -1, -1)).also { loadApps() }

private fun loadApps() {
viewModelScope.launch {
val apps = appRepo.loadApps(true)
appStats = AppStats(
totalCount = apps.size,
uniqueAppCount = apps.groupBy { it.packageName + it.activityName }.size,
mainAppCount = apps.filter { it.user.isMain }.size,
workAppCount = apps.filter { !it.user.isMain }.size
)
}
}
}

data class AppStats(
val totalCount: Int,
val uniqueAppCount: Int,
val mainAppCount: Int,
val workAppCount: Int
) {
val isLoaded = totalCount >= 0
}
Loading

0 comments on commit afcfac1

Please sign in to comment.