Use composable scaffold.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-01-13 15:24:35 +01:00
parent 9c653d788b
commit f2cd02e130
23 changed files with 622 additions and 982 deletions

View File

@@ -96,25 +96,28 @@ dependencies {
implementation 'androidx.fragment:fragment-ktx:1.5.5'
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation 'androidx.compose.material:material-icons-extended:1.3.1'
implementation 'androidx.activity:activity-compose:1.3.1'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation 'androidx.activity:activity-compose:1.6.1'
implementation "androidx.compose.ui:ui:1.3.3"
implementation "androidx.compose.ui:ui-tooling-preview:1.3.3"
implementation "androidx.compose.runtime:runtime-livedata:1.3.3"
implementation "androidx.navigation:navigation-compose:2.5.3"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "com.google.dagger:hilt-android:2.44"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.3.3"
debugImplementation "androidx.compose.ui:ui-tooling:1.3.3"
debugImplementation "androidx.compose.ui:ui-test-manifest:1.3.3"
kapt "com.google.dagger:hilt-compiler:2.44"
implementation("androidx.room:room-runtime:2.4.3")
annotationProcessor("androidx.room:room-compiler:2.4.3")
kapt("androidx.room:room-compiler:2.4.3")
implementation("androidx.room:room-ktx:2.4.3")
implementation("androidx.multidex:multidex:2.0.1")
implementation "androidx.room:room-runtime:2.5.0"
annotationProcessor "androidx.room:room-compiler:2.5.0"
kapt "androidx.room:room-compiler:2.5.0"
implementation "androidx.room:room-ktx:2.5.0"
implementation "androidx.multidex:multidex:2.0.1"
api "androidx.navigation:navigation-fragment-ktx:2.5.3"
}
// Allow references to generated code

View File

