diff --git a/go/chat/server.go b/go/chat/server.go index fa103eb22f06..ea0fbfaa0f18 100644 --- a/go/chat/server.go +++ b/go/chat/server.go @@ -175,6 +175,20 @@ func (h *Server) RequestInboxUnbox(ctx context.Context, convIDs []chat1.Conversa return nil } +func (h *Server) RequestInboxSmallIncrease(ctx context.Context) (err error) { + ctx = globals.ChatCtx(ctx, h.G(), keybase1.TLFIdentifyBehavior_CHAT_GUI, nil, nil) + defer h.Trace(ctx, func() error { return err }, "RequestInboxSmallIncrease")() + h.G().UIInboxLoader.UpdateLayoutFromSmallIncrease(ctx) + return nil +} + +func (h *Server) RequestInboxSmallReset(ctx context.Context) (err error) { + ctx = globals.ChatCtx(ctx, h.G(), keybase1.TLFIdentifyBehavior_CHAT_GUI, nil, nil) + defer h.Trace(ctx, func() error { return err }, "RequestInboxSmallReset")() + h.G().UIInboxLoader.UpdateLayoutFromSmallReset(ctx) + return nil +} + func (h *Server) GetInboxNonblockLocal(ctx context.Context, arg chat1.GetInboxNonblockLocalArg) (res chat1.NonblockFetchRes, err error) { var breaks []keybase1.TLFIdentifyFailure ctx = globals.ChatCtx(ctx, h.G(), arg.IdentifyBehavior, &breaks, h.identNotifier) diff --git a/go/chat/types/interfaces.go b/go/chat/types/interfaces.go index 9705d756fdeb..13cf31e50faa 100644 --- a/go/chat/types/interfaces.go +++ b/go/chat/types/interfaces.go @@ -565,6 +565,8 @@ type UIInboxLoader interface { UpdateLayout(ctx context.Context, reselectMode chat1.InboxLayoutReselectMode, reason string) UpdateLayoutFromNewMessage(ctx context.Context, conv RemoteConversation) UpdateLayoutFromSubteamRename(ctx context.Context, convs []RemoteConversation) + UpdateLayoutFromSmallIncrease(ctx context.Context) + UpdateLayoutFromSmallReset(ctx context.Context) UpdateConvs(ctx context.Context, convIDs []chat1.ConversationID) error LoadNonblock(ctx context.Context, query *chat1.GetInboxLocalQuery, maxUnbox *int, skipUnverified bool) error } diff --git a/go/chat/types/types.go b/go/chat/types/types.go index f5da4bfd146a..849a887c8377 100644 --- a/go/chat/types/types.go +++ b/go/chat/types/types.go @@ -647,6 +647,9 @@ func (d DummyUIInboxLoader) UpdateLayoutFromNewMessage(ctx context.Context, conv func (d DummyUIInboxLoader) UpdateLayoutFromSubteamRename(ctx context.Context, convs []RemoteConversation) { } +func (d DummyUIInboxLoader) UpdateLayoutFromSmallIncrease(ctx context.Context) {} +func (d DummyUIInboxLoader) UpdateLayoutFromSmallReset(ctx context.Context) {} + type DummyAttachmentUploader struct{} var _ AttachmentUploader = (*DummyAttachmentUploader)(nil) diff --git a/go/chat/uiinboxloader.go b/go/chat/uiinboxloader.go index b3e2c9e26ce3..aebebdfdf098 100644 --- a/go/chat/uiinboxloader.go +++ b/go/chat/uiinboxloader.go @@ -31,14 +31,16 @@ type UIInboxLoader struct { started bool eg errgroup.Group - clock clockwork.Clock - transmitCh chan interface{} - layoutCh chan chat1.InboxLayoutReselectMode - bigTeamUnboxCh chan []chat1.ConversationID - convTransmitBatch map[string]chat1.ConversationLocal - batchDelay time.Duration - lastBatchFlush time.Time - lastLayoutFlush time.Time + clock clockwork.Clock + transmitCh chan interface{} + layoutCh chan chat1.InboxLayoutReselectMode + bigTeamUnboxCh chan []chat1.ConversationID + convTransmitBatch map[string]chat1.ConversationLocal + batchDelay time.Duration + lastBatchFlush time.Time + lastLayoutFlush time.Time + smallTeamBound int + defaultSmallTeamBound int // layout tracking lastLayoutMu sync.Mutex @@ -49,12 +51,18 @@ type UIInboxLoader struct { } func NewUIInboxLoader(g *globals.Context) *UIInboxLoader { + defaultSmallTeamBound := 100 + if g.IsMobileAppType() { + defaultSmallTeamBound = 50 + } return &UIInboxLoader{ - Contextified: globals.NewContextified(g), - DebugLabeler: utils.NewDebugLabeler(g.GetLog(), "UIInboxLoader", false), - convTransmitBatch: make(map[string]chat1.ConversationLocal), - clock: clockwork.NewRealClock(), - batchDelay: 200 * time.Millisecond, + Contextified: globals.NewContextified(g), + DebugLabeler: utils.NewDebugLabeler(g.GetLog(), "UIInboxLoader", false), + convTransmitBatch: make(map[string]chat1.ConversationLocal), + clock: clockwork.NewRealClock(), + batchDelay: 200 * time.Millisecond, + smallTeamBound: defaultSmallTeamBound, + defaultSmallTeamBound: defaultSmallTeamBound, } } @@ -469,6 +477,10 @@ func (h *UIInboxLoader) buildLayout(ctx context.Context, inbox types.Inbox, return res.SmallTeams[i].Time.After(res.SmallTeams[j].Time) }) res.BigTeams = btcollector.finalize(ctx) + res.TotalSmallTeams = len(res.SmallTeams) + if res.TotalSmallTeams > h.smallTeamBound { + res.SmallTeams = res.SmallTeams[:h.smallTeamBound] + } if !selectedInLayout || reselectMode == chat1.InboxLayoutReselectMode_FORCE { // select a new conv for the UI var reselect chat1.UIInboxReselectInfo @@ -667,3 +679,15 @@ func (h *UIInboxLoader) UpdateConvs(ctx context.Context, convIDs []chat1.Convers } return h.LoadNonblock(ctx, &query, nil, true) } + +func (h *UIInboxLoader) UpdateLayoutFromSmallIncrease(ctx context.Context) { + defer h.Trace(ctx, func() error { return nil }, "UpdateLayoutFromSmallIncrease")() + h.smallTeamBound += h.defaultSmallTeamBound + h.UpdateLayout(ctx, chat1.InboxLayoutReselectMode_DEFAULT, "small increase") +} + +func (h *UIInboxLoader) UpdateLayoutFromSmallReset(ctx context.Context) { + defer h.Trace(ctx, func() error { return nil }, "UpdateLayoutFromSmallReset")() + h.smallTeamBound = h.defaultSmallTeamBound + h.UpdateLayout(ctx, chat1.InboxLayoutReselectMode_DEFAULT, "small reset") +} diff --git a/go/protocol/chat1/chat_ui.go b/go/protocol/chat1/chat_ui.go index b20933576b4a..3487934e22b1 100644 --- a/go/protocol/chat1/chat_ui.go +++ b/go/protocol/chat1/chat_ui.go @@ -223,14 +223,16 @@ func (o UIInboxReselectInfo) DeepCopy() UIInboxReselectInfo { } type UIInboxLayout struct { - SmallTeams []UIInboxSmallTeamRow `codec:"smallTeams" json:"smallTeams"` - BigTeams []UIInboxBigTeamRow `codec:"bigTeams" json:"bigTeams"` - ReselectInfo *UIInboxReselectInfo `codec:"reselectInfo,omitempty" json:"reselectInfo,omitempty"` - WidgetList []UIInboxSmallTeamRow `codec:"widgetList" json:"widgetList"` + TotalSmallTeams int `codec:"totalSmallTeams" json:"totalSmallTeams"` + SmallTeams []UIInboxSmallTeamRow `codec:"smallTeams" json:"smallTeams"` + BigTeams []UIInboxBigTeamRow `codec:"bigTeams" json:"bigTeams"` + ReselectInfo *UIInboxReselectInfo `codec:"reselectInfo,omitempty" json:"reselectInfo,omitempty"` + WidgetList []UIInboxSmallTeamRow `codec:"widgetList" json:"widgetList"` } func (o UIInboxLayout) DeepCopy() UIInboxLayout { return UIInboxLayout{ + TotalSmallTeams: o.TotalSmallTeams, SmallTeams: (func(x []UIInboxSmallTeamRow) []UIInboxSmallTeamRow { if x == nil { return nil diff --git a/go/protocol/chat1/local.go b/go/protocol/chat1/local.go index 36d38af499f1..b3874c048636 100644 --- a/go/protocol/chat1/local.go +++ b/go/protocol/chat1/local.go @@ -5876,6 +5876,12 @@ type RequestInboxUnboxArg struct { ConvIDs []ConversationID `codec:"convIDs" json:"convIDs"` } +type RequestInboxSmallIncreaseArg struct { +} + +type RequestInboxSmallResetArg struct { +} + type GetInboxNonblockLocalArg struct { SessionID int `codec:"sessionID" json:"sessionID"` MaxUnbox *int `codec:"maxUnbox,omitempty" json:"maxUnbox,omitempty"` @@ -6388,6 +6394,8 @@ type LocalInterface interface { GetInboxAndUnboxUILocal(context.Context, GetInboxAndUnboxUILocalArg) (GetInboxAndUnboxUILocalRes, error) RequestInboxLayout(context.Context, InboxLayoutReselectMode) error RequestInboxUnbox(context.Context, []ConversationID) error + RequestInboxSmallIncrease(context.Context) error + RequestInboxSmallReset(context.Context) error GetInboxNonblockLocal(context.Context, GetInboxNonblockLocalArg) (NonblockFetchRes, error) PostLocal(context.Context, PostLocalArg) (PostLocalRes, error) GenerateOutboxID(context.Context) (OutboxID, error) @@ -6583,6 +6591,26 @@ func LocalProtocol(i LocalInterface) rpc.Protocol { return }, }, + "requestInboxSmallIncrease": { + MakeArg: func() interface{} { + var ret [1]RequestInboxSmallIncreaseArg + return &ret + }, + Handler: func(ctx context.Context, args interface{}) (ret interface{}, err error) { + err = i.RequestInboxSmallIncrease(ctx) + return + }, + }, + "requestInboxSmallReset": { + MakeArg: func() interface{} { + var ret [1]RequestInboxSmallResetArg + return &ret + }, + Handler: func(ctx context.Context, args interface{}) (ret interface{}, err error) { + err = i.RequestInboxSmallReset(ctx) + return + }, + }, "getInboxNonblockLocal": { MakeArg: func() interface{} { var ret [1]GetInboxNonblockLocalArg @@ -7848,6 +7876,16 @@ func (c LocalClient) RequestInboxUnbox(ctx context.Context, convIDs []Conversati return } +func (c LocalClient) RequestInboxSmallIncrease(ctx context.Context) (err error) { + err = c.Cli.Call(ctx, "chat.1.local.requestInboxSmallIncrease", []interface{}{RequestInboxSmallIncreaseArg{}}, nil, 0*time.Millisecond) + return +} + +func (c LocalClient) RequestInboxSmallReset(ctx context.Context) (err error) { + err = c.Cli.Call(ctx, "chat.1.local.requestInboxSmallReset", []interface{}{RequestInboxSmallResetArg{}}, nil, 0*time.Millisecond) + return +} + func (c LocalClient) GetInboxNonblockLocal(ctx context.Context, __arg GetInboxNonblockLocalArg) (res NonblockFetchRes, err error) { err = c.Cli.Call(ctx, "chat.1.local.getInboxNonblockLocal", []interface{}{__arg}, &res, 0*time.Millisecond) return diff --git a/protocol/avdl/chat1/chat_ui.avdl b/protocol/avdl/chat1/chat_ui.avdl index 54502cf3cbb1..a0f144ea7747 100644 --- a/protocol/avdl/chat1/chat_ui.avdl +++ b/protocol/avdl/chat1/chat_ui.avdl @@ -57,6 +57,7 @@ protocol chatUi { } record UIInboxLayout { + int totalSmallTeams; array smallTeams; array bigTeams; union { null, UIInboxReselectInfo } reselectInfo; diff --git a/protocol/avdl/chat1/local.avdl b/protocol/avdl/chat1/local.avdl index 1486bc9b766f..0b3127a3bc5d 100644 --- a/protocol/avdl/chat1/local.avdl +++ b/protocol/avdl/chat1/local.avdl @@ -797,6 +797,8 @@ protocol local { } void requestInboxLayout(InboxLayoutReselectMode reselectMode); void requestInboxUnbox(array convIDs); + void requestInboxSmallIncrease(); + void requestInboxSmallReset(); NonblockFetchRes getInboxNonblockLocal(int sessionID, union { null, int } maxUnbox, boolean skipUnverified, union { null, GetInboxLocalQuery} query, keybase1.TLFIdentifyBehavior identifyBehavior); PostLocalRes postLocal(int sessionID, ConversationID conversationID, MessagePlaintext msg, union { null, MessageID } replyTo, keybase1.TLFIdentifyBehavior identifyBehavior); diff --git a/protocol/bin/enabled-calls.json b/protocol/bin/enabled-calls.json index d30fb0dc9435..52250586b490 100644 --- a/protocol/bin/enabled-calls.json +++ b/protocol/bin/enabled-calls.json @@ -54,6 +54,8 @@ "chat.1.local.removeBotMember": {"promise": true}, "chat.1.local.resolveMaybeMention": {"promise": true}, "chat.1.local.requestInboxLayout": {"promise": true}, + "chat.1.local.requestInboxSmallIncrease": {"promise": true}, + "chat.1.local.requestInboxSmallReset": {"promise": true}, "chat.1.local.requestInboxUnbox": {"promise": true}, "chat.1.local.resolveUnfurlPrompt": {"promise": true}, "chat.1.local.saveUnfurlSettings": {"promise": true}, diff --git a/protocol/json/chat1/chat_ui.json b/protocol/json/chat1/chat_ui.json index b24dfc0ce403..0bea00092ef5 100644 --- a/protocol/json/chat1/chat_ui.json +++ b/protocol/json/chat1/chat_ui.json @@ -192,6 +192,10 @@ "type": "record", "name": "UIInboxLayout", "fields": [ + { + "type": "int", + "name": "totalSmallTeams" + }, { "type": { "type": "array", diff --git a/protocol/json/chat1/local.json b/protocol/json/chat1/local.json index 1cfb98c2b2b0..6353e642be4d 100644 --- a/protocol/json/chat1/local.json +++ b/protocol/json/chat1/local.json @@ -3796,6 +3796,14 @@ ], "response": null }, + "requestInboxSmallIncrease": { + "request": [], + "response": null + }, + "requestInboxSmallReset": { + "request": [], + "response": null + }, "getInboxNonblockLocal": { "request": [ { diff --git a/shared/actions/chat2-gen.tsx b/shared/actions/chat2-gen.tsx index e2ae2ff819f8..71bb4dfdc101 100644 --- a/shared/actions/chat2-gen.tsx +++ b/shared/actions/chat2-gen.tsx @@ -63,6 +63,7 @@ export const jumpToRecent = 'chat2:jumpToRecent' export const leaveConversation = 'chat2:leaveConversation' export const loadAttachmentView = 'chat2:loadAttachmentView' export const loadMessagesCentered = 'chat2:loadMessagesCentered' +export const loadMoreSmalls = 'chat2:loadMoreSmalls' export const loadNewerMessagesDueToScroll = 'chat2:loadNewerMessagesDueToScroll' export const loadNextBotPage = 'chat2:loadNextBotPage' export const loadOlderMessagesDueToScroll = 'chat2:loadOlderMessagesDueToScroll' @@ -111,6 +112,7 @@ export const replyJump = 'chat2:replyJump' export const requestInfoReceived = 'chat2:requestInfoReceived' export const resetChatWithoutThem = 'chat2:resetChatWithoutThem' export const resetLetThemIn = 'chat2:resetLetThemIn' +export const resetSmalls = 'chat2:resetSmalls' export const resolveMaybeMention = 'chat2:resolveMaybeMention' export const saveMinWriterRole = 'chat2:saveMinWriterRole' export const selectConversation = 'chat2:selectConversation' @@ -324,6 +326,7 @@ type _LoadMessagesCenteredPayload = { readonly messageID: Types.MessageID readonly highlightMode: Types.CenterOrdinalHighlightMode } +type _LoadMoreSmallsPayload = void type _LoadNewerMessagesDueToScrollPayload = {readonly conversationIDKey: Types.ConversationIDKey} type _LoadNextBotPagePayload = {readonly pageSize: number} type _LoadOlderMessagesDueToScrollPayload = {readonly conversationIDKey: Types.ConversationIDKey} @@ -533,6 +536,7 @@ type _RequestInfoReceivedPayload = { } type _ResetChatWithoutThemPayload = {readonly conversationIDKey: Types.ConversationIDKey} type _ResetLetThemInPayload = {readonly conversationIDKey: Types.ConversationIDKey; readonly username: string} +type _ResetSmallsPayload = void type _ResolveMaybeMentionPayload = {readonly name: string; readonly channel: string} type _SaveMinWriterRolePayload = { readonly conversationIDKey: Types.ConversationIDKey @@ -1094,6 +1098,20 @@ export const createStaticConfigLoaded = (payload: _StaticConfigLoadedPayload): S payload, type: staticConfigLoaded, }) +/** + * Tell the service to give us more small teams + */ +export const createLoadMoreSmalls = (payload: _LoadMoreSmallsPayload): LoadMoreSmallsPayload => ({ + payload, + type: loadMoreSmalls, +}) +/** + * Tell the service to revert to default number of small teams + */ +export const createResetSmalls = (payload: _ResetSmallsPayload): ResetSmallsPayload => ({ + payload, + type: resetSmalls, +}) /** * Tell the service to toggle a reaction on a message. */ @@ -1761,6 +1779,10 @@ export type LoadMessagesCenteredPayload = { readonly payload: _LoadMessagesCenteredPayload readonly type: typeof loadMessagesCentered } +export type LoadMoreSmallsPayload = { + readonly payload: _LoadMoreSmallsPayload + readonly type: typeof loadMoreSmalls +} export type LoadNewerMessagesDueToScrollPayload = { readonly payload: _LoadNewerMessagesDueToScrollPayload readonly type: typeof loadNewerMessagesDueToScroll @@ -1929,6 +1951,7 @@ export type ResetLetThemInPayload = { readonly payload: _ResetLetThemInPayload readonly type: typeof resetLetThemIn } +export type ResetSmallsPayload = {readonly payload: _ResetSmallsPayload; readonly type: typeof resetSmalls} export type ResolveMaybeMentionPayload = { readonly payload: _ResolveMaybeMentionPayload readonly type: typeof resolveMaybeMention @@ -2215,6 +2238,7 @@ export type Actions = | LeaveConversationPayload | LoadAttachmentViewPayload | LoadMessagesCenteredPayload + | LoadMoreSmallsPayload | LoadNewerMessagesDueToScrollPayload | LoadNextBotPagePayload | LoadOlderMessagesDueToScrollPayload @@ -2263,6 +2287,7 @@ export type Actions = | RequestInfoReceivedPayload | ResetChatWithoutThemPayload | ResetLetThemInPayload + | ResetSmallsPayload | ResolveMaybeMentionPayload | SaveMinWriterRolePayload | SelectConversationPayload diff --git a/shared/actions/chat2/index.tsx b/shared/actions/chat2/index.tsx index 40007906dfe5..ea40439ef1f1 100644 --- a/shared/actions/chat2/index.tsx +++ b/shared/actions/chat2/index.tsx @@ -102,6 +102,22 @@ const inboxRefresh = ( return actions } +const inboxLoadMoreSmalls = async () => { + try { + await RPCChatTypes.localRequestInboxSmallIncreaseRpcPromise() + } catch (err) { + logger.info(`inboxLoadMoreSmalls: failed to increase smalls: ${err.message}`) + } +} + +const inboxResetSmalls = async () => { + try { + await RPCChatTypes.localRequestInboxSmallResetRpcPromise() + } catch (err) { + logger.info(`inboxResetSmalls: failed to reset smalls: ${err.message}`) + } +} + // Only get the untrusted conversations out const untrustedConversationIDKeys = (state: Container.TypedState, ids: Array) => ids.filter(id => (state.chat2.metaMap.get(id) ?? {trustedState: 'untrusted'}).trustedState === 'untrusted') @@ -3463,6 +3479,8 @@ function* chat2Saga() { // Refresh the inbox yield* Saga.chainAction2([Chat2Gen.inboxRefresh, EngineGen.chat1NotifyChatChatInboxStale], inboxRefresh) yield* Saga.chainAction2([Chat2Gen.selectConversation, Chat2Gen.metasReceived], ensureSelectedTeamLoaded) + yield* Saga.chainAction(Chat2Gen.loadMoreSmalls, inboxLoadMoreSmalls) + yield* Saga.chainAction(Chat2Gen.resetSmalls, inboxResetSmalls) // We've scrolled some new inbox rows into view, queue them up yield* Saga.chainAction2(Chat2Gen.metaNeedsUpdating, queueMetaToRequest) // We have some items in the queue to process diff --git a/shared/actions/json/chat2.json b/shared/actions/json/chat2.json index 4ab63242ee9c..a53bf5c0661f 100644 --- a/shared/actions/json/chat2.json +++ b/shared/actions/json/chat2.json @@ -861,6 +861,12 @@ "username": "string", "allowCommands": "boolean", "allowMentions": "boolean" + }, + "loadMoreSmalls": { + "_description": "Tell the service to give us more small teams" + }, + "resetSmalls": { + "_description": "Tell the service to revert to default number of small teams" } } } diff --git a/shared/actions/typed-actions-gen.tsx b/shared/actions/typed-actions-gen.tsx index 40fc062908d6..93a6991f8ce3 100644 --- a/shared/actions/typed-actions-gen.tsx +++ b/shared/actions/typed-actions-gen.tsx @@ -239,6 +239,8 @@ export type TypedActionsMap = { 'chat2:setBotSettings': chat2.SetBotSettingsPayload 'chat2:removeBotMember': chat2.RemoveBotMemberPayload 'chat2:editBotSettings': chat2.EditBotSettingsPayload + 'chat2:loadMoreSmalls': chat2.LoadMoreSmallsPayload + 'chat2:resetSmalls': chat2.ResetSmallsPayload 'config:startHandshake': config.StartHandshakePayload 'config:restartHandshake': config.RestartHandshakePayload 'config:daemonHandshake': config.DaemonHandshakePayload diff --git a/shared/chat/inbox/container/index.tsx b/shared/chat/inbox/container/index.tsx index af9a35f2a5d1..7ce60ecf1e42 100644 --- a/shared/chat/inbox/container/index.tsx +++ b/shared/chat/inbox/container/index.tsx @@ -175,15 +175,24 @@ const Connected = Container.namedConnect( let smallRows = makeSmallRows(smallTeams) let bigRows = makeBigRows(bigTeams) const teamBuilder: RowItemTeamBuilder = {type: 'teamBuilder'} + + const hasAllSmallTeamConvs = + (stateProps._inboxLayout?.smallTeams?.length ?? 0) === (stateProps._inboxLayout?.totalSmallTeams ?? 0) + const divider: Array = + bigRows.length !== 0 || !hasAllSmallTeamConvs + ? [{showButton: !hasAllSmallTeamConvs || smallTeamsBelowTheFold, type: 'divider'}] + : [] if (smallRows.length !== 0) { if (bigRows.length === 0) { - smallRows.push(teamBuilder) + if (divider.length !== 0) { + divider.push(teamBuilder) + } else { + smallRows.push(teamBuilder) + } } else { bigRows.push(teamBuilder) } } - const divider: Array = - bigRows.length !== 0 ? [{showButton: smallTeamsBelowTheFold, type: 'divider'}] : [] const rows: Array = [...smallRows, ...divider, ...bigRows] const unreadIndices: Array = [] @@ -220,7 +229,7 @@ const Connected = Container.namedConnect( onUntrustedInboxVisible: dispatchProps.onUntrustedInboxVisible, rows, setInboxNumSmallRows: dispatchProps.setInboxNumSmallRows, - smallTeamsExpanded: stateProps.smallTeamsExpanded, + smallTeamsExpanded: stateProps.smallTeamsExpanded || bigTeams.length === 0, toggleSmallTeamsExpanded: dispatchProps.toggleSmallTeamsExpanded, unreadIndices, } diff --git a/shared/chat/inbox/index.desktop.tsx b/shared/chat/inbox/index.desktop.tsx index cedc8bf999a1..7731b1dab6aa 100644 --- a/shared/chat/inbox/index.desktop.tsx +++ b/shared/chat/inbox/index.desktop.tsx @@ -134,7 +134,7 @@ class Inbox extends React.Component { } return (
- {row.showButton && ( + {row.showButton && !this.props.smallTeamsExpanded && ( <> { toggle={this.props.toggleSmallTeamsExpanded} showButton={row.showButton} rows={this.props.rows} + smallTeamsExpanded={this.props.smallTeamsExpanded} />
) diff --git a/shared/chat/inbox/index.native.tsx b/shared/chat/inbox/index.native.tsx index 5b8dd51a12f1..0d43d351bd58 100644 --- a/shared/chat/inbox/index.native.tsx +++ b/shared/chat/inbox/index.native.tsx @@ -67,6 +67,7 @@ class Inbox extends React.PureComponent { showButton={row.showButton} toggle={this.props.toggleSmallTeamsExpanded} rows={this.props.rows} + smallTeamsExpanded={this.props.smallTeamsExpanded} /> ) } else if (row.type === 'teamBuilder') { diff --git a/shared/chat/inbox/row/big-teams-divider/container.tsx b/shared/chat/inbox/row/big-teams-divider/container.tsx index 2d66fe06b140..f44e62a3d498 100644 --- a/shared/chat/inbox/row/big-teams-divider/container.tsx +++ b/shared/chat/inbox/row/big-teams-divider/container.tsx @@ -3,6 +3,7 @@ import * as Container from '../../../../util/container' import * as Types from '../../../../constants/types/chat2' import * as RPCChatTypes from '../../../../constants/types/rpc-chat-gen' import {memoize} from '../../../../util/memoize' +import * as Chat2Gen from '../../../../actions/chat2-gen' type OwnProps = { toggle: () => void @@ -26,9 +27,14 @@ export default Container.connect( state => ({ badgeCount: getBadgeCount(state.chat2.inboxLayout, state.chat2.badgeMap), }), - () => ({}), - (stateProps, _, ownProps: OwnProps) => ({ + (dispatch, ownProps: OwnProps) => ({ + toggle: () => { + dispatch(Chat2Gen.createResetSmalls()) + ownProps.toggle() + }, + }), + (stateProps, dispatchProps) => ({ badgeCount: stateProps.badgeCount, - toggle: ownProps.toggle, + toggle: dispatchProps.toggle, }) )(BigTeamsDivider) diff --git a/shared/chat/inbox/row/teams-divider/container.tsx b/shared/chat/inbox/row/teams-divider/container.tsx index f929066fe69f..6519a328de5f 100644 --- a/shared/chat/inbox/row/teams-divider/container.tsx +++ b/shared/chat/inbox/row/teams-divider/container.tsx @@ -5,9 +5,11 @@ import {RowItem} from '../..' import {memoize} from '../../../../util/memoize' import * as RPCChatTypes from '../../../../constants/types/rpc-chat-gen' import * as Types from '../../../../constants/types/chat2' +import * as Chat2Gen from '../../../../actions/chat2-gen' type OwnProps = { hiddenCountDelta: number + smallTeamsExpanded: boolean rows: Array showButton: boolean toggle: () => void @@ -22,16 +24,14 @@ const mapStateToProps = (state: TypedState) => ({ const getMetaCounts = memoize( (badges: Types.ConversationCountMap, inboxLayout: RPCChatTypes.UIInboxLayout | null) => { let badgeCount = 0 - let hiddenCount = 0 const smallTeams = inboxLayout ? inboxLayout.smallTeams || [] : [] smallTeams.forEach((conv: RPCChatTypes.UIInboxSmallTeamRow) => { const id = Types.stringToConversationIDKey(conv.convID) badgeCount += badges.get(id) || 0 - hiddenCount++ }) return { badgeCount, - hiddenCount, + hiddenCount: inboxLayout?.totalSmallTeams ?? 0, } } ) @@ -55,8 +55,16 @@ const getRowCounts = memoize((badges, rows) => { export default namedConnect( mapStateToProps, - () => ({}), - (stateProps, _, ownProps: OwnProps) => { + (dispatch, ownProps: OwnProps) => ({ + toggle: () => { + if (ownProps.smallTeamsExpanded) { + dispatch(Chat2Gen.createLoadMoreSmalls()) + } else { + ownProps.toggle() + } + }, + }), + (stateProps, dispatchProps, ownProps: OwnProps) => { // we remove the badge count of the stuff we're showing let {badgeCount, hiddenCount} = getRowCounts(stateProps._badges, ownProps.rows) @@ -75,7 +83,7 @@ export default namedConnect( hiddenCount, showButton: ownProps.showButton, style: ownProps.style, - toggle: ownProps.toggle, + toggle: dispatchProps.toggle, } }, 'TeamsDivider' diff --git a/shared/constants/types/rpc-chat-gen.tsx b/shared/constants/types/rpc-chat-gen.tsx index a6e4d347cb8b..d6f621971a00 100644 --- a/shared/constants/types/rpc-chat-gen.tsx +++ b/shared/constants/types/rpc-chat-gen.tsx @@ -471,6 +471,14 @@ export type MessageTypes = { inParam: {readonly reselectMode: InboxLayoutReselectMode} outParam: void } + 'chat.1.local.requestInboxSmallIncrease': { + inParam: void + outParam: void + } + 'chat.1.local.requestInboxSmallReset': { + inParam: void + outParam: void + } 'chat.1.local.requestInboxUnbox': { inParam: {readonly convIDs?: Array | null} outParam: void @@ -1317,7 +1325,7 @@ export type UICommandMarkdown = {readonly body: String; readonly title?: String export type UIInboxBigTeamChannelRow = {readonly convID: String; readonly teamname: String; readonly channelname: String; readonly draft?: String | null; readonly isMuted: Boolean} export type UIInboxBigTeamLabelRow = {readonly name: String; readonly id: String} export type UIInboxBigTeamRow = {state: UIInboxBigTeamRowTyp.label; label: UIInboxBigTeamLabelRow} | {state: UIInboxBigTeamRowTyp.channel; channel: UIInboxBigTeamChannelRow} -export type UIInboxLayout = {readonly smallTeams?: Array | null; readonly bigTeams?: Array | null; readonly reselectInfo?: UIInboxReselectInfo | null; readonly widgetList?: Array | null} +export type UIInboxLayout = {readonly totalSmallTeams: Int; readonly smallTeams?: Array | null; readonly bigTeams?: Array | null; readonly reselectInfo?: UIInboxReselectInfo | null; readonly widgetList?: Array | null} export type UIInboxReselectInfo = {readonly oldConvID: String; readonly newConvID?: String | null} export type UIInboxSmallTeamRow = {readonly convID: String; readonly name: String; readonly time: Gregor1.Time; readonly snippet?: String | null; readonly snippetDecoration: SnippetDecoration; readonly draft?: String | null; readonly isMuted: Boolean; readonly isTeam: Boolean} export type UILinkDecoration = {readonly display: String; readonly url: String; readonly punycode: String} @@ -1516,6 +1524,8 @@ export const localPreviewConversationByIDLocalRpcPromise = (params: MessageTypes export const localProfileChatSearchRpcPromise = (params: MessageTypes['chat.1.local.profileChatSearch']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.profileChatSearch', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey})) export const localRemoveBotMemberRpcPromise = (params: MessageTypes['chat.1.local.removeBotMember']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.removeBotMember', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey})) export const localRequestInboxLayoutRpcPromise = (params: MessageTypes['chat.1.local.requestInboxLayout']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.requestInboxLayout', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey})) +export const localRequestInboxSmallIncreaseRpcPromise = (params: MessageTypes['chat.1.local.requestInboxSmallIncrease']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.requestInboxSmallIncrease', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey})) +export const localRequestInboxSmallResetRpcPromise = (params: MessageTypes['chat.1.local.requestInboxSmallReset']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.requestInboxSmallReset', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey})) export const localRequestInboxUnboxRpcPromise = (params: MessageTypes['chat.1.local.requestInboxUnbox']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.requestInboxUnbox', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey})) export const localResolveMaybeMentionRpcPromise = (params: MessageTypes['chat.1.local.resolveMaybeMention']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.resolveMaybeMention', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey})) export const localResolveUnfurlPromptRpcPromise = (params: MessageTypes['chat.1.local.resolveUnfurlPrompt']['inParam'], waitingKey?: WaitingKey) => new Promise((resolve, reject) => engine()._rpcOutgoing({method: 'chat.1.local.resolveUnfurlPrompt', params, callback: (error, result) => (error ? reject(error) : resolve(result)), waitingKey}))