Skip to content

Commit f546daa

Browse files
Merge pull request #20 from matejsemancik/feature/navigation-tabs
Navigation Tabs + logout fix
2 parents baacc53 + 2ae32e3 commit f546daa

File tree

12 files changed

+276
-88
lines changed

12 files changed

+276
-88
lines changed

shared/src/commonMain/composeResources/values/strings.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<string name="remove">Remove</string>
77

88
<!-- App -->
9+
<string name="bottom_nav_timer">Timer</string>
10+
<string name="bottom_nav_logbook">Logbook</string>
11+
<string name="bottom_nav_settings">Settings</string>
912
<string name="app_name">tempo-timer</string>
1013
<string name="toggle_dark_mode">Toggle dark mode</string>
1114
<string name="settings">Settings</string>
@@ -22,7 +25,9 @@
2225
<string name="log_time">Log Time</string>
2326

2427
<!-- Settings -->
25-
<string name="credentials_title">🔐 Credentials</string>
28+
<string name="settings_app_section_title">⚙️ App</string>
29+
<string name="settings_account_section_title">👤 Account</string>
30+
<string name="settings_credentials_section_title">🔐 Sign In</string>
2631
<string name="credentials_description">Sign In by providing necessary credentials.</string>
2732
<string name="credentials_instructions_md">Jira API token is used to sync your profile and search issues. Tempo API
2833
token is used to synchronize worklogs with Tempo. [Instructions
@@ -45,4 +50,4 @@
4550
<string name="no_timers">No running timers</string>
4651
<string name="start_timer_instructions">Start a new timer by clicking on Favourite,\nor from menu bar down there 👇
4752
</string>
48-
</resources>
53+
</resources>

shared/src/commonMain/kotlin/dev/matsem/bpm/data/database/dao/JiraIssueDao.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.matsem.bpm.data.database.dao
22

33
import androidx.room.Dao
4+
import androidx.room.Delete
45
import androidx.room.Insert
56
import androidx.room.Query
67
import androidx.room.Transaction
@@ -29,4 +30,7 @@ interface JiraIssueDao {
2930

3031
@Query("SELECT * FROM jira_issue INNER JOIN favourite_issue ON favourite_issue.jira_issue_id = jira_issue.id")
3132
fun getFavouriteIssues(): Flow<List<JiraIssue>>
32-
}
33+
34+
@Query("DELETE FROM jira_issue")
35+
suspend fun deleteAllIssues()
36+
}

shared/src/commonMain/kotlin/dev/matsem/bpm/data/repo/IssueRepo.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ interface IssueRepo {
2424
suspend fun removeFavouriteIssue(issue: Issue)
2525

2626
fun getFavouriteIssues(): Flow<List<Issue>>
27+
28+
suspend fun deleteAllIssues()
2729
}
2830