@@ -1,50 +1,163 @@
package me.zobrist.tichucounter
import android.os.Bundle
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.navigation.NavigationView
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.Calculate
import androidx.compose.material.icons.outlined.List
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import dagger.hilt.android.AndroidEntryPoint
import me.zobrist.tichucounter.databinding.ActivityDrawerBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.ui.counter.*
@AndroidEntryPoint
class MainActivity : BaseActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDrawerBinding
private val counterViewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDrawerBinding.inflate(layoutInflater)
setContentView(binding.root)
setContent {
NavigationDrawer()
}
}
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_drawer)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyScaffoldLayout(
drawerState: DrawerState,
scope: CoroutineScope,
navController: NavHostController
) {
setSupportActionBar(binding.appBarDrawer.toolbar)
MaterialTheme() {
Scaffold(
topBar = { TopBar(drawerState, scope) }) {
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_counter, R.id.nav_history, R.id.nav_settings
), drawerLayout
NavHost(
navController = navController,
startDestination = "counter",
modifier = Modifier.padding(it)
) {
composable("counter") {
Counter(counterViewModel)
}
composable("history") {
Column() {
Text("History")
}
}
composable("settings") {
Column() {
Text("Settings")
}
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(drawerState: DrawerState, scope: CoroutineScope) {
CenterAlignedTopAppBar(
title = {
Text(
"Centered TopAppBar",
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
navigationIcon = {
IconButton(onClick = { scope.launch { drawerState.open() } }) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = "Localized description"
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_drawer)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
},
actions = {
IconButton(onClick = { /* doSomething() */ }) {
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = "Localized description"
)
}
}
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun NavigationDrawer() {
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
val navController = rememberNavController()
val items = listOf(Screen.Calculator, Screen.History, Screen.Settings)
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
ModalNavigationDrawer(
drawerState = drawerState,
drawerContent = {
ModalDrawerSheet {
Spacer(Modifier.height(12.dp))
items.forEach { screen ->
NavigationDrawerItem(
icon = { Icon(screen.icon, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
scope.launch { drawerState.close() }
navController.navigate(screen.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
}
},
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
)
}
}
},
content = { MyScaffoldLayout(drawerState, scope, navController) }
)
}
sealed class Screen(val route: String, val icon: ImageVector, @StringRes val resourceId: Int) {
object Calculator : Screen("counter", Icons.Outlined.Calculate, R.string.menu_counter)
object History : Screen("history", Icons.Outlined.List, R.string.menu_history)
object Settings : Screen("settings", Icons.Outlined.Settings, R.string.menu_settings)
}
}

View File

@@ -1,69 +0,0 @@
package me.zobrist.tichucounter.ui.counter
import android.os.Bundle
import android.view.*
import androidx.appcompat.app.AlertDialog
import androidx.core.view.MenuHost
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.R
import me.zobrist.tichucounter.databinding.FragmentCounterBinding
import me.zobrist.tichucounter.repository.GameRepository
import me.zobrist.tichucounter.ui.FragmentBase
import javax.inject.Inject
@AndroidEntryPoint
class CounterFragment : FragmentBase<FragmentCounterBinding>(), MenuProvider {
@Inject
lateinit var gameRepository: GameRepository
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentCounterBinding
get() = FragmentCounterBinding::inflate
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val menuHost: MenuHost = requireActivity()
menuHost.addMenuProvider(
this, viewLifecycleOwner, Lifecycle.State.RESUMED
)
}
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.menu_counter, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.action_new -> {
val builder = context?.let { AlertDialog.Builder(it) }
if (builder != null) {
builder.setMessage(getString(R.string.confirmNew)).setTitle(R.string.clear)
.setCancelable(false)
.setPositiveButton(getString(R.string.yes)) { dialog, _ ->
dialog.dismiss()
viewLifecycleOwner.lifecycleScope.launch {
gameRepository.newGame()
}
}.setNegativeButton(getString(R.string.no)) { dialog, _ ->
dialog.cancel()
}
builder.create().show()
}
true
}
R.id.action_undo -> {
viewLifecycleOwner.lifecycleScope.launch {
gameRepository.revertLastRound()
}
true
}
else -> false
}
}
}

View File

@@ -0,0 +1,43 @@
package me.zobrist.tichucounter.ui.counter
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun Counter(
viewModel: CounterViewModel
) {
Column() {
TeamNamesView(
viewModel.teamNameA,
viewModel.teamNameB,
{ viewModel.updateNameA(it) },
{ viewModel.updateNameB(it) })
TeamScoresView(
viewModel.totalScoreA,
viewModel.totalScoreB
)
RoundListView(
viewModel.roundScoreList,
Modifier.weight(1f)
)
KeyboardView(
viewModel.currentScoreA,
viewModel.currentScoreB,
viewModel.requestFocusA,
viewModel.enableSubmit,
{ viewModel.updateFocusStateA(it) },
{ viewModel.updateFocusStateB(it) },
{ viewModel.digitClicked(it) },
{ viewModel.addSub100Clicked(it) },
{ viewModel.deleteClicked() },
{ viewModel.negateClicked() },
{ viewModel.submitClicked() }
)
}
}

View File

@@ -8,17 +8,39 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.GameDao
import me.zobrist.tichucounter.data.Round
import me.zobrist.tichucounter.data.RoundDao
import me.zobrist.tichucounter.domain.Tichu
import me.zobrist.tichucounter.repository.GameRepository
import javax.inject.Inject
@HiltViewModel
class KeyboardViewModel @Inject constructor(private val gameRepository: GameRepository) :
class CounterViewModel @Inject constructor(
private val gameRepository: GameRepository,
private val roundDao: RoundDao,
private val gameDao: GameDao
) :
ViewModel() {
var scoreA by mutableStateOf("")
var roundScoreList by mutableStateOf(emptyList<Round>())
var totalScoreA by mutableStateOf(0)
private set
var scoreB by mutableStateOf("")
var totalScoreB by mutableStateOf(0)
private set
var teamNameA by mutableStateOf("")
private set
var teamNameB by mutableStateOf("")
private set
var currentScoreA by mutableStateOf("")
private set
var currentScoreB by mutableStateOf("")
private set
var enableSubmit by mutableStateOf(false)
@@ -34,89 +56,58 @@ class KeyboardViewModel @Inject constructor(private val gameRepository: GameRepo
private var activeValue: String
get() {
return if (isBFocused) {
scoreB
currentScoreB
} else {
scoreA
currentScoreA
}
}
set(value) {
if (isBFocused) {
scoreB = value
currentScoreB = value
} else {
scoreA = value
currentScoreA = value
}
}
private var inactiveValue: String
get() {
return if (isAFocused) {
scoreB
currentScoreB
} else {
scoreA
currentScoreA
}
}
set(value) {
if (isAFocused) {
scoreB = value
currentScoreB = value
} else {
scoreA = value
currentScoreA = value
}
}
fun submitScore() {
init {
viewModelScope.launch {
gameRepository.addRoundToActiveGame(scoreA.toInt(), scoreB.toInt())
roundDao.getForActiveGame().collect {
roundScoreList = it
}
scoreA = ""
scoreB = ""
enableSubmit = false
}
fun appendToFocusedScore(toAppend: String) {
giveFocusToAIfNone()
activeValue += toAppend
updateOtherScore()
updateSubmitButton()
viewModelScope.launch {
gameDao.getActive().collect {
if (it != null) {
teamNameA = it.nameA
teamNameB = it.nameB
}
}
}
fun negateActiveInput() {
giveFocusToAIfNone()
activeValue = if (activeValue.contains("-")) {
activeValue.replace("-", "")
} else {
"-$activeValue"
viewModelScope.launch {
roundDao.getRoundSumForActiveGame().collect { score ->
totalScoreA = score.scoreA
totalScoreB = score.scoreB
}
updateOtherScore()
updateSubmitButton()
}
fun addToActiveInput(toAdd: Int) {
giveFocusToAIfNone()
activeValue = try {
val temp = activeValue.toInt() + toAdd
temp.toString()
} catch (e: Exception) {
toAdd.toString()
}
if(inactiveValue == "")
{
updateOtherScore()
}
updateSubmitButton()
}
fun removeLastCharFromActive() {
if (activeValue != "") {
activeValue = activeValue.dropLast(1)
}
updateOtherScore()
}
private fun giveFocusToAIfNone() {
if (!isAFocused && !isBFocused) {
@@ -142,7 +133,7 @@ class KeyboardViewModel @Inject constructor(private val gameRepository: GameRepo
private fun isValidTichuRound(): Boolean {
return try {
val tichu = Tichu()
tichu.isValidRound(scoreA.toInt(), scoreB.toInt())
tichu.isValidRound(currentScoreA.toInt(), currentScoreB.toInt())
} catch (_: java.lang.NumberFormatException) {
false
}
@@ -151,4 +142,80 @@ class KeyboardViewModel @Inject constructor(private val gameRepository: GameRepo
private fun updateSubmitButton() {
enableSubmit = isValidTichuRound()
}
fun submitClicked() {
viewModelScope.launch {
gameRepository.addRoundToActiveGame(currentScoreA.toInt(), currentScoreB.toInt())
}
currentScoreA = ""
currentScoreB = ""
enableSubmit = false
}
fun digitClicked(digit: String) {
giveFocusToAIfNone()
activeValue += digit
updateOtherScore()
updateSubmitButton()
}
fun negateClicked() {
giveFocusToAIfNone()
activeValue = if (activeValue.contains("-")) {
activeValue.replace("-", "")
} else {
"-$activeValue"
}
updateOtherScore()
updateSubmitButton()
}
fun addSub100Clicked(toAdd: Int) {
giveFocusToAIfNone()
activeValue = try {
val temp = activeValue.toInt() + toAdd
temp.toString()
} catch (e: Exception) {
toAdd.toString()
}
if (inactiveValue == "") {
updateOtherScore()
}
updateSubmitButton()
}
fun deleteClicked() {
if (activeValue != "") {
activeValue = activeValue.dropLast(1)
}
updateOtherScore()
}
fun updateNameA(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameA = value
gameRepository.updateGame(game)
}
}
fun updateNameB(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameB = value
gameRepository.updateGame(game)
}
}
fun updateFocusStateA(state: Boolean) {
isAFocused = state
}
fun updateFocusStateB(state: Boolean) {
isBFocused = state
}
}

View File

@@ -1,161 +0,0 @@
package me.zobrist.tichucounter.ui.counter
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Backspace
import androidx.compose.material.icons.outlined.Check
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.stringResource
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import me.zobrist.tichucounter.R
@AndroidEntryPoint
class Keyboard : Fragment() {
private val viewModel: KeyboardViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
// Dispose of the Composition when the view's LifecycleOwner
// is destroyed
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
KeyboardView(viewModel)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun KeyboardView(viewModel: KeyboardViewModel) {
val keyboardController = LocalSoftwareKeyboardController.current
Column {
Row {
TextField(
value = viewModel.scoreA,
onValueChange = { },
placeholder = { Text("0") },
singleLine = true,
readOnly = true,
modifier = Modifier
.onFocusChanged {
keyboardController?.hide()
viewModel.isAFocused = it.isFocused
}
.focusRequester(viewModel.requestFocusA)
.weight(1f),
)
TextField(
value = viewModel.scoreB,
onValueChange = { },
placeholder = { Text("0") },
singleLine = true,
readOnly = true,
modifier = Modifier
.onFocusChanged {
keyboardController?.hide()
viewModel.isBFocused = it.isFocused
}
.weight(1f)
)
}
Row {
TextButton(
onClick = { viewModel.appendToFocusedScore("1") },
modifier = Modifier.weight(1F)
) { Text("1") }
TextButton(
onClick = { viewModel.appendToFocusedScore("2") },
modifier = Modifier.weight(1F)
) { Text("2") }
TextButton(
onClick = { viewModel.appendToFocusedScore("3") },
modifier = Modifier.weight(1F)
) { Text("3") }
TextButton(
onClick = { viewModel.addToActiveInput(100) },
modifier = Modifier.weight(1F)
) { Text("+100") }
}
Row {
TextButton(
onClick = { viewModel.appendToFocusedScore("4") },
modifier = Modifier.weight(1F)
) { Text("4") }
TextButton(
onClick = { viewModel.appendToFocusedScore("5") },
modifier = Modifier.weight(1F)
) { Text("5") }
TextButton(
onClick = { viewModel.appendToFocusedScore("6") },
modifier = Modifier.weight(1F)
) { Text("6") }
TextButton(
onClick = { viewModel.addToActiveInput(-100) },
modifier = Modifier.weight(1F)
) { Text("-100") }
}
Row {
TextButton(
onClick = { viewModel.appendToFocusedScore("7") },
modifier = Modifier.weight(1F)
) { Text("7") }
TextButton(
onClick = { viewModel.appendToFocusedScore("8") },
modifier = Modifier.weight(1F)
) { Text("8") }
TextButton(
onClick = { viewModel.appendToFocusedScore("9") },
modifier = Modifier.weight(1F)
) { Text("9") }
IconButton(
onClick = { viewModel.removeLastCharFromActive() },
modifier = Modifier.weight(1F)
) { Icon(Icons.Outlined.Backspace, stringResource(R.string.submit)) }
}
Row {
TextButton(
onClick = { viewModel.negateActiveInput() },
modifier = Modifier.weight(1F)
) { Text("+/-") }
TextButton(
onClick = { viewModel.appendToFocusedScore("0") },
modifier = Modifier.weight(1F)
) { Text("0") }
Spacer(modifier = Modifier.weight(1F))
IconButton(
onClick = { viewModel.submitScore() },
modifier = Modifier.weight(1F),
enabled = viewModel.enableSubmit
) { Icon(Icons.Outlined.Check, stringResource(R.string.submit)) }
}
}
}
}

View File

@@ -0,0 +1,141 @@
package me.zobrist.tichucounter.ui.counter
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Backspace
import androidx.compose.material.icons.outlined.Check
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import me.zobrist.tichucounter.R
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun KeyboardView(
scoreA: String,
scoreB: String,
requestFocusA: FocusRequester,
enableSubmit: Boolean,
updateFocusStateA: (Boolean) -> Unit,
updateFocusStateB: (Boolean) -> Unit,
digitClicked: (String) -> Unit,
addSub100Clicked: (Int) -> Unit,
deleteClicked: () -> Unit,
negateClicked: () -> Unit,
submitClicked: () -> Unit
) {
val keyboardController = LocalSoftwareKeyboardController.current
Column {
Row {
TextField(
value = scoreA,
onValueChange = { },
placeholder = { Text("0") },
singleLine = true,
readOnly = true,
modifier = Modifier
.onFocusChanged {
keyboardController?.hide()
updateFocusStateA(it.isFocused)
}
.focusRequester(requestFocusA)
.weight(1f),
)
TextField(
value = scoreB,
onValueChange = { },
placeholder = { Text("0") },
singleLine = true,
readOnly = true,
modifier = Modifier
.onFocusChanged {
keyboardController?.hide()
updateFocusStateB(it.isFocused)
}
.weight(1f)
)
}
Row {
TextButton(
onClick = { digitClicked("1") },
modifier = Modifier.weight(1F)
) { Text("1") }
TextButton(
onClick = { digitClicked("2") },
modifier = Modifier.weight(1F)
) { Text("2") }
TextButton(
onClick = { digitClicked("3") },
modifier = Modifier.weight(1F)
) { Text("3") }
TextButton(
onClick = { addSub100Clicked(100) },
modifier = Modifier.weight(1F)
) { Text("+100") }
}
Row {
TextButton(
onClick = { digitClicked("4") },
modifier = Modifier.weight(1F)
) { Text("4") }
TextButton(
onClick = { digitClicked("5") },
modifier = Modifier.weight(1F)
) { Text("5") }
TextButton(
onClick = { digitClicked("6") },
modifier = Modifier.weight(1F)
) { Text("6") }
TextButton(
onClick = { addSub100Clicked(-100) },
modifier = Modifier.weight(1F)
) { Text("-100") }
}
Row {
TextButton(
onClick = { digitClicked("7") },
modifier = Modifier.weight(1F)
) { Text("7") }
TextButton(
onClick = { digitClicked("8") },
modifier = Modifier.weight(1F)
) { Text("8") }
TextButton(
onClick = { digitClicked("9") },
modifier = Modifier.weight(1F)
) { Text("9") }
IconButton(
onClick = { deleteClicked() },
modifier = Modifier.weight(1F)
) { Icon(Icons.Outlined.Backspace, stringResource(R.string.submit)) }
}
Row {
TextButton(
onClick = { negateClicked() },
modifier = Modifier.weight(1F)
) { Text("+/-") }
TextButton(
onClick = { digitClicked("0") },
modifier = Modifier.weight(1F)
) { Text("0") }
Spacer(modifier = Modifier.weight(1F))
IconButton(
onClick = { submitClicked() },
modifier = Modifier.weight(1F),
enabled = enableSubmit
) { Icon(Icons.Outlined.Check, stringResource(R.string.submit)) }
}
}
}

View File

@@ -1,114 +0,0 @@
package me.zobrist.tichucounter.ui.counter
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.Round
@AndroidEntryPoint
class RoundList : Fragment() {
private val viewModel: RoundListViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
// Dispose of the Composition when the view's LifecycleOwner
// is destroyed
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
RoundListView(viewModel)
}
}
}
}
@Composable
fun RoundListView(viewModel: RoundListViewModel) {
RoundListView(viewModel.scores)
}
@Composable
fun RoundListView(rounds: List<Round>) {
val lazyListState = rememberLazyListState()
val scope = rememberCoroutineScope()
LazyColumn(state = lazyListState) {
itemsIndexed(rounds) { index, item ->
RoundListItem(item, index, lazyListState)
}
scope.launch {
lazyListState.animateScrollToItem(viewModel.scores.size)
}
}
}
@Composable
fun RoundListItem(round: Round, index: Int, lazyListState: LazyListState) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(all = 4.dp)
) {
Text(
text = round.scoreA.toString(),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(5f),
textAlign = TextAlign.Center
)
Text(
text = index.toString(),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center
)
Text(
text = round.scoreB.toString(),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(5f),
textAlign = TextAlign.Center
)
}
}
@Composable
@Preview
fun RoundListViewPreview() {
val rounds = listOf<Round>(
Round(1, 10, 90),
Round(1, 5, 95),
Round(1, 100, 0),
Round(1, 125, -25),
Round(1, 50, 50)
)
RoundListView(rounds)
}
}

View File

@@ -0,0 +1,76 @@
package me.zobrist.tichucounter.ui.counter
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.Round
@Composable
fun RoundListView(rounds: List<Round>, modifier: Modifier) {
val lazyListState = rememberLazyListState()
val scope = rememberCoroutineScope()
LazyColumn(state = lazyListState, modifier = modifier) {
itemsIndexed(rounds) { index, item ->
RoundListItem(item, index, lazyListState)
}
scope.launch {
lazyListState.animateScrollToItem(rounds.size)
}
}
}
@Composable
private fun RoundListItem(round: Round, index: Int, lazyListState: LazyListState) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(all = 4.dp)
) {
Text(
text = round.scoreA.toString(),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(5f),
textAlign = TextAlign.Center
)
Text(
text = index.toString(),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center
)
Text(
text = round.scoreB.toString(),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(5f),
textAlign = TextAlign.Center
)
}
}
@Composable
@Preview
fun RoundListViewPreview() {
val rounds = listOf<Round>(
Round(1, 10, 90),
Round(1, 5, 95),
Round(1, 100, 0),
Round(1, 125, -25),
Round(1, 50, 50)
)
RoundListView(rounds, Modifier)
}

View File

@@ -1,28 +0,0 @@
package me.zobrist.tichucounter.ui.counter
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 kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.Round
import me.zobrist.tichucounter.data.RoundDao
import javax.inject.Inject
@HiltViewModel
class RoundListViewModel @Inject constructor(private val roundDao: RoundDao) : ViewModel(){
var scores by mutableStateOf(emptyList<Round>())
init {
viewModelScope.launch {
roundDao.getForActiveGame().collect {
scores = it
}
}
}
}

View File

@@ -1,84 +0,0 @@
package me.zobrist.tichucounter.ui.counter
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.tooling.preview.Preview
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class TeamNames : Fragment() {
private val viewModel: TeamNamesViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
// Dispose of the Composition when the view's LifecycleOwner
// is destroyed
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
TeamNamesView(viewModel)
}
}
}
}
@Composable
private fun TeamNamesView(viewModel: TeamNamesViewModel) {
TeamNamesView(
viewModel.nameA,
viewModel.nameB,
{ viewModel.updateNameA(it)},
{ viewModel.updateNameB(it)})
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TeamNamesView(
nameA: String,
nameB: String,
updateA: (String) -> Unit,
updateB: (String) -> Unit
){
Row() {
TextField(
value = nameA,
onValueChange = { updateA(it) },
singleLine = true,
modifier = Modifier.weight(1f))
TextField(
value = nameB,
onValueChange = { updateB(it) },
singleLine = true,
modifier = Modifier.weight(1f))
}
}
@Preview
@Composable
private fun TeamNamesView() {
TeamNamesView("TeamA", "TeamB", {}, {})
}
}

View File

@@ -0,0 +1,39 @@
package me.zobrist.tichucounter.ui.counter
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TeamNamesView(
nameA: String,
nameB: String,
updateA: (String) -> Unit,
updateB: (String) -> Unit
) {
Row() {
TextField(
value = nameA,
onValueChange = { updateA(it) },
singleLine = true,
modifier = Modifier.weight(1f)
)
TextField(
value = nameB,
onValueChange = { updateB(it) },
singleLine = true,
modifier = Modifier.weight(1f)
)
}
}
@Preview
@Composable
private fun TeamNamesViewPreview() {
TeamNamesView("TeamA", "TeamB", {}, {})
}

View File

@@ -1,56 +0,0 @@
package me.zobrist.tichucounter.ui.counter
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.Game
import me.zobrist.tichucounter.data.GameDao
import me.zobrist.tichucounter.repository.GameRepository
import javax.inject.Inject
@HiltViewModel
class TeamNamesViewModel @Inject constructor(
private val gameDao: GameDao,
private val gameRepository: GameRepository
) :
ViewModel() {
var nameA by mutableStateOf("")
private set
var nameB by mutableStateOf("")
private set
init {
viewModelScope.launch {
gameDao.getActive().collect {
if (it != null) {
nameA = it.nameA
nameB = it.nameB
}
}
}
}
fun updateNameA(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameA = value
gameRepository.updateGame(game)
}
}
fun updateNameB(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameB = value
gameRepository.updateGame(game)
}
}
}

