Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp the "Market" page #41

Merged
merged 90 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
582ac6d
Modify the `EntitySubscription` to accept `stateAccessor` parameter.
Artem-Semenov-dev Jun 23, 2023
5bff148
Center the title of the `Dialog` component.
Artem-Semenov-dev Jun 23, 2023
9172856
Configure the `headlineSmall` parameter of the `MaterialTheme.typogra…
Artem-Semenov-dev Jun 23, 2023
0b4b660
Add a leading icon to the input field component.
Artem-Semenov-dev Jun 23, 2023
af02be1
Add subscription to the previous state of the `AvailableSharesMarket`…
Artem-Semenov-dev Jun 23, 2023
c7d10c6
Modify the `NumericInput` component to use the custom `Input` component.
Artem-Semenov-dev Jun 23, 2023
8975fca
Modify `MainItemContent` to show the price difference between shares.
Artem-Semenov-dev Jun 23, 2023
0d7409f
Implement `SearchField` component.
Artem-Semenov-dev Jun 23, 2023
200cb12
Rewrite the `Image` component to draw the image synchronously.
Artem-Semenov-dev Jun 23, 2023
7cf32c8
Extract the `ShareItem` component.
Artem-Semenov-dev Jun 23, 2023
9bee684
Modify the layout of the `ButtonSection` component on the `MarketPage`.
Artem-Semenov-dev Jun 23, 2023
912ba76
Modify the layout of the `PurchaseDialog` component.
Artem-Semenov-dev Jun 23, 2023
5fb683e
Implement the `ShareProfile` component.
Artem-Semenov-dev Jun 23, 2023
dd43aa7
Extract the `SharesList` component.
Artem-Semenov-dev Jun 23, 2023
a5d10c4
Modify the layout of the `MarketPage` component.
Artem-Semenov-dev Jun 23, 2023
bb6370d
Add green color to the `MaterialTheme.colorScheme`
Artem-Semenov-dev Jun 23, 2023
cc5a8d1
Extract the `Input` component to a separate file.
Artem-Semenov-dev Jun 23, 2023
dd48b53
Add parameters documentation for components in the `MarketPage`.
Artem-Semenov-dev Jun 23, 2023
d6297c4
Implement the empty state of the shares list on the `MarketPage`.
Artem-Semenov-dev Jun 23, 2023
ef48f0c
Fix EOF in the `Input`.
Artem-Semenov-dev Jun 23, 2023
22cfeb4
Add documentation for the new API of the `MarketPageModel`.
Artem-Semenov-dev Jun 23, 2023
3a34825
Implement the `PurchaseResultMessage` component.
Artem-Semenov-dev Jun 23, 2023
69550aa
Change the arrangement of components in the `MarketPage`.
Artem-Semenov-dev Jun 23, 2023
765b2c4
Remove an empty line from the `MarketPage`.
Artem-Semenov-dev Jun 23, 2023
05fee62
Change filtering by index with filtering by id in the `ShareList` com…
Artem-Semenov-dev Jun 26, 2023
b0dc961
Rename the `stateAccessor` callback in `EntitySubscription` to `befor…
Artem-Semenov-dev Jun 26, 2023
ad2f175
Add `contentPadding` parameter to the `Input` component.
Artem-Semenov-dev Jun 26, 2023
a15193d
Rename the `MainItemContent` component to `ShareItemContent`.
Artem-Semenov-dev Jun 26, 2023
a8d6aeb
Change RGB notation of green color to HEX in the `Theme`.
Artem-Semenov-dev Jun 26, 2023
5e34972
Extract the `ShareProfileTab` component from the `MarketPage` component.
Artem-Semenov-dev Jun 26, 2023
8c6c4ff
Rename the `beforeUpdate` callback to `previousStateAccessor` in the …
Artem-Semenov-dev Jun 26, 2023
c4dfaf4
Rewrite `PriceDifferenceCard` component.
Artem-Semenov-dev Jun 27, 2023
d8377bd
Divide the `Input` component onto smaller ones.
Artem-Semenov-dev Jun 27, 2023
30fdf85
Extract all extensions to a separate file.
Artem-Semenov-dev Jun 27, 2023
88a7432
Extract the `Popup` component to a separate file.
Artem-Semenov-dev Jun 27, 2023
ca3c059
Move `NumericInput` component to the `Input` file.
Artem-Semenov-dev Jun 27, 2023
2f88938
Extract common components to a separate file.
Artem-Semenov-dev Jun 27, 2023
ac1bad3
Implement `ModifierExtensions` object.
Artem-Semenov-dev Jun 27, 2023
2d44c6f
Configure the `Jacoco` lib version.
Artem-Semenov-dev Jun 28, 2023
5efbcd5
Extract the `Java` version to a `BuildSettings` file.
Artem-Semenov-dev Jun 28, 2023
38c5ec7
Add dependency on the gradle plugin for `Kotlin` in the `buildSrc` mo…
Artem-Semenov-dev Jun 28, 2023
97f6ac2
Implement custom 'kotlin-common' plugin.
Artem-Semenov-dev Jun 28, 2023
7d3e433
Use defined constant for `kotlin-gradle-plugin` version.
Artem-Semenov-dev Jun 28, 2023
ab2e0ed
Bump `Jacoco` version -> `0.8.10`
Artem-Semenov-dev Jun 28, 2023
ed98a84
Rename the `kotlin-common` plugin to `kotlin-settings`.
Artem-Semenov-dev Jun 28, 2023
b698c3c
Extract the `MarketPageModel` from the `MarketPage` file.
Artem-Semenov-dev Jun 29, 2023
a3182fa
Extract the `SharesListTab` component from the `MarketPage` to a sepa…
Artem-Semenov-dev Jun 29, 2023
5343bb4
Extract the `SharesListTab` component from the `MarketPage` to a sepa…
Artem-Semenov-dev Jun 29, 2023
1cfbbc3
Move `NumericField` component to a `PageComponents` file.
Artem-Semenov-dev Jun 29, 2023
9020546
Divide the `PageComponents` file into separate files.
Artem-Semenov-dev Jun 29, 2023
0b3ca2b
Update documentation for the `EmptyShareProfileTab` component.
Artem-Semenov-dev Jun 29, 2023
577c08c
Add gradle plugin for `Detekt` dependency to project.
Artem-Semenov-dev Jun 29, 2023
fe90cff
Divide extensions into a separate files.
Artem-Semenov-dev Jun 29, 2023
947dfe0
Extract `NumericInput` to a separate file.
Artem-Semenov-dev Jun 29, 2023
9f3562b
Extract `SearchField` to a separate file.
Artem-Semenov-dev Jun 29, 2023
f1ef868
Extract `PurchaseOperationModel` from the `MarketPageModel` class.
Artem-Semenov-dev Jun 29, 2023
fd1f70a
Adjust imports in the `SharesListTab`.
Artem-Semenov-dev Jun 29, 2023
5586081
Move the `PrimaryButton` component to the `component` package.
Artem-Semenov-dev Jun 29, 2023
fbd4cab
Add explicitly declaration of the Kotlin version.
Artem-Semenov-dev Jun 29, 2023
e87daf0
Configure the `Detekt` library.
Artem-Semenov-dev Jun 29, 2023
90ca44d
Merge branch 'market-page-ui' into kotlin-configuration
Artem-Semenov-dev Jun 29, 2023
5b61ccd
Remove the `extension` package.
Artem-Semenov-dev Jun 30, 2023
3de630e
Rename the custom `Scaffold` component to `ContainerWithPopup`.
Artem-Semenov-dev Jul 3, 2023
7ec500a
Create the specific package for the Share-related components.
Artem-Semenov-dev Jul 3, 2023
94d3d49
Configure the `Detekt` lib for the `client` module.
Artem-Semenov-dev Jul 3, 2023
6ecb1c5
Move `asUsd` and `validateMoney` extensions to the `MoneyExts` file.
Artem-Semenov-dev Jul 3, 2023
2fa44ea
Merge branch 'market-page-ui' into kotlin-configuration
Artem-Semenov-dev Jul 3, 2023
5d0e3ec
Replace wildcard imports with imports using fully qualified class names.
Artem-Semenov-dev Jul 4, 2023
ed8b532
Format lines that contain more than 100 symbols.
Artem-Semenov-dev Jul 4, 2023
fe8f1f0
Remove object destruction in the `Popup` component.
Artem-Semenov-dev Jul 4, 2023
35b0bce
Rename the `currentPage` variable to `current` in the `CurrentPage` o…
Artem-Semenov-dev Jul 4, 2023
cc0cc3b
Add parameter to define color for the `Modifier.bottomBorder` extension.
Artem-Semenov-dev Jul 4, 2023
904b1b5
Suppress the `EmptyFunctionBlock` `Detekt` rule for the pages that ar…
Artem-Semenov-dev Jul 4, 2023
7639c08
Make the `Main` class an object.
Artem-Semenov-dev Jul 4, 2023
3ff6f73
Format the line that contains more than 100 symbols in the `PurchaseD…
Artem-Semenov-dev Jul 4, 2023
c739f69
Remove all redundant private APIs from the `DesktopClient` class.
Artem-Semenov-dev Jul 4, 2023
67f2704
Extract the `PurchaseResultMessageModel` from the `PurchaseOperationM…
Artem-Semenov-dev Jul 4, 2023
6bcf2b6
Rename the `Menu` component to `Navigation`.
Artem-Semenov-dev Jul 4, 2023
f77dca6
Suppress the "MemberNameEqualsClassName" `Detekt` rule for the `main`…
Artem-Semenov-dev Jul 4, 2023
ce993ad
Divide the `WalletPageModel` on parts.
Artem-Semenov-dev Jul 4, 2023
9a7d0a1
Adjust the `Kotlin` version in the `buildSrc` module.
Artem-Semenov-dev Jul 4, 2023
a380c6e
Get rid of the hardcoded "$" symbol for `asReadableString` `Money` ex…
Artem-Semenov-dev Jul 5, 2023
d247eee
Revert "Get rid of the hardcoded "$" symbol for `asReadableString` `M…
Artem-Semenov-dev Jul 5, 2023
75309be
Get rid of the hardcoded "$" symbol for `asReadableString` `Money` ex…
Artem-Semenov-dev Jul 5, 2023
67237d5
Merge branch 'market-page-ui' into kotlin-configuration
Artem-Semenov-dev Jul 5, 2023
f09e5d4
Merge `detekt-config.yml` and `detekt-config-compose.yml` to one file.
Artem-Semenov-dev Jul 5, 2023
b94bcbe
Remove redundant check for 'currency' option existence in the `Curren…
Artem-Semenov-dev Jul 5, 2023
a860adc
Remove sequence call in `Currency.symbol` extension.
Artem-Semenov-dev Jul 5, 2023
0cb94de
Change the signature of the `CurrencyDescriptor.findValueOf` method t…
Artem-Semenov-dev Jul 5, 2023
8447757
Merge pull request #42 from spine-examples/kotlin-configuration
Artem-Semenov-dev Jul 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -293,18 +293,22 @@ public class DesktopClient private constructor(
* @param entityType type of the entity on which changes subscription works
* @param client client with the help of which the entity will be subscribed
* @param id entity ID by which arrived entities will be filtered
* @param stateAccessor the callback function that provides access to the state of the entity
* before the updated one has arrived
*/
public class EntitySubscription<S : EntityState> internal constructor(
entityType: Class<S>,
client: DesktopClient,
id: Message
id: Message,
stateAccessor: (S?) -> Unit = {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to rename stateAccessor to beforeObserver (as in subscribeToEntity) or beforeUpdate because it will be called every time before the state is updated with the previous state.

) {
private var state: MutableStateFlow<S?>

init {
val entity = client.readEntity(entityType, id)
state = MutableStateFlow(entity)
client.subscribeToEntity(entityType, id) { value ->
stateAccessor(state.value)
state.value = value
}
}
Expand Down
131 changes: 131 additions & 0 deletions client/src/main/kotlin/io/spine/examples/shareaware/client/Input.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright 2023, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.examples.shareaware.client

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import io.spine.examples.shareaware.client.payment.Tooltip

/**
* The input component that supports displaying a tip.
*
* @param value the input text to be shown in the text field
* @param onChange the callback that is triggered when the input's value change

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param onChange the callback that is triggered when the input's value change
* @param onChange the callback that is triggered when the input's value changes

* @param placeholder the label to be displayed inside the input container
* @param isError indicates if the input's current value is in error
* @param tipMessage message to be displayed in the tooltip
* @param containerColor the color used for the background of this input
* @param leadingIcon the optional leading icon to be displayed at the beginning of the input field container
*/
@Composable
public fun Input(
value: String,
onChange: (String) -> Unit,
placeholder: String,
isError: Boolean,
tipMessage: String = "",
containerColor: Color = MaterialTheme.colorScheme.tertiary,
leadingIcon: @Composable (() -> Unit)? = null
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The body of this function is too long. Please extract some meaningful bits into components (preferably) or functions.

val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
val borderColor = if (isFocused) MaterialTheme.colorScheme.primary else Color.Unspecified
val toolTipIconColor = if (isError) MaterialTheme.colorScheme.error else
MaterialTheme.colorScheme.onSecondary
BasicTextField(
value = value,
onValueChange = onChange,
textStyle = MaterialTheme.typography.bodySmall,
interactionSource = interactionSource,
maxLines = 1
) { innerTextField ->
Row(
modifier = Modifier
.fillMaxWidth()
.border(
width = 2.dp,
color = borderColor,
shape = MaterialTheme.shapes.small
)
.background(
color = containerColor,
shape = MaterialTheme.shapes.small
)
.padding(
start = if (leadingIcon == null) 16.dp else 5.dp,
end = 16.dp,
top = if (leadingIcon == null) 8.dp else 2.dp,
bottom = if (leadingIcon == null) 8.dp else 2.dp,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's weird if leadingIcon is a @Composable function with no preset size, but the padding in this component depends on it existing with a specific size.

),
verticalAlignment = Alignment.CenterVertically,
) {
if (leadingIcon != null) {
leadingIcon()
}
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
contentAlignment = Alignment.CenterStart,
) {
if (value.isEmpty()) {
Text(
text = placeholder,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSecondary
)
}
innerTextField()
}
if (tipMessage != "") {
Tooltip(
tip = tipMessage,
modifier = Modifier.align(Alignment.CenterVertically),
iconColor = toolTipIconColor,
offset = DpOffset(130.dp, 0.dp)
)
}
}
}
}
Loading