2931
internal class IssueRepoImpl(
@@ -70,4 +72,8 @@ internal class IssueRepoImpl(
7072

7173
override fun getFavouriteIssues(): Flow<List<Issue>> =
7274
jiraIssueDao.getFavouriteIssues().map { issueList -> issueList.map { issue -> issue.toDomainModel() } }
75+
76+
override suspend fun deleteAllIssues() {
77+
jiraIssueDao.deleteAllIssues()
78+
}
7379
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dev.matsem.bpm.design.navigation
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Row
5+
import androidx.compose.foundation.shape.RoundedCornerShape
6+
import androidx.compose.material3.Icon
7+
import androidx.compose.material3.IconButton
8+
import androidx.compose.material3.IconButtonDefaults
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.Modifier
11+
import dev.matsem.bpm.design.theme.BpmTheme
12+
import kotlinx.collections.immutable.ImmutableList
13+
14+
@Composable
15+
fun BottomNavigationBar(
16+
items: ImmutableList<NavigationBarItem>,
17+
onClick: (NavigationBarItem) -> Unit,
18+
modifier: Modifier = Modifier,
19+
) {
20+
Row(
21+
modifier = modifier
22+
.background(color = BpmTheme.colorScheme.surfaceContainerHighest, shape = RoundedCornerShape(100))
23+
) {
24+
for (bottomNavItem in items) {
25+
IconButton(
26+
onClick = {
27+
onClick(bottomNavItem)
28+
},
29+
colors = if (bottomNavItem.isSelected) IconButtonDefaults.filledIconButtonColors() else IconButtonDefaults.iconButtonColors()
30+
) {
31+
Icon(
32+
bottomNavItem.icon,
33+
contentDescription = bottomNavItem.title
34+
)
35+
}
36+
}
37+
}
38+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package dev.matsem.bpm.design.navigation
2+
3+
import androidx.compose.material.icons.Icons
4+
import androidx.compose.material.icons.filled.Receipt
5+
import androidx.compose.material.icons.filled.Settings
6+
import androidx.compose.material.icons.filled.Timer
7+
import androidx.compose.runtime.Composable
8+
import androidx.compose.ui.graphics.painter.Painter
9+
import androidx.compose.ui.graphics.vector.rememberVectorPainter
10+
import bpm_tracker.shared.generated.resources.Res
11+
import bpm_tracker.shared.generated.resources.bottom_nav_logbook
12+
import bpm_tracker.shared.generated.resources.bottom_nav_settings
13+
import bpm_tracker.shared.generated.resources.bottom_nav_timer
14+
import org.jetbrains.compose.resources.stringResource
15+
16+
sealed interface NavigationBarItem {
17+
18+
val title: String @Composable get
19+
val icon: Painter @Composable get
20+
val isSelected: Boolean
21+
22+
data class Timer(override val isSelected: Boolean = false) : NavigationBarItem {
23+
override val title: String
24+
@Composable get() = stringResource(Res.string.bottom_nav_timer)
25+
override val icon: Painter
26+
@Composable get() = rememberVectorPainter(Icons.Filled.Timer)
27+
}
28+
29+
data class Logbook(override val isSelected: Boolean = false) : NavigationBarItem {
30+
override val title: String
31+
@Composable get() = stringResource(Res.string.bottom_nav_logbook)
32+
override val icon: Painter
33+
@Composable get() = rememberVectorPainter(Icons.Filled.Receipt)
34+
}
35+
36+
data class Settings(override val isSelected: Boolean = false) : NavigationBarItem {
37+
override val title: String
38+
@Composable get() = stringResource(Res.string.bottom_nav_settings)
39+
override val icon: Painter
40+
@Composable get() = rememberVectorPainter(Icons.Filled.Settings)
41+
}
42+
}

shared/src/commonMain/kotlin/dev/matsem/bpm/feature/app/presentation/AppWindowActions.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package dev.matsem.bpm.feature.app.presentation
22

33
import dev.matsem.bpm.data.repo.model.Timer
4+
import dev.matsem.bpm.design.navigation.NavigationBarItem
45

56
interface AppWindowActions {
67

7-
fun onSettingsClick()
8-
fun onSearchClick()
8+
fun onNavigationBarClick(item: NavigationBarItem)
9+
fun onNewTimerClick()
910
fun onOpenCommitDialog(timer: Timer)
1011

1112
fun onUpdateBannerDismissClick()
@@ -15,8 +16,8 @@ interface AppWindowActions {
1516

1617
companion object {
1718
fun noOp() = object : AppWindowActions {
18-
override fun onSettingsClick() = Unit
19-
override fun onSearchClick() = Unit
19+
override fun onNavigationBarClick(item: NavigationBarItem) = Unit
20+
override fun onNewTimerClick() = Unit
2021
override fun onOpenCommitDialog(timer: Timer) = Unit
2122
override fun onUpdateBannerDismissClick() = Unit
2223
override fun onDismissSheet() = Unit

shared/src/commonMain/kotlin/dev/matsem/bpm/feature/app/presentation/AppWindowModel.kt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import dev.matsem.bpm.arch.BaseModel
44
import dev.matsem.bpm.data.operation.UndoStack
55
import dev.matsem.bpm.data.repo.GitHubRepo
66
import dev.matsem.bpm.data.repo.model.Timer
7+
import dev.matsem.bpm.design.navigation.NavigationBarItem
78
import dev.matsem.bpm.tooling.Platform
89
import dev.matsem.bpm.tooling.VersionComparator
910
import kotlinx.coroutines.launch
@@ -28,10 +29,6 @@ internal class AppWindowModel(
2829
val currentVersion = platform.getVersionString()
2930
val isUpdateAvailable = VersionComparator.isUpdateAvailable(currentVersion, latestAppVersion.version)
3031

31-
println("latestAppVersion: $latestAppVersion")
32-
println("currentVersion: $currentVersion")
33-
println("isUpdateAvailable: $isUpdateAvailable")
34-
3532
updateState { state ->
3633
state.copy(
3734
newVersionBannerVisible = isUpdateAvailable,
@@ -43,24 +40,33 @@ internal class AppWindowModel(
4340
}
4441

4542
override val actions: AppWindowActions = object : AppWindowActions {
46-
override fun onSettingsClick() = updateState { state ->
47-
state.copy(sheet = AppWindowSheet.Settings)
43+
44+
override fun onNavigationBarClick(item: NavigationBarItem) = updateState { state ->
45+
state.copy(
46+
navigationState = state.navigationState.copy(
47+
content = when (item) {
48+
is NavigationBarItem.Timer -> AppWindowContent.Timer
49+
is NavigationBarItem.Logbook -> TODO("https://github.com/matejsemancik/tempo-timer/issues/7")
50+
is NavigationBarItem.Settings -> AppWindowContent.Settings
51+
}
52+
)
53+
)
4854
}
4955

50-
override fun onSearchClick() = updateState { state ->
51-
state.copy(sheet = AppWindowSheet.Search)
56+
override fun onNewTimerClick() = updateState { state ->
57+
state.copy(navigationState = state.navigationState.copy(sheet = AppWindowSheet.Search))
5258
}
5359

5460
override fun onOpenCommitDialog(timer: Timer) = updateState { state ->
55-
state.copy(sheet = AppWindowSheet.CommitDialog(timer))
61+
state.copy(navigationState = state.navigationState.copy(sheet = AppWindowSheet.CommitDialog(timer)))
5662
}
5763

5864
override fun onUpdateBannerDismissClick() = updateState { state ->
5965
state.copy(newVersionBannerVisible = false)
6066
}
6167

6268
override fun onDismissSheet() = updateState { state ->
63-
state.copy(sheet = null)
69+
state.copy(navigationState = state.navigationState.copy(sheet = null))
6470
}
6571

6672
override fun onUndo() {

shared/src/commonMain/kotlin/dev/matsem/bpm/feature/app/presentation/AppWindowState.kt

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,39 @@ package dev.matsem.bpm.feature.app.presentation
22

33
import dev.matsem.bpm.data.repo.model.AppVersion
44
import dev.matsem.bpm.data.repo.model.Timer
5-
6-
sealed interface AppWindowSheet {
7-
data object Settings : AppWindowSheet
8-
data object Search : AppWindowSheet
9-
data class CommitDialog(val timer: Timer) : AppWindowSheet
10-
}
5+
import dev.matsem.bpm.design.navigation.NavigationBarItem
6+
import kotlinx.collections.immutable.ImmutableList
7+
import kotlinx.collections.immutable.persistentListOf
118

129
data class AppWindowState(
1310
val newVersionBannerVisible: Boolean = false,
1411
val latestAppVersion: AppVersion? = null,
12+
val navigationState: AppWindowNavigationState = AppWindowNavigationState(
13+
content = AppWindowContent.Timer,
14+
sheet = null
15+
),
16+
) {
17+
val navigationItems: ImmutableList<NavigationBarItem>
18+
get() = persistentListOf(
19+
NavigationBarItem.Timer(isSelected = navigationState.content == AppWindowContent.Timer),
20+
NavigationBarItem.Settings(isSelected = navigationState.content == AppWindowContent.Settings),
21+
)
22+
23+
val isFabVisible: Boolean
24+
get() = navigationState.content == AppWindowContent.Timer
25+
}
26+
27+
data class AppWindowNavigationState(
28+
val content: AppWindowContent,
1529
val sheet: AppWindowSheet? = null,
16-
)
30+
)
31+
32+
sealed interface AppWindowContent {
33+
data object Timer : AppWindowContent
34+
data object Settings : AppWindowContent
35+
}
36+
37+
sealed interface AppWindowSheet {
38+
data object Search : AppWindowSheet
39+
data class CommitDialog(val timer: Timer) : AppWindowSheet
40+
}

0 commit comments

Comments
 (0)