Skip to content

Commit 1e08197

Browse files
committed
feat: Added UI/UX improvements.
1 parent 9bcbb32 commit 1e08197

File tree

12 files changed

+148
-107
lines changed

12 files changed

+148
-107
lines changed

core/data/src/commonMain/kotlin/com/zrcoding/hackertab/data/mappers/Mappers.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ fun ArticleDto.toFreeCodeCamp() = FreeCodeCamp(
3232
title = title,
3333
url = url,
3434
isoDate = publishedAt.toZonedLocalDate(),
35-
categories = tags.orEmpty()
35+
categories = tags.orEmpty().take(4)
3636
)
3737

3838
fun GithubDto.toGithubRepo() = GithubRepo(
3939
id = id,
40-
name = title,
40+
title = title,
4141
description = description,
4242
owner = owner,
4343
url = url,

core/design/src/commonMain/composeResources/drawable/ic_hackertab.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
android:viewportWidth="364.016"
55
android:viewportHeight="28.141">
66
<path
7-
android:fillColor="@color/black"
7+
android:fillColor="#000000"
88
android:pathData="M7.008,24.626L0.008,24.626L0.008,0.126L7.008,0.126L7.008,7.126L21.008,7.126L21.008,10.626L24.508,10.626L24.508,24.626L17.508,24.626L17.508,10.626L7.008,10.626L7.008,24.626ZM52.503,24.626L31.503,24.626L31.503,21.126L28.003,21.126L28.003,17.626L31.503,17.626L31.503,14.126L45.503,14.126L45.503,10.626L31.503,10.626L31.503,7.126L49.003,7.126L49.003,10.626L52.503,10.626L52.503,24.626ZM35.003,17.626L35.003,21.126L45.503,21.126L45.503,17.626L35.003,17.626ZM80.499,24.626L59.499,24.626L59.499,21.126L55.999,21.126L55.999,10.626L59.499,10.626L59.499,7.126L80.499,7.126L80.499,10.626L62.999,10.626L62.999,21.126L80.499,21.126L80.499,24.626ZM90.994,24.626L83.994,24.626L83.994,0.126L90.994,0.126L90.994,14.126L97.994,14.126L97.994,10.626L101.494,10.626L101.494,7.126L108.494,7.126L108.494,10.626L104.994,10.626L104.994,14.126L101.494,14.126L101.494,17.626L104.994,17.626L104.994,21.126L108.494,21.126L108.494,24.626L101.494,24.626L101.494,21.126L97.994,21.126L97.994,17.626L90.994,17.626L90.994,24.626ZM132.989,24.626L115.489,24.626L115.489,21.126L111.989,21.126L111.989,10.626L115.489,10.626L115.489,7.126L132.989,7.126L132.989,10.626L136.489,10.626L136.489,17.626L118.989,17.626L118.989,21.126L132.989,21.126L132.989,24.626ZM118.989,10.626L118.989,14.126L129.489,14.126L129.489,10.626L118.989,10.626ZM150.485,7.126L150.485,10.626L153.985,10.626L153.985,14.126L150.485,14.126L150.485,24.626L143.485,24.626L143.485,7.126L150.485,7.126ZM153.985,7.126L164.485,7.126L164.485,10.626L153.985,10.626L153.985,7.126ZM185.48,24.626L178.48,24.626L178.48,10.626L171.48,10.626L171.48,7.126L178.48,7.126L178.48,0.126L185.48,0.126L185.48,7.126L192.48,7.126L192.48,10.626L185.48,10.626L185.48,24.626ZM220.476,24.626L199.476,24.626L199.476,21.126L195.976,21.126L195.976,17.626L199.476,17.626L199.476,14.126L213.476,14.126L213.476,10.626L199.476,10.626L199.476,7.126L216.976,7.126L216.976,10.626L220.476,10.626L220.476,24.626ZM202.976,17.626L202.976,21.126L213.476,21.126L213.476,17.626L202.976,17.626ZM244.971,24.626L227.471,24.626L227.471,21.126L223.971,21.126L223.971,0.126L230.971,0.126L230.971,7.126L244.971,7.126L244.971,10.626L248.471,10.626L248.471,21.126L244.971,21.126L244.971,24.626ZM230.971,10.626L230.971,21.126L241.471,21.126L241.471,10.626L230.971,10.626ZM265.966,24.626L258.966,24.626L258.966,17.626L265.966,17.626L265.966,24.626ZM304.462,24.626L283.462,24.626L283.462,21.126L279.962,21.126L279.962,10.626L283.462,10.626L283.462,7.126L297.462,7.126L297.462,0.126L304.462,0.126L304.462,24.626ZM286.962,10.626L286.962,21.126L297.462,21.126L297.462,10.626L286.962,10.626ZM328.957,24.626L311.457,24.626L311.457,21.126L307.957,21.126L307.957,10.626L311.457,10.626L311.457,7.126L328.957,7.126L328.957,10.626L332.457,10.626L332.457,17.626L314.957,17.626L314.957,21.126L328.957,21.126L328.957,24.626ZM314.957,10.626L314.957,14.126L325.457,14.126L325.457,10.626L314.957,10.626ZM353.452,24.626L346.452,24.626L346.452,21.126L342.952,21.126L342.952,17.626L339.452,17.626L339.452,7.126L346.452,7.126L346.452,17.626L353.452,17.626L353.452,7.126L360.452,7.126L360.452,17.626L356.952,17.626L356.952,21.126L353.452,21.126L353.452,24.626Z"/>
99
</vector>

core/design/src/commonMain/kotlin/com/zrcoding/hackertab/design/theme/Color.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ package com.zrcoding.hackertab.design.theme
22

33
import androidx.compose.ui.graphics.Color
44

5+
val Black = Color(0xFF000000)
6+
val Black900 = Color(0xFF272728)
7+
val Black700 = Color(0xFF575758)
8+
val Black400 = Color(0xFF9F9F9F)
59

610
val Blue = Color(0XFF0366D6)
711
val Flamingo = Color(0xFFf6682f)
812
val ChestnutRose = Color(0xFFCF6679)
913
val ChineseBlack = Color(0xFF0D1116)
10-
val Black900 = Color(0xFF272728)
1114
val HawkesBlue = Color(0xFFEFF6FE)
1215
val White600 = Color(0xFFF9F9F9)

core/design/src/commonMain/kotlin/com/zrcoding/hackertab/design/theme/Theme.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ import androidx.compose.material.MaterialTheme
55
import androidx.compose.material.darkColors
66
import androidx.compose.material.lightColors
77
import androidx.compose.runtime.Composable
8-
import androidx.compose.ui.graphics.Color
98

109
private val DarkColorPalette = darkColors(
1110
primary = Blue,
1211
primaryVariant = ChineseBlack,
1312
secondary = Black900,
14-
secondaryVariant = Color.Black,
13+
secondaryVariant = Black900,
1514
background = ChineseBlack,
1615
error = ChestnutRose
1716
)
@@ -20,7 +19,7 @@ private val LightColorPalette = lightColors(
2019
primary = Blue,
2120
primaryVariant = HawkesBlue,
2221
secondary = White600,
23-
secondaryVariant = Color.White,
22+
secondaryVariant = White600,
2423
background = HawkesBlue,
2524
error = ChestnutRose
2625
)

core/design/src/commonMain/kotlin/com/zrcoding/hackertab/design/theme/Type.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ val Typography: Typography
3030
fontSize = 20.sp
3131
),
3232
subtitle1 = TextStyle(
33-
fontFamily = FontFamily(Font(Res.font.nunito_regular)),
33+
fontFamily = FontFamily(Font(Res.font.nunito_medium)),
3434
fontWeight = FontWeight.Normal,
35-
fontSize = 16.sp,
35+
fontSize = 18.sp,
3636
letterSpacing = 0.15.sp
3737
),
3838
subtitle2 = TextStyle(
39-
fontFamily = FontFamily(Font(Res.font.nunito_medium)),
39+
fontFamily = FontFamily(Font(Res.font.nunito_regular)),
4040
fontWeight = FontWeight.W500,
4141
fontSize = 14.sp,
4242
letterSpacing = 0.1.sp

core/domain/src/commonMain/kotlin/com/zrcoding/hackertab/domain/models/GithubRepo.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.zrcoding.hackertab.domain.models
22

33
data class GithubRepo(
44
override val id: String,
5-
val name: String,
5+
val title: String,
66
val description: String,
77
val owner: String,
88
val url: String,

core/domain/src/commonMain/kotlin/com/zrcoding/hackertab/domain/usecases/ObserveSelectedTopicsUseCase.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ class ObserveSelectedTopicsUseCase(
1313
@OptIn(ExperimentalCoroutinesApi::class)
1414
operator fun invoke(): Flow<List<Topic>> {
1515
return settingRepository.observeSavedTopicsIds().mapLatest { savedTopicsIds ->
16-
val topics = settingRepository.getTopics() + Topic.trending
17-
topics.filter { it.id in savedTopicsIds }
16+
val topics = settingRepository.getTopics()
17+
listOf(Topic.trending) + topics.filter { it.id in savedTopicsIds }
1818
}
1919
}
2020
}

feature/home/src/commonMain/kotlin/com/zrcoding/hackertab/home/presentation/HomeScreen.kt

Lines changed: 88 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.zrcoding.hackertab.home.presentation
22

3+
import androidx.compose.foundation.Image
34
import androidx.compose.foundation.clickable
45
import androidx.compose.foundation.layout.Arrangement
56
import androidx.compose.foundation.layout.Box
67
import androidx.compose.foundation.layout.Column
7-
import androidx.compose.foundation.layout.ColumnScope
88
import androidx.compose.foundation.layout.PaddingValues
99
import androidx.compose.foundation.layout.Row
1010
import androidx.compose.foundation.layout.Spacer
@@ -37,6 +37,7 @@ import androidx.compose.material.Text
3737
import androidx.compose.material.TopAppBar
3838
import androidx.compose.material.icons.Icons
3939
import androidx.compose.material.icons.automirrored.filled.ArrowRight
40+
import androidx.compose.material.icons.filled.AddBox
4041
import androidx.compose.material.icons.filled.ArrowDropDown
4142
import androidx.compose.material.icons.filled.Menu
4243
import androidx.compose.material.rememberDrawerState
@@ -74,7 +75,6 @@ import com.zrcoding.hackertab.design.resources.support_email_subject
7475
import com.zrcoding.hackertab.design.resources.support_no_apps_description
7576
import com.zrcoding.hackertab.design.resources.support_no_apps_title
7677
import com.zrcoding.hackertab.design.resources.support_support_footer_message
77-
import com.zrcoding.hackertab.design.theme.White600
7878
import com.zrcoding.hackertab.design.theme.dimension
7979
import com.zrcoding.hackertab.domain.common.AppConfig
8080
import com.zrcoding.hackertab.domain.models.BaseArticle
@@ -90,6 +90,7 @@ import com.zrcoding.hackertab.domain.models.Medium
9090
import com.zrcoding.hackertab.domain.models.ProductHunt
9191
import com.zrcoding.hackertab.domain.models.Reddit
9292
import com.zrcoding.hackertab.domain.models.Source
93+
import com.zrcoding.hackertab.domain.models.Topic
9394
import com.zrcoding.hackertab.home.presentation.cards.conferences.ConferenceItem
9495
import com.zrcoding.hackertab.home.presentation.cards.devto.DevtoItem
9596
import com.zrcoding.hackertab.home.presentation.cards.freecodecamp.FreeCodeCampItem
@@ -130,7 +131,8 @@ fun HomeRoute(
130131
onSourceSelected = viewModel::onSourceSelected,
131132
onNavigationBtnClick = {
132133
scope.launch { drawerState.open() }
133-
}
134+
},
135+
onAddSourceClick = onNavigateToSourcesSettings
134136
)
135137
},
136138
drawerContent = {
@@ -159,30 +161,15 @@ fun HomeRoute(
159161
horizontalAlignment = Alignment.CenterHorizontally
160162
) {
161163
if (viewState.selectedSource?.supportsFilters == true && viewState.enabledTopics.isNotEmpty()) {
162-
CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) {
163-
LazyRow(
164-
modifier = Modifier.fillMaxWidth()
165-
.padding(horizontal = MaterialTheme.dimension.large)
166-
.padding(bottom = MaterialTheme.dimension.small),
167-
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.dimension.medium),
168-
) {
169-
items(viewState.enabledTopics) { topic ->
170-
val selected = viewState.selectedTopic == topic
171-
FilterChip(
172-
selected = selected,
173-
onClick = { viewModel.onTopicSelected(topic) },
174-
colors = if (selected) ChipDefaults.filterChipColors(
175-
backgroundColor = MaterialTheme.colors.primary,
176-
contentColor = White600
177-
) else ChipDefaults.filterChipColors(),
178-
) {
179-
Text(text = topic.label)
180-
}
181-
}
182-
}
183-
}
164+
HomeScreenTopicsFilter(
165+
enabledTopics = viewState.enabledTopics,
166+
selectedTopic = viewState.selectedTopic,
167+
onTopicSelected = viewModel::onTopicSelected
168+
)
169+
}
170+
if (viewState.isLoading) {
171+
CircularProgressIndicator()
184172
}
185-
if (viewState.isLoading) CircularProgressIndicator()
186173
when {
187174
viewState.articles.isNotEmpty() -> LazyColumn(
188175
modifier = Modifier.fillMaxSize(),
@@ -193,20 +180,8 @@ fun HomeRoute(
193180
items = viewState.articles,
194181
key = { item -> item.id }
195182
) { item: BaseArticle ->
196-
when (item) {
197-
is GithubRepo -> GithubItem(item)
198-
is HackerNews -> HackerNewsItem(item)
199-
is Conference -> ConferenceItem(item)
200-
is Devto -> DevtoItem(item)
201-
is ProductHunt -> ProductHuntItem(item)
202-
is Reddit -> RedditItem(item)
203-
is Lobster -> LobstersItem(item)
204-
is Hashnode -> HashnodeItem(item)
205-
is FreeCodeCamp -> FreeCodeCampItem(item)
206-
is IndieHackers -> IndieHackersItem(item)
207-
is Medium -> MediumItem(item)
208-
}
209-
Divider(modifier = Modifier.padding(horizontal = MaterialTheme.dimension.large))
183+
item.ToListItem()
184+
Divider()
210185
}
211186
}
212187

@@ -236,6 +211,7 @@ private fun HomeScreenTopAppBar(
236211
selectedSource: String,
237212
onSourceSelected: (Source) -> Unit,
238213
onNavigationBtnClick: () -> Unit,
214+
onAddSourceClick: () -> Unit,
239215
) {
240216
var expanded by remember { mutableStateOf(false) }
241217
TopAppBar(
@@ -274,14 +250,29 @@ private fun HomeScreenTopAppBar(
274250
onSourceSelected(source)
275251
}
276252
) {
277-
Icon(
253+
Image(
278254
painter = painterResource(source.icon),
279255
contentDescription = "Select source",
280256
)
281257
Spacer(modifier = Modifier.width(MaterialTheme.dimension.small))
282258
Text(text = source.label)
283259
}
284260
}
261+
if (enabledSources.size < Source.entries.size) {
262+
DropdownMenuItem(
263+
onClick = {
264+
expanded = false
265+
onAddSourceClick()
266+
}
267+
) {
268+
Icon(
269+
imageVector = Icons.Default.AddBox,
270+
contentDescription = "Select source",
271+
)
272+
Spacer(modifier = Modifier.width(MaterialTheme.dimension.small))
273+
Text(text = "Add source", color = MaterialTheme.colors.onBackground.copy(alpha = 0.8f))
274+
}
275+
}
285276
}
286277
}
287278
}
@@ -297,6 +288,10 @@ private fun HomeScreenTopAppBar(
297288
)
298289
}
299290
},
291+
292+
actions = {
293+
294+
},
300295
backgroundColor = MaterialTheme.colors.background,
301296
elevation = MaterialTheme.dimension.none
302297
)
@@ -351,24 +346,6 @@ private fun HomeScreenDrawer(
351346
}
352347
}
353348

