Skip to content

Commit 66b2320

Browse files
committed
feat: Enhance splash screen and add user search functionality
This commit enhances the app's splash screen with a custom exit animation and introduces the ability to search for users within the app. Changes: - **Splash Screen Animation:** - Implemented a custom exit animation for the splash screen that zooms out and rotates the icon, using `ObjectAnimator` and `OvershootInterpolator`. - Added `Theme.App.Starting` style for splash screen configuration, including background color, icon background color, and animated icon. - Added `logo_animator.xml` and `animated_logo.xml` to add animation in splash screen icon - Added new `ic_launcher_foreground` in `mipmap` folders and `ic_launcher_background.xml` - Added new `app_logo.xml` in `drawable` folder - Updated `ic_launcher.xml` and `ic_launcher_round.xml` in `mipmap-anydpi-v26` to remove deprecated drawables. - updated `AndroidManifest.xml` to use splash screen theme - Updated `themes.xml` to add splash screen style and `themes.xml (v31)` - updated all `ic_launcher` and `ic_launcher_round` to webp format in all `mipmap` folders - Added `ic_launcher-playstore.png` - **User Search Functionality:** - Added `searchQuery`, `allUsers` state flows to `MainViewModel` to manage user search. - Implemented `setSearchQuery` to update the search query and filter users. - Implemented `filterUsers` to filter the `allUsers` based on the current search query, updating the `uiState` accordingly. - Modified `HomeScreenTopBar` to include a search bar and search icon. - Added search functionality and animated icon in `HomeScreenTopBar` - Added `DockedSearchBar` to `HomeScreenTopBar` for user search. - Added `clearSearchQuery` action in `HomeScreenTopBar` - Added `BackHandler` in `HomeScreen` to clear the search field when user back press. - Updated `UserList` to display a message when no users are found, including an error icon. - Display `UserListFooter` only if there are users in the list - Changed `bs` title in `UserDetailsItemCompanyRow` to `Business` - Added `Icon` in case of error in `UserList` - Updated `HomeScreenContent` to remove `contentAlignment = Alignment.Center` - Added `TechExactlyApplication` to apply Koin configuration
1 parent 9e0c5cb commit 66b2320

33 files changed

Lines changed: 314 additions & 27 deletions

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
android:label="@string/app_name"
1414
android:roundIcon="@mipmap/ic_launcher_round"
1515
android:supportsRtl="true"
16-
android:theme="@style/Theme.TechExactly"
16+
android:theme="@style/Theme.App.Starting"
1717
tools:targetApi="31">
1818
<activity
1919
android:name=".MainActivity"
2020
android:exported="true"
2121
android:label="@string/app_name"
22-
android:theme="@style/Theme.TechExactly">
22+
android:theme="@style/Theme.App.Starting">
2323
<intent-filter>
2424
<action android:name="android.intent.action.MAIN" />
2525

16.5 KB
Loading

app/src/main/java/com/example/techexactly/MainActivity.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,40 @@
11
package com.example.techexactly
22

3+
import android.animation.ObjectAnimator
34
import android.os.Bundle
5+
import android.view.View
6+
import android.view.animation.OvershootInterpolator
47
import androidx.activity.ComponentActivity
58
import androidx.activity.compose.setContent
69
import androidx.activity.enableEdgeToEdge
10+
import androidx.core.animation.doOnEnd
11+
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
712
import androidx.navigation.compose.rememberNavController
813
import com.example.techexactly.ui.theme.TechExactlyTheme
914
import com.example.techexactly.view.navigation.SetupNavGraph
1015