View File

@@ -1,72 +0,0 @@
package me.zobrist.tichucounter.ui.counter
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint
import me.zobrist.tichucounter.ui.FragmentBase
@AndroidEntryPoint
class TeamScores : Fragment() {
private val viewModel: TeamScoresViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
// Dispose of the Composition when the view's LifecycleOwner
// is destroyed
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
TeamScoresView(viewModel)
}
}
}
}
@Composable
private fun TeamScoresView(viewModel: TeamScoresViewModel) {
TeamScoresView(viewModel.scoreA, viewModel.scoreB)
}
@Composable
private fun TeamScoresView(scoreA: Int, scoreB: Int,){
Row() {
Text(
text = scoreA.toString(),
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center)
Text(
text = scoreB.toString(),
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center)
}
}
@Preview
@Composable
private fun TeamNamesView() {
TeamScoresView(10, 90)
}
}

View File

@@ -0,0 +1,32 @@
package me.zobrist.tichucounter.ui.counter
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun TeamScoresView(scoreA: Int, scoreB: Int) {
Row() {
Text(
text = scoreA.toString(),
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center
)
Text(
text = scoreB.toString(),
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center
)
}
}
@Preview
@Composable
private fun TeamNamesView() {
TeamScoresView(10, 90)
}

View File