354-
@Composable
355-
private fun HomeScreenDrawerItemsContainer(
356-
content: @Composable ColumnScope.() -> Unit
357-
) {
358-
Card(shape = MaterialTheme.shapes.large) {
359-
Column(
360-
modifier = Modifier
361-
.fillMaxWidth()
362-
.padding(
363-
horizontal = MaterialTheme.dimension.large,
364-
vertical = MaterialTheme.dimension.default
365-
)
366-
) {
367-
content()
368-
}
369-
}
370-
}
371-
372349
@OptIn(ExperimentalMaterialApi::class)
373350
@Composable
374351
private fun HomeScreenDrawerItem(
@@ -412,7 +389,58 @@ private fun AppVersionName(modifier: Modifier = Modifier, versionName: String) {
412389
modifier = modifier,
413390
text = stringResource(Res.string.setting_master_screen_version_name, versionName),
414391
color = MaterialTheme.colors.onBackground,
415-
style = MaterialTheme.typography.subtitle1,
392+
style = MaterialTheme.typography.body1,
416393
textAlign = TextAlign.Center
417394
)
418395
}
396+
397+
@Composable
398+
@OptIn(ExperimentalMaterialApi::class)
399+
private fun HomeScreenTopicsFilter(
400+
enabledTopics: ImmutableList<Topic>,
401+
selectedTopic: Topic?,
402+
onTopicSelected: (Topic) -> Unit,
403+
) {
404+
CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) {
405+
LazyRow(
406+
modifier = Modifier.fillMaxWidth().padding(bottom = MaterialTheme.dimension.small),
407+
contentPadding = PaddingValues(horizontal = MaterialTheme.dimension.default),
408+
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.dimension.medium),
409+
) {
410+
items(enabledTopics) { topic ->
411+
val selected = selectedTopic == topic
412+
FilterChip(
413+
selected = selected,
414+
onClick = { onTopicSelected(topic) },
415+
shape = MaterialTheme.shapes.medium,
416+
colors = if (selected) ChipDefaults.filterChipColors(
417+
backgroundColor = MaterialTheme.colors.onBackground,
418+
contentColor = MaterialTheme.colors.background
419+
) else ChipDefaults.filterChipColors(
420+
backgroundColor = MaterialTheme.colors.secondary,
421+
contentColor = MaterialTheme.colors.onBackground
422+
),
423+
) {
424+
Text(text = topic.label)
425+
}
426+
}
427+
}
428+
}
429+
}
430+
431+
@Composable
432+
private fun BaseArticle.ToListItem() {
433+
when (this) {
434+
is GithubRepo -> GithubItem(this)
435+
is HackerNews -> HackerNewsItem(this)
436+
is Conference -> ConferenceItem(this)
437+
is Devto -> DevtoItem(this)
438+
is ProductHunt -> ProductHuntItem(this)
439+
is Reddit -> RedditItem(this)
440+
is Lobster -> LobstersItem(this)
441+
is Hashnode -> HashnodeItem(this)
442+
is FreeCodeCamp -> FreeCodeCampItem(this)
443+
is IndieHackers -> IndieHackersItem(this)
444+
is Medium -> MediumItem(this)
445+
}
446+
}

0 commit comments

Comments
 (0)