1116
class MainActivity : ComponentActivity() {
1217
override fun onCreate(savedInstanceState: Bundle?) {
1318
super.onCreate(savedInstanceState)
19+
installSplashScreen().apply {
20+
setOnExitAnimationListener { screen ->
21+
val zoomX = ObjectAnimator.ofFloat(
22+
screen.iconView, View.SCALE_X, 0.4f, 0.0f
23+
)
24+
zoomX.interpolator = OvershootInterpolator()
25+
zoomX.duration = 500L
26+
zoomX.doOnEnd { screen.remove() }
27+
val zoomY = ObjectAnimator.ofFloat(
28+
screen.iconView, View.SCALE_Y, 0.4f, 0.0f
29+
)
30+
zoomY.interpolator = OvershootInterpolator()
31+
zoomY.duration = 500L
32+
zoomY.doOnEnd { screen.remove() }
33+
34+
zoomX.start()
35+
zoomY.start()
36+
}
37+
}
1438
enableEdgeToEdge()
1539
setContent {
1640
TechExactlyTheme {

app/src/main/java/com/example/techexactly/TechExactlyApplication.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ package com.example.techexactly
33
import android.app.Application
44
import com.example.techexactly.di.appModule
55
import org.koin.android.ext.koin.androidContext
6+
import org.koin.android.ext.koin.androidLogger
67
import org.koin.core.context.startKoin
8+
import org.koin.core.logger.Level
79

810
class TechExactlyApplication : Application() {
911
override fun onCreate() {
1012
super.onCreate()
1113
startKoin {
14+
androidLogger(Level.DEBUG)
1215
androidContext(this@TechExactlyApplication)
1316
modules(appModule)
1417
}

app/src/main/java/com/example/techexactly/view/home/HomeScreen.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package com.example.techexactly.view.home
22

3+
import androidx.activity.compose.BackHandler
34
import androidx.compose.foundation.layout.Box
45
import androidx.compose.foundation.layout.fillMaxSize
56
import androidx.compose.foundation.layout.padding
67
import androidx.compose.material3.ExperimentalMaterial3Api
78
import androidx.compose.material3.Scaffold
89
import androidx.compose.material3.TopAppBarDefaults
910
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.getValue
1012
import androidx.compose.ui.Modifier
1113
import androidx.compose.ui.input.nestedscroll.nestedScroll
1214
import androidx.compose.ui.res.stringResource
15+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
1316
import com.example.techexactly.R
1417
import com.example.techexactly.model.dataclass.User
1518
import com.example.techexactly.viewmodel.MainViewModel
@@ -21,6 +24,14 @@ fun HomeScreen(
2124
onUserClicked: (User) -> Unit, mainViewModel: MainViewModel = koinViewModel<MainViewModel>()
2225
) {
2326
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
27+
28+
val searchQuery by mainViewModel.searchQuery.collectAsStateWithLifecycle()
29+
30+
BackHandler(
31+
enabled = searchQuery.isNotEmpty(), onBack = {
32+
mainViewModel.setSearchQuery("")
33+
})
34+
2435
Scaffold(
2536
modifier = Modifier
2637
.fillMaxSize()
@@ -29,8 +40,14 @@ fun HomeScreen(
2940
HomeScreenTopBar(
3041
title = stringResource(id = R.string.app_name),
3142
subtitle = "Users",
32-
scrollBehavior = scrollBehavior
33-
)
43+
scrollBehavior = scrollBehavior,
44+
searchQuery = searchQuery,
45+
onSearchQueryChanged = { newQuery ->
46+
mainViewModel.setSearchQuery(newQuery)
47+
},
48+
clearSearchQuery = {
49+
mainViewModel.setSearchQuery("")
50+
})
3451
}) { innerPadding ->
3552
Box(
3653
modifier = Modifier

app/src/main/java/com/example/techexactly/view/home/HomeScreenContent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fun HomeScreenContent(
3232
) {
3333
val uiState by mainViewModel.uiState.collectAsState()
3434
Box(
35-
modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center
35+
modifier = Modifier.fillMaxSize()
3636
) {
3737
when (val state = uiState) {
3838
is UiState.Error -> {
Lines changed: 121 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,143 @@
11
package com.example.techexactly.view.home
22

3+
import androidx.compose.animation.AnimatedVisibility
4+
import androidx.compose.foundation.Image
35
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.layout.size
9+
import androidx.compose.material.icons.Icons
10+
import androidx.compose.material.icons.filled.Close
11+
import androidx.compose.material.icons.filled.Search
412
import androidx.compose.material3.CenterAlignedTopAppBar
13+
import androidx.compose.material3.DockedSearchBar
514
import androidx.compose.material3.ExperimentalMaterial3Api
15+
import androidx.compose.material3.Icon
16+
import androidx.compose.material3.IconButton
617
import androidx.compose.material3.MaterialTheme
18+
import androidx.compose.material3.SearchBarDefaults
719
import androidx.compose.material3.Text
820
import androidx.compose.material3.TopAppBarDefaults
921
import androidx.compose.material3.TopAppBarScrollBehavior
1022
import androidx.compose.runtime.Composable
23+
import androidx.compose.runtime.getValue
24+
import androidx.compose.runtime.mutableStateOf
25+
import androidx.compose.runtime.remember
26+
import androidx.compose.runtime.setValue
1127
import androidx.compose.ui.Alignment
28+
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.graphics.ColorFilter
30+
import androidx.compose.ui.res.painterResource
1231
import androidx.compose.ui.res.stringResource
32+
import androidx.compose.ui.text.style.TextAlign
1333
import androidx.compose.ui.text.style.TextOverflow
1434
import androidx.compose.ui.tooling.preview.Preview
35+
import androidx.compose.ui.unit.dp
1536
import com.example.techexactly.R
1637

1738
@OptIn(ExperimentalMaterial3Api::class)
1839
@Composable
1940
fun HomeScreenTopBar(
20-
title: String, subtitle: String, scrollBehavior: TopAppBarScrollBehavior
41+
title: String, subtitle: String,
42+
scrollBehavior: TopAppBarScrollBehavior,
43+
searchQuery: String = "",
44+
onSearchQueryChanged: (String) -> Unit,
45+
clearSearchQuery: () -> Unit,
2146
) {
22-
CenterAlignedTopAppBar(
23-
title = {
24-
Column(
25-
horizontalAlignment = Alignment.CenterHorizontally
26-
) {
27-
Text(
28-
text = title, maxLines = 1, overflow = TextOverflow.Ellipsis
29-
)
47+
var showSearchBar by remember { mutableStateOf(false) }
48+
Column {
49+
CenterAlignedTopAppBar(
50+
title = {
51+
Column(
52+
horizontalAlignment = Alignment.CenterHorizontally
53+
) {
54+
Text(
55+
text = title, maxLines = 1, overflow = TextOverflow.Ellipsis
56+
)
57+
Text(
58+
text = subtitle, style = MaterialTheme.typography.labelMedium
59+
)
60+
}
61+
}, actions = {
62+
AnimatedVisibility(visible = showSearchBar) {
63+
IconButton(
64+
onClick = { showSearchBar = !showSearchBar }) {
65+
Icon(
66+
imageVector = Icons.Default.Close, contentDescription = "Close"
67+
)
68+
}
69+
}
70+
AnimatedVisibility(visible = !showSearchBar) {
71+
IconButton(
72+
onClick = { showSearchBar = !showSearchBar }) {
73+
Icon(
74+
imageVector = Icons.Default.Search, contentDescription = "Search"
75+
)
76+
}
77+
}
78+
}, navigationIcon = {
79+
Image(
80+
modifier = Modifier.padding(start = 8.dp).size(24.dp),
81+
painter = painterResource(id = R.drawable.app_logo),
82+
contentDescription = null,
83+
colorFilter = ColorFilter.tint(
84+
MaterialTheme.colorScheme.onSurface
85+
)
86+
)
87+
},
88+
scrollBehavior = scrollBehavior
89+
)
90+
AnimatedVisibility(visible = showSearchBar) {
91+
DockedSearchBar(
92+
modifier = Modifier
93+
.fillMaxWidth()
94+
.padding(horizontal = 8.dp, vertical = 4.dp),
95+
inputField = {
96+
SearchBarDefaults.InputField(
97+
modifier = Modifier.fillMaxWidth(0.9f),
98+
query = searchQuery,
99+
onQueryChange = {
100+
onSearchQueryChanged(it)
101+
},
102+
onSearch = {
103+
showSearchBar = false
104+
},
105+
expanded = false,
106+
onExpandedChange = { },
107+
placeholder = { Text("Search Users") },
108+
leadingIcon = {
109+
Icon(
110+
Icons.Default.Search, contentDescription = null
111+
)
112+
},
113+
trailingIcon = {
114+
if (showSearchBar) {
115+
IconButton(onClick = {
116+
if (searchQuery.isNotEmpty()) {
117+
clearSearchQuery()
118+
}
119+
showSearchBar = false
120+
}) {
121+
Icon(Icons.Default.Close, contentDescription = null)
122+
}
123+
}
124+
125+
})
126+
},
127+
expanded = false,
128+
onExpandedChange = {}) {}
129+
}
130+
AnimatedVisibility(searchQuery.isNotEmpty()) {
30131
Text(
31-
text = subtitle, style = MaterialTheme.typography.labelMedium
132+
text = "Showing results for: $searchQuery",
133+
style = MaterialTheme.typography.labelMedium,
134+
modifier = Modifier
135+
.fillMaxWidth()
136+
.padding(horizontal = 8.dp, vertical = 4.dp),
137+
textAlign = TextAlign.Center
32138
)
33139
}
34-
}, navigationIcon = {}, scrollBehavior = scrollBehavior
35-
)
140+
}
36141
}
37142

38143
@Preview
@@ -42,6 +147,8 @@ fun HomeScreenTopBarPreview() {
42147
HomeScreenTopBar(
43148
title = stringResource(id = R.string.app_name),
44149
subtitle = "Users",
45-
scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
46-
)
150+
scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(),
151+
searchQuery = "",
152+
onSearchQueryChanged = {},
153+
clearSearchQuery = {})
47154
}

app/src/main/java/com/example/techexactly/view/home/UserList.kt

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
package com.example.techexactly.view.home
22

3+
import androidx.compose.animation.AnimatedVisibility
34
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Spacer
47
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.foundation.layout.height
59
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.foundation.layout.size
611
import androidx.compose.foundation.lazy.LazyColumn
712
import androidx.compose.foundation.lazy.items
13+
import androidx.compose.material.icons.Icons
14+
import androidx.compose.material.icons.filled.SentimentVeryDissatisfied
15+
import androidx.compose.material3.Icon
16+
import androidx.compose.material3.MaterialTheme
17+
import androidx.compose.material3.Text
818
import androidx.compose.runtime.Composable
919
import androidx.compose.ui.Alignment
1020
import androidx.compose.ui.Modifier
21+
import androidx.compose.ui.text.style.TextAlign
1122
import androidx.compose.ui.tooling.preview.Preview
1223
import androidx.compose.ui.unit.dp
1324
import com.example.techexactly.model.dataclass.Address
@@ -28,7 +39,33 @@ fun UserList(users: List<User>, onUserClicked: (User) -> Unit) {
2839
UserListItem(user = user, onUserClicked = onUserClicked)
2940
}
3041
item {
31-
UserListFooter()
42+
AnimatedVisibility(users.isEmpty()) {
43+
Column(
44+
horizontalAlignment = Alignment.CenterHorizontally,
45+
verticalArrangement = Arrangement.Center,
46+
) {
47+
Spacer(modifier = Modifier.height(8.dp))
48+
Icon(
49+
imageVector = Icons.Default.SentimentVeryDissatisfied,
50+
contentDescription = "ERROR",
51+
modifier = Modifier.size(48.dp),
52+
tint = MaterialTheme.colorScheme.error
53+
)
54+
Spacer(modifier = Modifier.height(8.dp))
55+
Text(
56+
text = "No Users Found",
57+
modifier = Modifier.fillMaxWidth(),
58+
style = MaterialTheme.typography.headlineSmall,
59+
textAlign = TextAlign.Center,
60+
color = MaterialTheme.colorScheme.error
61+
)
62+
}
63+
}
64+
}
65+
item {
66+
AnimatedVisibility(users.isNotEmpty()) {
67+
UserListFooter()
68+
}
3269
}
3370
}
3471
}

app/src/main/java/com/example/techexactly/view/user/UserDetailsBody.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ fun UserDetailsItemCompany(
214214
value = company.catchPhrase
215215
)
216216
UserDetailsItemCompanyRow(
217-
icon = Icons.Default.Work, title = "Bs", value = company.bs
217+
icon = Icons.Default.Work, title = "Business", value = company.bs
218218
)
219219
}
220220
})

0 commit comments

Comments
 (0)