@@ -1,34 +0,0 @@
package me.zobrist.tichucounter.ui.counter
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.RoundDao
import javax.inject.Inject
@HiltViewModel
class TeamScoresViewModel @Inject constructor(private val roundDao: RoundDao) : ViewModel() {
var scoreA by mutableStateOf(0)
private set
var scoreB by mutableStateOf(0)
private set
init {
viewModelScope.launch {
roundDao.getRoundSumForActiveGame().collect { score ->
scoreA = score.scoreA
scoreB = score.scoreB
}
}
}
}

View File

@@ -1,71 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/left"
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2"
app:layout_constraintEnd_toStartOf="@+id/right"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/teamNames"
android:name="me.zobrist.tichucounter.ui.counter.TeamNames"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout="@layout/fragment_team_names" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/teamScores"
android:name="me.zobrist.tichucounter.ui.counter.TeamScores"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/teamNames"
tools:layout="@layout/fragment_team_scores" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/scrollHistory"
android:name="me.zobrist.tichucounter.ui.counter.RoundList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:clickable="false"
tools:layout="@layout/fragment_round_list" />
</LinearLayout>
<LinearLayout
android:id="@+id/right"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/left">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/keyboard"
android:name="me.zobrist.tichucounter.ui.counter.Keyboard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout="@layout/fragment_keyboard" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:id="@+id/app_bar_drawer"
layout="@layout/app_bar_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_drawer"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_drawer" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/app_bar_drawer">
<fragment
android:id="@+id/nav_host_fragment_content_drawer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/teamNames"
android:name="me.zobrist.tichucounter.ui.counter.TeamNames"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout="@layout/fragment_team_names" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/teamScores"
android:name="me.zobrist.tichucounter.ui.counter.TeamScores"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/teamNames"
tools:layout="@layout/fragment_team_scores" />
<View
android:id="@+id/dividerTop"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_weight="1"
android:background="?android:attr/listDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/teamScores"
tools:layout_editor_absoluteY="50dp" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/scrollHistory"
android:name="me.zobrist.tichucounter.ui.counter.RoundList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toTopOf="@id/dividerBottom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dividerTop"
tools:layout="@layout/fragment_round_list" />
<View
android:id="@+id/dividerBottom"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"
app:layout_constraintBottom_toTopOf="@id/keyboard"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/keyboard"
android:name="me.zobrist.tichucounter.ui.counter.Keyboard"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout="@layout/fragment_keyboard" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/nav_header_desc"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@mipmap/ic_launcher_round" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@string/app_name"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle" />
</LinearLayout>