mirror of
https://github.com/JetBrains/intellij-platform-plugin-template.git
synced 2025-12-05 06:11:52 +00:00
Add a context menu for location items and add remove location functionality
This commit is contained in:
parent
443883d7e4
commit
ae6d343913
@ -0,0 +1,60 @@
|
|||||||
|
package org.jetbrains.plugins.template.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.onClick
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.PopupPositionProvider
|
||||||
|
import org.jetbrains.jewel.foundation.theme.JewelTheme
|
||||||
|
import org.jetbrains.jewel.ui.component.Icon
|
||||||
|
import org.jetbrains.jewel.ui.component.PopupContainer
|
||||||
|
import org.jetbrains.jewel.ui.component.Text
|
||||||
|
import org.jetbrains.jewel.ui.icon.IconKey
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ContextPopupMenu(
|
||||||
|
popupPositionProvider: PopupPositionProvider,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
PopupContainer(
|
||||||
|
popupPositionProvider = popupPositionProvider,
|
||||||
|
modifier = Modifier.wrapContentSize(),
|
||||||
|
onDismissRequest = { onDismissRequest() },
|
||||||
|
horizontalAlignment = Alignment.Start
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun ContextPopupMenuItem(
|
||||||
|
actionText: String,
|
||||||
|
actionIcon: IconKey,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.widthIn(min = 100.dp)
|
||||||
|
.padding(8.dp)
|
||||||
|
.onClick { onClick() },
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
actionIcon,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = actionText,
|
||||||
|
style = JewelTheme.defaultTextStyle
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,20 @@
|
|||||||
package org.jetbrains.plugins.template.weatherApp.ui
|
package org.jetbrains.plugins.template.weatherApp.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.pointer.PointerEventType
|
||||||
|
import androidx.compose.ui.input.pointer.isSecondaryPressed
|
||||||
|
import androidx.compose.ui.input.pointer.onPointerEvent
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.layout.positionInWindow
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.*
|
||||||
|
import androidx.compose.ui.window.PopupPositionProvider
|
||||||
import org.jetbrains.jewel.foundation.lazy.SelectableLazyColumn
|
import org.jetbrains.jewel.foundation.lazy.SelectableLazyColumn
|
||||||
import org.jetbrains.jewel.foundation.lazy.SelectionMode
|
import org.jetbrains.jewel.foundation.lazy.SelectionMode
|
||||||
import org.jetbrains.jewel.foundation.lazy.itemsIndexed
|
import org.jetbrains.jewel.foundation.lazy.itemsIndexed
|
||||||
@ -18,8 +24,10 @@ import org.jetbrains.jewel.ui.component.*
|
|||||||
import org.jetbrains.jewel.ui.icon.IconKey
|
import org.jetbrains.jewel.ui.icon.IconKey
|
||||||
import org.jetbrains.jewel.ui.icons.AllIconsKeys
|
import org.jetbrains.jewel.ui.icons.AllIconsKeys
|
||||||
import org.jetbrains.plugins.template.ComposeTemplateBundle
|
import org.jetbrains.plugins.template.ComposeTemplateBundle
|
||||||
|
import org.jetbrains.plugins.template.components.ContextPopupMenu
|
||||||
|
import org.jetbrains.plugins.template.components.ContextPopupMenuItem
|
||||||
import org.jetbrains.plugins.template.weatherApp.model.Location
|
import org.jetbrains.plugins.template.weatherApp.model.Location
|
||||||
import org.jetbrains.plugins.template.weatherApp.services.*
|
import org.jetbrains.plugins.template.weatherApp.services.SearchAutoCompletionItemProvider
|
||||||
import org.jetbrains.plugins.template.weatherApp.ui.components.SearchToolbarMenu
|
import org.jetbrains.plugins.template.weatherApp.ui.components.SearchToolbarMenu
|
||||||
import org.jetbrains.plugins.template.weatherApp.ui.components.WeatherDetailsCard
|
import org.jetbrains.plugins.template.weatherApp.ui.components.WeatherDetailsCard
|
||||||
|
|
||||||
@ -119,6 +127,7 @@ private fun EmptyListPlaceholder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun MyLocationList(
|
private fun MyLocationList(
|
||||||
myLocationsUIState: LocationsUIState,
|
myLocationsUIState: LocationsUIState,
|
||||||
@ -158,9 +167,66 @@ private fun MyLocationList(
|
|||||||
itemsIndexed(
|
itemsIndexed(
|
||||||
items = myLocationsUIState.locations,
|
items = myLocationsUIState.locations,
|
||||||
key = { _, item -> item.label },
|
key = { _, item -> item.label },
|
||||||
) { index, item ->
|
) { index, locationItem ->
|
||||||
|
|
||||||
SimpleListItem(text = item.label, isSelected = myLocationsUIState.selectedIndex == index, isActive = isActive)
|
Box(Modifier.wrapContentSize()) {
|
||||||
|
val showPopup = remember { mutableStateOf(false) }
|
||||||
|
val popupPosition = remember { mutableStateOf(IntOffset.Zero) }
|
||||||
|
val itemPosition = remember { mutableStateOf(Offset.Zero) }
|
||||||
|
|
||||||
|
SimpleListItem(
|
||||||
|
text = locationItem.label,
|
||||||
|
isSelected = myLocationsUIState.selectedIndex == index,
|
||||||
|
isActive = isActive,
|
||||||
|
modifier = Modifier
|
||||||
|
.onGloballyPositioned { coordinates ->
|
||||||
|
itemPosition.value = coordinates.positionInWindow()
|
||||||
|
}
|
||||||
|
.onPointerEvent(PointerEventType.Press) { pointerEvent ->
|
||||||
|
if (!pointerEvent.buttons.isSecondaryPressed) return@onPointerEvent
|
||||||
|
|
||||||
|
// Calculate exact click position
|
||||||
|
val clickOffset = pointerEvent.changes.first().position
|
||||||
|
popupPosition.value = IntOffset(
|
||||||
|
x = (itemPosition.value.x + clickOffset.x).toInt(),
|
||||||
|
y = (itemPosition.value.y + clickOffset.y).toInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
showPopup.value = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (showPopup.value) {
|
||||||
|
val popupPositionProvider = remember(popupPosition.value) {
|
||||||
|
object : PopupPositionProvider {
|
||||||
|
override fun calculatePosition(
|
||||||
|
anchorBounds: IntRect,
|
||||||
|
windowSize: IntSize,
|
||||||
|
layoutDirection: LayoutDirection,
|
||||||
|
popupContentSize: IntSize
|
||||||
|
): IntOffset = popupPosition.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextPopupMenu(
|
||||||
|
popupPositionProvider,
|
||||||
|
onDismissRequest = {
|
||||||
|
showPopup.value = false
|
||||||
|
popupPosition.value = IntOffset.Zero
|
||||||
|
itemPosition.value = Offset.Zero
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
ContextPopupMenuItem(
|
||||||
|
ComposeTemplateBundle.getMessage("weather.app.context.menu.delete.option"),
|
||||||
|
AllIconsKeys.General.Delete
|
||||||
|
) {
|
||||||
|
showPopup.value = false
|
||||||
|
|
||||||
|
myLocationsViewModelApi.onDeleteLocation(locationItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,4 +9,6 @@ weather.app.search.toolbar.menu.add.button.text=Add
|
|||||||
weather.app.search.toolbar.menu.add.button.content.description=Add a place to a watch list.
|
weather.app.search.toolbar.menu.add.button.content.description=Add a place to a watch list.
|
||||||
weather.app.7days.forecast.title.text=7-day Forecast
|
weather.app.7days.forecast.title.text=7-day Forecast
|
||||||
|
|
||||||
|
weather.app.context.menu.delete.option=Delete
|
||||||
|
|
||||||
weather.app.clear.button.content.description=Clear
|
weather.app.clear.button.content.description=Clear
|
||||||
Loading…
Reference in New Issue
Block a user