forked from Writand/writand
Merge branch 'frontend/file-menu' into 'main'
File menu Closes #25 See merge request EmmaVandewalle/writand!50
This commit is contained in:
commit
72e8c88ef1
9 changed files with 338 additions and 241 deletions
|
@ -42,7 +42,7 @@ android {
|
||||||
compose true
|
compose true
|
||||||
}
|
}
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion '1.5.0'
|
kotlinCompilerExtensionVersion '1.5.7'
|
||||||
}
|
}
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
resources {
|
resources {
|
||||||
|
|
|
@ -63,13 +63,13 @@ fun WNavGraph(navHostController: NavHostController, modifier: Modifier) {
|
||||||
// Editor view
|
// Editor view
|
||||||
|
|
||||||
composable(WAppDestinations.MAIN_EDITOR + "/{projectId}/{path}") { entry ->
|
composable(WAppDestinations.MAIN_EDITOR + "/{projectId}/{path}") { entry ->
|
||||||
val projectId: Int? = entry.arguments?.getInt("projectId")
|
val projectId: String? = entry.arguments?.getString("projectId")
|
||||||
val path: String? =
|
val path: String? =
|
||||||
entry.arguments?.getString("path")?.let { URLDecoder.decode(it, "UTF-8") }
|
entry.arguments?.getString("path")?.let { URLDecoder.decode(it, "UTF-8") }
|
||||||
if (projectId != null) {
|
if (projectId != null) {
|
||||||
EditorScreen(
|
EditorScreen(
|
||||||
navHostController = navHostController,
|
navHostController = navHostController,
|
||||||
projectId = projectId,
|
projectId = projectId.toInt(),
|
||||||
path = path ?: "./"
|
path = path ?: "./"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,9 @@ fun EditorScreen(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
BottomEditorBar()
|
BottomEditorBar(
|
||||||
|
navHostController = navHostController
|
||||||
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Row(modifier = Modifier.padding(it).padding(10.dp)) {
|
Row(modifier = Modifier.padding(it).padding(10.dp)) {
|
||||||
|
|
|
@ -1,17 +1,44 @@
|
||||||
package be.re.writand.screens.editor.bottom
|
package be.re.writand.screens.editor.bottom
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.sizeIn
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Home
|
||||||
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
|
import androidx.compose.material.icons.filled.Settings
|
||||||
|
import androidx.compose.material.icons.outlined.ExitToApp
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
import be.re.writand.R
|
||||||
|
import be.re.writand.screens.WUIGlobals
|
||||||
|
import be.re.writand.screens.components.WButton
|
||||||
|
import be.re.writand.screens.components.WPopup
|
||||||
import be.re.writand.screens.components.WText
|
import be.re.writand.screens.components.WText
|
||||||
|
import be.re.writand.screens.projectpicker.ProjectPickerComponent
|
||||||
|
import be.re.writand.screens.projectpicker.ProjectPickerViewModel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bar component that represents the bottom of the editor itself.
|
* Bar component that represents the bottom of the editor itself.
|
||||||
|
@ -19,20 +46,55 @@ import be.re.writand.screens.components.WText
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun BottomEditorBar(
|
fun BottomEditorBar(
|
||||||
vM: BottomEditorBarViewModel = hiltViewModel()
|
navHostController: NavHostController,
|
||||||
|
vM: BottomEditorBarViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val row = vM.row.collectAsState()
|
val row = vM.row.collectAsState()
|
||||||
val column = vM.column.collectAsState()
|
val column = vM.column.collectAsState()
|
||||||
|
|
||||||
|
val openFileMenu = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 15.dp, vertical = 15.dp),
|
.padding(horizontal = 15.dp, vertical = 15.dp),
|
||||||
horizontalArrangement = Arrangement.End
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.sizeIn(minWidth = 50.dp)
|
||||||
|
.clickable { openFileMenu.value = true },
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Home,
|
||||||
|
contentDescription = "Open File Menu",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(WUIGlobals.iconSize)
|
||||||
|
.padding(end = 5.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
WText(text = "${row.value}:${column.value}")
|
WText(text = "${row.value}:${column.value}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (openFileMenu.value) {
|
||||||
|
WPopup(
|
||||||
|
titleBar = {},
|
||||||
|
width = 600.dp,
|
||||||
|
height = 500.dp,
|
||||||
|
onDismiss = { openFileMenu.value = false }) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(color = MaterialTheme.colorScheme.primary),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
ProjectPickerComponent(
|
||||||
|
navHostController = navHostController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
package be.re.writand.screens.projectpicker
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
import be.re.writand.data.local.models.Project
|
||||||
|
import be.re.writand.navigation.WAppDestinations
|
||||||
|
import be.re.writand.screens.WUIGlobals
|
||||||
|
import be.re.writand.screens.components.TopPopUpBar
|
||||||
|
import be.re.writand.screens.components.WBorderButton
|
||||||
|
import be.re.writand.screens.components.WButton
|
||||||
|
import be.re.writand.screens.components.WLoadingIndicator
|
||||||
|
import be.re.writand.screens.components.WPopup
|
||||||
|
import be.re.writand.screens.components.WText
|
||||||
|
import be.re.writand.screens.directoryprovider.DirectoryProvider
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A composable that shows a list of projects and allows the user to open them.
|
||||||
|
* The screen has two parts: a list of recent projects, and a set of buttons
|
||||||
|
* to open a project or create a new one.
|
||||||
|
* @param[navHostController] the navigation host controller used to navigate to other screens.
|
||||||
|
* @param[modifier] the basic modifier for the component
|
||||||
|
* @param[vM] the view model of the screen, used to get the projects.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun ProjectPickerComponent(
|
||||||
|
navHostController: NavHostController,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
vM: ProjectPickerViewModel = hiltViewModel()
|
||||||
|
) {
|
||||||
|
val projects by vM.projects.collectAsState()
|
||||||
|
val openDialog = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
WText(
|
||||||
|
text = "Recent projects",
|
||||||
|
settingsFontSizeAlterBy = WUIGlobals.HEADING
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(width = 500.dp, height = 400.dp)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(350.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.border(
|
||||||
|
1.dp,
|
||||||
|
color = MaterialTheme.colorScheme.tertiary,
|
||||||
|
shape = RoundedCornerShape(WUIGlobals.cornerRadius)
|
||||||
|
)
|
||||||
|
.clip(shape = RoundedCornerShape(WUIGlobals.cornerRadius)),
|
||||||
|
) {
|
||||||
|
when (val value = projects) {
|
||||||
|
ProjectPickerUiState.Loading -> {
|
||||||
|
WLoadingIndicator()
|
||||||
|
}
|
||||||
|
|
||||||
|
is ProjectPickerUiState.Success -> {
|
||||||
|
LazyColumn {
|
||||||
|
items(value.projects.size) { project ->
|
||||||
|
ProjectItem(value.projects[project], navHostController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
verticalAlignment = Alignment.Bottom,
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
WButton("Open/Create Project", onClick = {
|
||||||
|
openDialog.value = !openDialog.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openDialog.value) {
|
||||||
|
DirectoryProvider(
|
||||||
|
onDismiss = { openDialog.value = false },
|
||||||
|
onConfirm = {
|
||||||
|
val newProject = Project(projectId = vM.amountOfProjects + 1, path = it)
|
||||||
|
vM.addProject(newProject)
|
||||||
|
navHostController.navigate(
|
||||||
|
WAppDestinations.MAIN_EDITOR
|
||||||
|
+ "/${newProject.projectId}/${
|
||||||
|
URLEncoder.encode(
|
||||||
|
newProject.path,
|
||||||
|
"UTF-8"
|
||||||
|
)
|
||||||
|
}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A composable that shows a single project.
|
||||||
|
* @param[project] the project to show.
|
||||||
|
* @param[navHostController] the navigation host controller to navigate to the editor screen.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun ProjectItem(
|
||||||
|
project: Project,
|
||||||
|
navHostController: NavHostController
|
||||||
|
) {
|
||||||
|
val showProjectConfirmation = remember { mutableStateOf(false) }
|
||||||
|
val name = project.path.split(File.separator).last()
|
||||||
|
|
||||||
|
var isClicked by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
color = if (isClicked) MaterialTheme.colorScheme.secondary
|
||||||
|
else MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 15.dp, horizontal = 10.dp)
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectTapGestures(
|
||||||
|
onTap = {
|
||||||
|
isClicked = true
|
||||||
|
},
|
||||||
|
onDoubleTap = {
|
||||||
|
isClicked = true
|
||||||
|
showProjectConfirmation.value = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
WText(text = name)
|
||||||
|
WText(text = project.path)
|
||||||
|
}
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showProjectConfirmation.value) {
|
||||||
|
PickProjectPopup(
|
||||||
|
name = name,
|
||||||
|
project = project,
|
||||||
|
onDismiss = { showProjectConfirmation.value = false },
|
||||||
|
navHostController = navHostController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(isClicked) {
|
||||||
|
if (isClicked) {
|
||||||
|
delay(200L)
|
||||||
|
isClicked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pop up asking for confirmation before opening a project.
|
||||||
|
* @param[name] the name of the project to be opened.
|
||||||
|
* @param[project] the project to be opened.
|
||||||
|
* @param[onDismiss] a function to be called when the pop up is to be closed.
|
||||||
|
* @param[navHostController] the navigation host controller used to navigate to the editor screen.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun PickProjectPopup(
|
||||||
|
name: String,
|
||||||
|
project: Project,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
navHostController: NavHostController
|
||||||
|
) {
|
||||||
|
WPopup(
|
||||||
|
titleBar = {
|
||||||
|
TopPopUpBar(title = "Open \"$name\"", onDismiss = onDismiss)
|
||||||
|
},
|
||||||
|
width = 500.dp,
|
||||||
|
height = 250.dp,
|
||||||
|
onDismiss = onDismiss,
|
||||||
|
bottomBar = {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
WBorderButton(
|
||||||
|
text = "Cancel",
|
||||||
|
onClick = onDismiss
|
||||||
|
)
|
||||||
|
|
||||||
|
WButton(
|
||||||
|
text = "Continue",
|
||||||
|
onClick = {
|
||||||
|
onDismiss()
|
||||||
|
navHostController.navigate(
|
||||||
|
WAppDestinations.MAIN_EDITOR
|
||||||
|
+ "/${project.projectId}/${
|
||||||
|
URLEncoder.encode(
|
||||||
|
project.path,
|
||||||
|
"UTF-8"
|
||||||
|
)
|
||||||
|
}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(it),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
WText(text = "Are you sure you want to open \"$name\"?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,69 +2,35 @@ package be.re.writand.screens.projectpicker
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Settings
|
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import be.re.writand.data.local.models.Project
|
|
||||||
import be.re.writand.navigation.WAppDestinations
|
|
||||||
import be.re.writand.screens.WUIGlobals
|
import be.re.writand.screens.WUIGlobals
|
||||||
import be.re.writand.screens.components.TopPopUpBar
|
|
||||||
import be.re.writand.screens.components.WBorderButton
|
|
||||||
import be.re.writand.screens.components.WButton
|
|
||||||
import be.re.writand.screens.components.WLoadingIndicator
|
|
||||||
import be.re.writand.screens.components.WLogoImage
|
import be.re.writand.screens.components.WLogoImage
|
||||||
import be.re.writand.screens.components.WPopup
|
|
||||||
import be.re.writand.screens.components.WText
|
|
||||||
import be.re.writand.screens.directoryprovider.DirectoryProvider
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URLEncoder
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A composable that shows a list of projects and allows the user to open them.
|
* A composable that shows a list of projects and allows the user to open them.
|
||||||
* The screen has two parts: a list of recent projects, and a set of buttons
|
* The screen has two parts: a list of recent projects, and a set of buttons
|
||||||
* to open a project or create a new one.
|
* to open a project or create a new one.
|
||||||
* @param[navHostController] the navigation host controller used to navigate to other screens.
|
* @param[navHostController] the navigation host controller used to navigate to other screens.
|
||||||
* @param[vM] the view model of the screen, used to get the projects.
|
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun ProjectPickerScreen(
|
fun ProjectPickerScreen(
|
||||||
navHostController: NavHostController,
|
navHostController: NavHostController
|
||||||
vM: ProjectPickerViewModel = hiltViewModel()
|
|
||||||
) {
|
) {
|
||||||
val projects by vM.projects.collectAsState()
|
|
||||||
val openDialog = remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = MaterialTheme.colorScheme.secondary),
|
.background(color = MaterialTheme.colorScheme.secondary),
|
||||||
|
@ -87,200 +53,10 @@ fun ProjectPickerScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Column(
|
ProjectPickerComponent(
|
||||||
modifier = Modifier
|
navHostController = navHostController,
|
||||||
.padding(it)
|
modifier = Modifier.padding(it)
|
||||||
.fillMaxSize(),
|
)
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
WText(
|
|
||||||
text = "Recent projects",
|
|
||||||
settingsFontSizeAlterBy = WUIGlobals.HEADING
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 500.dp, height = 400.dp)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.height(350.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.border(
|
|
||||||
1.dp,
|
|
||||||
color = MaterialTheme.colorScheme.tertiary,
|
|
||||||
shape = RoundedCornerShape(WUIGlobals.cornerRadius)
|
|
||||||
)
|
|
||||||
.clip(shape = RoundedCornerShape(WUIGlobals.cornerRadius)),
|
|
||||||
) {
|
|
||||||
when (val value = projects) {
|
|
||||||
ProjectPickerUiState.Loading -> {
|
|
||||||
WLoadingIndicator()
|
|
||||||
}
|
|
||||||
|
|
||||||
is ProjectPickerUiState.Success -> {
|
|
||||||
LazyColumn {
|
|
||||||
items(value.projects.size) { project ->
|
|
||||||
ProjectItem(value.projects[project], navHostController)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
verticalAlignment = Alignment.Bottom,
|
|
||||||
horizontalArrangement = Arrangement.End
|
|
||||||
) {
|
|
||||||
WButton("Open/Create Project", onClick = {
|
|
||||||
openDialog.value = !openDialog.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openDialog.value) {
|
|
||||||
DirectoryProvider(
|
|
||||||
onDismiss = { openDialog.value = false },
|
|
||||||
onConfirm = {
|
|
||||||
val newProject = Project(projectId = vM.amountOfProjects, path = it)
|
|
||||||
vM.addProject(newProject)
|
|
||||||
navHostController.navigate(
|
|
||||||
WAppDestinations.MAIN_EDITOR
|
|
||||||
+ "/${newProject.projectId}/${
|
|
||||||
URLEncoder.encode(
|
|
||||||
newProject.path,
|
|
||||||
"UTF-8"
|
|
||||||
)
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A composable that shows a single project.
|
|
||||||
* @param[project] the project to show.
|
|
||||||
* @param[navHostController] the navigation host controller to navigate to the editor screen.
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
fun ProjectItem(
|
|
||||||
project: Project,
|
|
||||||
navHostController: NavHostController
|
|
||||||
) {
|
|
||||||
val showProjectConfirmation = remember { mutableStateOf(false) }
|
|
||||||
val name = project.path.split(File.separator).last()
|
|
||||||
|
|
||||||
var isClicked by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
Column {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.background(
|
|
||||||
color = if (isClicked) MaterialTheme.colorScheme.secondary
|
|
||||||
else MaterialTheme.colorScheme.primary
|
|
||||||
)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 15.dp, horizontal = 10.dp)
|
|
||||||
.pointerInput(Unit) {
|
|
||||||
detectTapGestures(
|
|
||||||
onTap = {
|
|
||||||
isClicked = true
|
|
||||||
},
|
|
||||||
onDoubleTap = {
|
|
||||||
isClicked = true
|
|
||||||
showProjectConfirmation.value = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
|
||||||
WText(text = name)
|
|
||||||
WText(text = project.path)
|
|
||||||
}
|
|
||||||
HorizontalDivider()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showProjectConfirmation.value) {
|
|
||||||
PickProjectPopup(
|
|
||||||
name = name,
|
|
||||||
project = project,
|
|
||||||
onDismiss = { showProjectConfirmation.value = false },
|
|
||||||
navHostController = navHostController
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(isClicked) {
|
|
||||||
if (isClicked) {
|
|
||||||
delay(200L)
|
|
||||||
isClicked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A pop up asking for confirmation before opening a project.
|
|
||||||
* @param[name] the name of the project to be opened.
|
|
||||||
* @param[project] the project to be opened.
|
|
||||||
* @param[onDismiss] a function to be called when the pop up is to be closed.
|
|
||||||
* @param[navHostController] the navigation host controller used to navigate to the editor screen.
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
fun PickProjectPopup(
|
|
||||||
name: String,
|
|
||||||
project: Project,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
navHostController: NavHostController
|
|
||||||
) {
|
|
||||||
WPopup(
|
|
||||||
titleBar = {
|
|
||||||
TopPopUpBar(title = "Open \"$name\"", onDismiss = onDismiss)
|
|
||||||
},
|
|
||||||
width = 500.dp,
|
|
||||||
height = 250.dp,
|
|
||||||
onDismiss = onDismiss,
|
|
||||||
bottomBar = {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(10.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
WBorderButton(
|
|
||||||
text = "Cancel",
|
|
||||||
onClick = onDismiss
|
|
||||||
)
|
|
||||||
|
|
||||||
WButton(
|
|
||||||
text = "Continue",
|
|
||||||
onClick = {
|
|
||||||
onDismiss()
|
|
||||||
navHostController.navigate(
|
|
||||||
WAppDestinations.MAIN_EDITOR
|
|
||||||
+ "/${project.projectId}/${
|
|
||||||
URLEncoder.encode(
|
|
||||||
project.path,
|
|
||||||
"UTF-8"
|
|
||||||
)
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(it),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
WText(text = "Are you sure you want to open \"$name\"?")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View model to be used by ProjectPickerScreen that handles the UserSettings and buttons.
|
* View model to be used by ProjectPickerComponent that handles the UserSettings and buttons.
|
||||||
* @param[getRecentProjects] use case to get the recent projects.
|
* @param[getRecentProjects] use case to get the recent projects.
|
||||||
* @param[addRecentProject] use case to add a project to the recent projects.
|
* @param[addRecentProject] use case to add a project to the recent projects.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.9.0'
|
kotlin_version = '1.9.21'
|
||||||
compose_ui_version = '1.6.8'
|
compose_ui_version = '1.6.8'
|
||||||
}
|
}
|
||||||
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '8.6.0' apply false
|
id 'com.android.application' version '8.7.2' apply false
|
||||||
id 'com.android.library' version '8.6.0' apply false
|
id 'com.android.library' version '8.7.2' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
|
id 'org.jetbrains.kotlin.android' version '1.9.21' apply false
|
||||||
id 'com.google.dagger.hilt.android' version '2.49' apply false
|
id 'com.google.dagger.hilt.android' version '2.49' apply false
|
||||||
id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.21'
|
id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.21'
|
||||||
}
|
}
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
#Tue Jul 16 09:37:51 CEST 2024
|
#Tue Jul 16 09:37:51 CEST 2024
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
Loading…
Reference in a new issue