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

Home page transaction entry #198

Merged
merged 24 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
35 changes: 24 additions & 11 deletions ui/cryptomaterial/dropdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ func (d *DropDown) Selected() string {
return d.items[d.SelectedIndex()].Text
}

func (d *DropDown) ClearSelection() {
d.selectedIndex = -1
}

func (d *DropDown) SelectedIndex() int {
return d.selectedIndex
}
Expand Down Expand Up @@ -152,12 +156,18 @@ func (d *DropDown) layoutActiveIcon(gtx layout.Context, index int) D {
}

func (d *DropDown) layoutOption(gtx layout.Context, itemIndex int) D {
item := d.items[itemIndex]
radius := Radius(0)
clickable := item.clickable
if !d.isOpen {
radius = Radius(8)
clickable = d.clickable
var item DropDownItem
if itemIndex > -1 {
item = d.items[itemIndex]
}

radius := Radius(8)
clickable := d.clickable
if d.isOpen {
radius = Radius(0)
if item.clickable != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

item will be nil if itemIndex == -1 and this code will panic.

This method also uses item in some places below which will crash if item is nil. Previously, item cannot be nil and the code here was safe. Now it can be nil and could panic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

All Possible areas where items could panic was addressed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you basically saying that item cannot be nil if d.isOpen?
Because in line 159-162 above, we only give item a value if itemIndex > -1. So if itemIndex is -1, item will be nil.

And this point where you do if item.clickable != nil will panic. Unless d.isOpen is only true if itemIndex > -1.

Copy link
Collaborator

Choose a reason for hiding this comment

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

All Possible areas where items could panic was addressed.

I don't see where this is done. Point me to it.

clickable = item.clickable
}
itswisdomagain marked this conversation as resolved.
Show resolved Hide resolved
}

padding := values.MarginPadding10
Expand All @@ -184,7 +194,7 @@ func (d *DropDown) layoutOption(gtx layout.Context, itemIndex int) D {
}

dropdownItemWidth -= gtx.Dp(values.MarginPadding24) // account for the dropdown Icon
return item.Icon.Layout24dp(gtx)
return item.Icon.Layout20dp(gtx)
itswisdomagain marked this conversation as resolved.
Show resolved Hide resolved
}),
layout.Rigid(func(gtx C) D {
gtx.Constraints.Max.X = dropdownItemWidth - gtx.Dp(values.MarginPadding50) // give some space for the dropdown Icon
Expand All @@ -193,11 +203,14 @@ func (d *DropDown) layoutOption(gtx layout.Context, itemIndex int) D {
Right: unit.Dp(5),
Left: unit.Dp(5),
}.Layout(gtx, func(gtx C) D {
lbl := d.theme.Body2(item.Text)
if !d.isOpen && len(item.Text) > 14 {
lbl.Text = item.Text[:14] + "..."
txt := item.Text
if !d.isOpen && len(txt) > 14 {
txt = item.Text[:14] + "..."
} else if txt == "" {
txt = "Select a wallet"
Sirmorrison marked this conversation as resolved.
Show resolved Hide resolved
}
return lbl.Layout(gtx)

return d.theme.Body2(txt).Layout(gtx)
})
}),
layout.Rigid(func(gtx C) D {
Expand Down
2 changes: 1 addition & 1 deletion ui/cryptomaterial/segmented_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (sc *SegmentedControl) Layout(gtx C) D {
return LinearLayout{
Width: WrapContent,
Height: WrapContent,
Background: sc.theme.Color.Background,
Background: sc.theme.Color.Gray2,
itswisdomagain marked this conversation as resolved.
Show resolved Hide resolved
Border: Border{Radius: Radius(8)},
}.Layout(gtx,
layout.Rigid(func(gtx C) D {
Expand Down
27 changes: 26 additions & 1 deletion ui/cryptomaterial/theme.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import (
"gioui.org/text"
"gioui.org/unit"
"gioui.org/widget"

"gioui.org/widget/material"

"github.com/crypto-power/cryptopower/libwallet/utils"
"github.com/crypto-power/cryptopower/ui/values"

"golang.org/x/exp/shiny/materialdesign/icons"
)

Expand Down Expand Up @@ -307,3 +308,27 @@ func SwitchEditors(event *key.Event, editors ...*widget.Editor) {
}
}
}

func (t *Theme) AssetIcon(asset utils.AssetType) *Image {
var icon *Image
switch asset {
case utils.DCRWalletAsset:
icon = t.Icons.DCR
case utils.LTCWalletAsset:
icon = t.Icons.LTC
case utils.BTCWalletAsset:
icon = t.Icons.BTC
default:
icon = nil
}
return icon
}

func CentralizeWidget(gtx C, widget layout.Widget) D {
return LinearLayout{
Width: MatchParent,
Height: WrapContent,
Orientation: layout.Horizontal,
Direction: layout.Center,
}.Layout2(gtx, widget)
}
2 changes: 1 addition & 1 deletion ui/page/components/asset_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (ats *AssetTypeSelector) Layout(window app.WindowNavigator, gtx C) D {
}.Layout(gtx, ats.selectedAssetType.Icon.Layout24dp)
}),
layout.Rigid(func(gtx C) D {
txt := ats.Theme.Label(values.TextSize16, ats.hint)
txt := ats.Theme.Label(values.TextSize14, ats.hint)
itswisdomagain marked this conversation as resolved.
Show resolved Hide resolved
txt.Color = ats.Theme.Color.Gray7
if ats.selectedAssetType != nil {
txt = ats.Theme.Label(values.TextSize16, ats.selectedAssetType.Type.String())
Expand Down
44 changes: 22 additions & 22 deletions ui/page/components/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,12 @@ func TransactionTitleIcon(l *load.Load, wal sharedW.Asset, tx *sharedW.Transacti
return &txStatus
}

// transactionRow is a single transaction row on the transactions and overview page. It lays out a transaction's
// direction, balance, status. isTxPage determines if the transaction should be drawn using the transactions page layout.
func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, tx *sharedW.Transaction, isTxPage bool) layout.Dimensions {
// LayoutTransactionRow is a single transaction row on the transactions and overview
// page. It lays out a transaction's direction, balance, status. isHiddenTxAssetInfo
// determines if the transaction should display additional information about the tx
// such as the wallet the tx belong to etc. This is usefil on pages where
// the tx is displayed from multi wallets.
func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, tx *sharedW.Transaction, isHiddenTxAssetInfo bool) layout.Dimensions {
Sirmorrison marked this conversation as resolved.
Show resolved Hide resolved
gtx.Constraints.Min.X = gtx.Constraints.Max.X
if wal == nil {
return D{}
Expand All @@ -240,7 +243,7 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
walName := l.Theme.Label(values.TextSize12, wal.GetWalletName())

insetLeft := values.MarginPadding16
if !isTxPage {
if !isHiddenTxAssetInfo {
insetLeft = values.MarginPadding8
}

Expand Down Expand Up @@ -281,7 +284,7 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
}.Layout(gtx,
layout.Rigid(l.Theme.Label(values.TextSize18, txStatus.Title).Layout),
layout.Rigid(func(gtx C) D {
if isTxPage {
if isHiddenTxAssetInfo {
return D{}
}
return layout.E.Layout(gtx, func(gtx C) D {
Expand All @@ -298,7 +301,7 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
)
}),
layout.Rigid(func(gtx C) D {
if !isTxPage && tx.Type == txhelper.TxTypeRegular {
if !isHiddenTxAssetInfo && tx.Type == txhelper.TxTypeRegular {
return cryptomaterial.LinearLayout{
Width: cryptomaterial.WrapContent,
Height: cryptomaterial.WrapContent,
Expand All @@ -312,23 +315,23 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
}),
)
}

return cryptomaterial.LinearLayout{
Width: cryptomaterial.WrapContent,
Height: cryptomaterial.WrapContent,
Orientation: layout.Horizontal,
Alignment: layout.Middle,
Direction: layout.W,
}.Layout(gtx,
layout.Rigid(func(gtx C) D {
if isTxPage {
if isHiddenTxAssetInfo {
return D{}
}

if tx.Type == txhelper.TxTypeMixed {
return cryptomaterial.LinearLayout{
Width: cryptomaterial.WrapContent,
Height: cryptomaterial.WrapContent,
Orientation: layout.Horizontal,
Direction: layout.W,
Alignment: layout.Middle,
}.Layout(gtx,
layout.Rigid(func(gtx C) D {
Expand All @@ -350,16 +353,12 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
)
}

if isTxPage {
return D{}
}

walBalTxt := l.Theme.Label(values.TextSize12, amount)
walBalTxt.Color = l.Theme.Color.GrayText2
return walBalTxt.Layout(gtx)
Sirmorrison marked this conversation as resolved.
Show resolved Hide resolved
}),
layout.Rigid(func(gtx C) D {
if dcrAsset, ok := wal.(*dcr.Asset); ok && !isTxPage {
if dcrAsset, ok := wal.(*dcr.Asset); ok && !isHiddenTxAssetInfo {
if ok, _ := dcrAsset.TicketHasVotedOrRevoked(tx.Hash); ok {
return layout.Inset{
Left: values.MarginPadding4,
Expand All @@ -378,7 +377,7 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
ticketSpender, _ = dcrAsset.TicketSpender(tx.Hash)
}

if ticketSpender == nil || isTxPage {
if ticketSpender == nil || isHiddenTxAssetInfo {
return D{}
}
amnt := wal.ToAmount(ticketSpender.VoteReward).ToCoin()
Expand All @@ -394,7 +393,7 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
}),
layout.Flexed(1, func(gtx C) D {
txSize := values.TextSize16
if !isTxPage {
if !isHiddenTxAssetInfo {
txSize = values.TextSize12
}
status := l.Theme.Label(txSize, values.String(values.StrUnknown))
Expand All @@ -417,7 +416,7 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
return layout.Flex{Alignment: layout.Baseline}.Layout(gtx,
layout.Rigid(func(gtx C) D {
voteOrRevocationTx := tx.Type == txhelper.TxTypeVote || tx.Type == txhelper.TxTypeRevocation
if isTxPage && voteOrRevocationTx {
if isHiddenTxAssetInfo && voteOrRevocationTx {
title := values.String(values.StrRevoke)
if tx.Type == txhelper.TxTypeVote {
title = values.String(values.StrVote)
Expand Down Expand Up @@ -445,7 +444,7 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
return D{}
}),
layout.Rigid(func(gtx C) D {
if !isTxPage {
if !isHiddenTxAssetInfo {
return cryptomaterial.LinearLayout{
Width: cryptomaterial.WrapContent,
Height: cryptomaterial.WrapContent,
Expand Down Expand Up @@ -483,22 +482,23 @@ func LayoutTransactionRow(gtx layout.Context, l *load.Load, wal sharedW.Asset, t
return D{}
}),
layout.Rigid(func(gtx C) D {
if isTxPage {
if isHiddenTxAssetInfo {
return status.Layout(gtx)
}
return D{}
}),
layout.Rigid(func(gtx C) D {
isMixedOrRegular := tx.Type == txhelper.TxTypeMixed || tx.Type == txhelper.TxTypeRegular
if !isTxPage && !isMixedOrRegular {
if !isHiddenTxAssetInfo && !isMixedOrRegular {
return D{}
}
statusIcon := l.Theme.Icons.ConfirmIcon

if TxConfirmations(wal, tx) < wal.RequiredConfirmations() {
statusIcon = l.Theme.Icons.PendingIcon
}

if isTxPage {
if isHiddenTxAssetInfo {
return layout.Inset{
Left: values.MarginPadding15,
Top: values.MarginPadding5,
Expand Down Expand Up @@ -628,7 +628,7 @@ func TimeFormat(secs int, long bool) string {

// TxPageDropDownFields returns the fields for the required drop down with the
// transactions view page. Since maps access of items order is always random
// an array of keys is provided guarrantee the dropdown order will always be
// an array of keys is provided guarantee the dropdown order will always be
Sirmorrison marked this conversation as resolved.
Show resolved Hide resolved
// maintained.
func TxPageDropDownFields(wType libutils.AssetType, tabIndex int) (mapInfo map[string]int32, keysInfo []string) {
switch {
Expand Down
48 changes: 27 additions & 21 deletions ui/page/components/items_scroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,26 @@ func (s *Scroll[T]) FetchScrollData(isReverse bool, window app.WindowNavigator)
}
s.mu.Unlock()

s.fetchScrollData(isReverse, window)
// set isReset to true here since all the callers of FetchScrollData()
// needs the data to be refreashed and data reset.
// TODO: set isreverse to default false all the callers of this
// FetchScrollData() is not initiating a reverse scroll action.
s.fetchScrollData(isReverse, true, window)
}

// fetchScrollData fetchs the scroll data and manages data returned depending on
// on the up or downwards scrollbar movement. Unless the data fetched is less than
// the page, all the old data is replaced by the new fetched data making it
// easier and smoother to scroll on the UI. At the end of the function call
// a window reload is triggered.
func (s *Scroll[T]) fetchScrollData(isReverse bool, window app.WindowNavigator) {
func (s *Scroll[T]) fetchScrollData(isReverse, isReset bool, window app.WindowNavigator) {
s.mu.Lock()

if isReset {
// resets the values for use on the next iteration.
s.isReset()
}

if s.isLoadingItems || s.loadedAllItems || s.queryFunc == nil {
return
}
Expand All @@ -90,7 +99,7 @@ func (s *Scroll[T]) fetchScrollData(isReverse bool, window app.WindowNavigator)
} else {
s.list.Position.Offset = 1
s.list.Position.OffsetLast = s.scrollView*-1 + 1
if s.data != nil {
if s.data != nil && !isReset {
s.offset += s.pageSize
}
}
Expand All @@ -102,12 +111,13 @@ func (s *Scroll[T]) fetchScrollData(isReverse bool, window app.WindowNavigator)

s.mu.Unlock()

items, itemsLen, isReset, err := s.queryFunc(offset, tempSize*2)
// Check if enough list items exists to fill the next page. If they do only query
// enough items to fit the current page otherwise return all the queried items.
if itemsLen > int(tempSize) && itemsLen%int(tempSize) == 0 {
items, itemsLen, isReset, err = s.queryFunc(offset, tempSize)
}
// keep fetching data until the last item.
// TODO. for inifinte scroll will implement fetching data in advance while
// having enough data on the page for reverse scroll. No need for making
// 2 queries to determine if there is enough tx. This approach will also
// prevent the app from freezing when the last item on the list is reached.
// TODO: deprecate isReset in a follow up PR as it cuts across multliple files.
items, itemsLen, _, err := s.queryFunc(offset, tempSize)

s.mu.Lock()

Expand All @@ -120,20 +130,16 @@ func (s *Scroll[T]) fetchScrollData(isReverse bool, window app.WindowNavigator)
return
}

if itemsLen > int(tempSize) {
// Since this is the last page set of items, prevent further scroll down queries.
if itemsLen < int(tempSize) {
// we know whe are at the last item when the item returned is less than the
// the page size.
s.loadedAllItems = true
}

s.data = items
s.itemsCount = itemsLen
s.isLoadingItems = false
s.mu.Unlock()

if isReset {
// resets the values for use on the next iteration.
s.resetList()
}
}

// FetchedData returns the latest queried data.
Expand Down Expand Up @@ -163,9 +169,9 @@ func (s *Scroll[T]) List() *cryptomaterial.ListStyle {
return s.listStyle
}

func (s *Scroll[T]) resetList() {
s.mu.Lock()
defer s.mu.Unlock()
func (s *Scroll[T]) isReset() {
// s.mu.Lock()
// defer s.mu.Unlock()

s.offset = 0
s.loadedAllItems = false
Expand Down Expand Up @@ -231,7 +237,7 @@ func (s *Scroll[T]) OnScrollChangeListener(window app.WindowNavigator) {

s.mu.Unlock()

go s.fetchScrollData(false, window)
go s.fetchScrollData(false, false, window)
}

if isScrollingUp {
Expand All @@ -241,7 +247,7 @@ func (s *Scroll[T]) OnScrollChangeListener(window app.WindowNavigator) {

s.mu.Unlock()

go s.fetchScrollData(true, window)
go s.fetchScrollData(true, false, window)
}

if !isScrollingUp && !isScrollingDown {
Expand Down
Loading
Loading