More card tweaks, show comments at the bottom and update date at the right for issues/prs

This commit is contained in:
Bruno Lemos
2019-04-30 21:28:17 -03:00
parent 5e27e248f9
commit 02ee9cd4f2
14 changed files with 280 additions and 103 deletions

View File

@@ -78,6 +78,7 @@ export interface EventCardProps {
event: EnhancedGitHubEvent
isFocused?: boolean
repoIsKnown: boolean
swipeable: boolean
}
export const EventCard = React.memo((props: EventCardProps) => {
@@ -85,8 +86,9 @@ export const EventCard = React.memo((props: EventCardProps) => {
cardViewMode,
enableCompactLabels,
event,
repoIsKnown,
isFocused,
repoIsKnown,
swipeable,
} = props
const itemRef = useRef<View>(null)
@@ -119,7 +121,10 @@ export const EventCard = React.memo((props: EventCardProps) => {
let branchName = getBranchNameFromRef(branchOrTagRef)
const issueOrPullRequest = issue || pullRequest
const issueOrPullRequest = (issue || pullRequest) as
| typeof issue
| typeof pullRequest
| undefined
const issueOrPullRequestNumber = issueOrPullRequest
? issueOrPullRequest.number ||
@@ -237,6 +242,8 @@ export const EventCard = React.memo((props: EventCardProps) => {
const avatarUrl = (isBot && botAvatarURL) || actor.avatar_url
const showCardActions = cardViewMode !== 'compact' && !swipeable
let withTopMargin = cardViewMode !== 'compact'
let withTopMarginCount = withTopMargin ? 1 : 0
function getWithTopMargin() {
@@ -346,7 +353,9 @@ export const EventCard = React.memo((props: EventCardProps) => {
}
body={issueOrPullRequest.body}
bold
commentsCount={issueOrPullRequest.comments}
commentsCount={
showCardActions ? undefined : issueOrPullRequest.comments
}
createdAt={issueOrPullRequest.created_at}
hideIcon
hideLabelText={false}
@@ -604,7 +613,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
color: label.color && `#${label.color}`,
name: label.name,
}))}
// muted={isRead}
muted={isRead}
style={{
alignSelf: 'center',
justifyContent: 'flex-end',
@@ -751,14 +760,27 @@ export const EventCard = React.memo((props: EventCardProps) => {
<View style={cardStyles.itemFixedWidth} />
</View>
<Spacer height={topCardMargin} />
{!!showCardActions && (
<>
<Spacer height={topCardMargin} />
<CardActions
isRead={isRead}
isSaved={isSaved}
itemIds={[id]}
type="activity"
/>
<CardActions
commentsCount={
issueOrPullRequest ? issueOrPullRequest.comments : undefined
}
commentsLink={
(comment && (comment.html_url || comment.url)) ||
(issueOrPullRequest &&
(issueOrPullRequest.html_url || issueOrPullRequest.url)) ||
undefined
}
isRead={isRead}
isSaved={isSaved}
itemIds={[id]}
type="activity"
/>
</>
)}
<Spacer width={contentPadding / 3} />
</View>

View File

@@ -45,7 +45,7 @@ export interface EventCardsProps
pointerEvents: FlatListProps<any>['pointerEvents']
refresh: EmptyCardsProps['refresh']
repoIsKnown: boolean
swipeable?: boolean
swipeable: boolean
}
function keyExtractor(item: EnhancedGitHubEvent, _index: number) {
@@ -163,11 +163,12 @@ export const EventCards = React.memo((props: EventCardsProps) => {
cardViewMode={cardViewMode}
enableCompactLabels={enableCompactLabels}
event={item}
repoIsKnown={props.repoIsKnown}
isFocused={
column.id === focusedColumnId &&
item.id === selectedItemIdRef.current
}
repoIsKnown={props.repoIsKnown}
swipeable={props.swipeable}
/>
)
}
@@ -183,6 +184,7 @@ export const EventCards = React.memo((props: EventCardsProps) => {
item.id === selectedItemIdRef.current
}
repoIsKnown={props.repoIsKnown}
swipeable={props.swipeable}
/>
</ErrorBoundary>
)

View File

@@ -49,6 +49,7 @@ export interface IssueOrPullRequestCardProps {
isPrivate?: boolean
issueOrPullRequest: EnhancedGitHubIssueOrPullRequest
repoIsKnown: boolean
swipeable: boolean
type: GitHubIssueOrPullRequestSubjectType
}
@@ -61,6 +62,7 @@ export const IssueOrPullRequestCard = React.memo(
isPrivate,
issueOrPullRequest,
repoIsKnown,
swipeable,
type,
} = props
@@ -119,6 +121,8 @@ export const IssueOrPullRequestCard = React.memo(
const cardIconName = cardIconDetails.icon
const cardIconColor = cardIconDetails.color
const showCardActions = cardViewMode !== 'compact' && !swipeable
let withTopMargin = false
let withTopMarginCount = withTopMargin ? 1 : 0
function getWithTopMargin() {
@@ -158,17 +162,11 @@ export const IssueOrPullRequestCard = React.memo(
}
body={issueOrPullRequest.body}
bold
commentsCount={issueOrPullRequest.comments}
createdAt={
cardViewMode === 'compact'
? issueOrPullRequest.created_at
: undefined
}
updatedAt={
cardViewMode === 'compact'
? undefined
: issueOrPullRequest.updated_at
commentsCount={
showCardActions ? undefined : issueOrPullRequest.comments
}
createdAt={issueOrPullRequest.created_at}
// updatedAt={issueOrPullRequest.updated_at}
hideIcon
hideLabelText={false}
// iconColor={issueIconColor || pullRequestIconColor}
@@ -180,6 +178,56 @@ export const IssueOrPullRequestCard = React.memo(
labels={enableCompactLabels ? [] : issueOrPullRequest.labels}
owner={repoOwnerName || ''}
repo={repoName || ''}
rightTitle={
!!issueOrPullRequest.updated_at &&
cardViewMode !== 'compact' && (
<View
style={[
cardStyles.compactItemFixedHeight,
sharedStyles.horizontal,
]}
>
<IntervalRefresh date={issueOrPullRequest.updated_at}>
{() => {
const createdAt = issueOrPullRequest.created_at
const updatedAt = issueOrPullRequest.updated_at
const dateText = getDateSmallText(updatedAt, false)
if (!dateText) return null
return (
<>
<ThemedText
color="foregroundColorMuted50"
numberOfLines={1}
style={cardStyles.smallerText}
{...Platform.select({
web: {
title: `${
createdAt
? `Created: ${getFullDateText(
createdAt,
)}\n`
: ''
}Updated: ${getFullDateText(updatedAt)}`,
},
})}
>
{/* <ThemedIcon
name="clock"
style={cardStyles.smallerText}
/>{' '} */}
{dateText}
</ThemedText>
</>
)
}}
</IntervalRefresh>
<Spacer width={contentPadding / 3} />
</View>
)
}
showBodyRow={
false
// issueOrPullRequest &&
@@ -188,7 +236,7 @@ export const IssueOrPullRequestCard = React.memo(
// ? true
// : false
}
showCreationDetails={cardViewMode !== 'compact'}
showCreationDetails={false}
title={issueOrPullRequest.title}
url={issueOrPullRequest.url}
userLinkURL={issueOrPullRequest.user.html_url || ''}
@@ -526,14 +574,26 @@ export const IssueOrPullRequestCard = React.memo(
</View>
</View>
<Spacer height={topCardMargin} />
{!!showCardActions && (
<>
<Spacer height={topCardMargin} />
<CardActions
isRead={isRead}
isSaved={isSaved}
itemIds={[id]}
type="issue_or_pr"
/>
<CardActions
commentsCount={
issueOrPullRequest ? issueOrPullRequest.comments : undefined
}
commentsLink={
(issueOrPullRequest &&
(issueOrPullRequest.html_url || issueOrPullRequest.url)) ||
undefined
}
isRead={isRead}
isSaved={isSaved}
itemIds={[id]}
type="issue_or_pr"
/>
</>
)}
<Spacer width={contentPadding / 3} />
</View>

View File

@@ -51,7 +51,7 @@ export interface IssueOrPullRequestCardsProps
loadState: EnhancedLoadState
pointerEvents: FlatListProps<any>['pointerEvents']
refresh: EmptyCardsProps['refresh']
swipeable?: boolean
swipeable: boolean
}
function keyExtractor(item: EnhancedGitHubIssueOrPullRequest) {
@@ -178,6 +178,7 @@ export const IssueOrPullRequestCards = React.memo(
}
issueOrPullRequest={item}
repoIsKnown={props.repoIsKnown}
swipeable={props.swipeable}
type={getIssueOrPullRequestSubjectType(item) || 'Issue'}
/>
)
@@ -194,6 +195,7 @@ export const IssueOrPullRequestCards = React.memo(
}
issueOrPullRequest={item}
repoIsKnown={props.repoIsKnown}
swipeable={props.swipeable}
type={getIssueOrPullRequestSubjectType(item) || 'Issue'}
/>
</ErrorBoundary>

View File

@@ -58,15 +58,17 @@ export interface NotificationCardProps {
isFocused: boolean
notification: EnhancedGitHubNotification
repoIsKnown: boolean
swipeable: boolean
}
export const NotificationCard = React.memo((props: NotificationCardProps) => {
const {
cardViewMode,
enableCompactLabels,
isFocused,
notification,
repoIsKnown,
enableCompactLabels,
swipeable,
} = props
const repoFullName =
@@ -146,6 +148,7 @@ export const NotificationCard = React.memo((props: NotificationCardProps) => {
state: undefined,
title: subject.title,
url: subject.latest_comment_url || subject.url,
html_url: '',
user: { avatar_url: '', login: '', html_url: '' },
}) ||
null
@@ -163,6 +166,7 @@ export const NotificationCard = React.memo((props: NotificationCardProps) => {
state: undefined,
title: subject.title,
url: subject.latest_comment_url || subject.url,
html_url: '',
user: { avatar_url: '', login: '', html_url: '' },
}) ||
null
@@ -216,6 +220,8 @@ export const NotificationCard = React.memo((props: NotificationCardProps) => {
actor && actor.login && actor.login.indexOf('[bot]') >= 0,
)
const showCardActions = cardViewMode !== 'compact' && !swipeable
let withTopMargin = cardViewMode !== 'compact'
let withTopMarginCount = withTopMargin ? 1 : 0
function getWithTopMargin() {
@@ -293,7 +299,9 @@ export const NotificationCard = React.memo((props: NotificationCardProps) => {
}
body={issueOrPullRequest.body}
bold
commentsCount={issueOrPullRequest.comments}
commentsCount={
showCardActions ? undefined : issueOrPullRequest.comments
}
createdAt={issueOrPullRequest.created_at}
hideIcon
hideLabelText={false}
@@ -608,7 +616,7 @@ export const NotificationCard = React.memo((props: NotificationCardProps) => {
backgroundThemeColor={theme =>
getCardBackgroundThemeColor(theme, { isRead })
}
// muted={isRead}
muted={isRead}
reason={notification.reason as GitHubNotificationReason}
/>
</View>
@@ -703,14 +711,27 @@ export const NotificationCard = React.memo((props: NotificationCardProps) => {
{/* <Spacer width={contentPadding / 3} /> */}
</View>
<Spacer height={topCardMargin} />
{!!showCardActions && (
<>
<Spacer height={topCardMargin} />
<CardActions
isRead={isRead}
isSaved={isSaved}
itemIds={[id]}
type="notifications"
/>
<CardActions
commentsCount={
issueOrPullRequest ? issueOrPullRequest.comments : undefined
}
commentsLink={
(comment && (comment.html_url || comment.url)) ||
(issueOrPullRequest &&
(issueOrPullRequest.html_url || issueOrPullRequest.url)) ||
undefined
}
isRead={isRead}
isSaved={isSaved}
itemIds={[id]}
type="notifications"
/>
</>
)}
<Spacer width={contentPadding / 3} />
</View>

View File

@@ -45,7 +45,7 @@ export interface NotificationCardsProps
pointerEvents: FlatListProps<any>['pointerEvents']
refresh: EmptyCardsProps['refresh']
repoIsKnown: boolean
swipeable?: boolean
swipeable: boolean
}
function keyExtractor(item: EnhancedGitHubNotification) {
@@ -170,6 +170,7 @@ export const NotificationCards = React.memo((props: NotificationCardsProps) => {
}
notification={item}
repoIsKnown={props.repoIsKnown}
swipeable={props.swipeable}
/>
)
}
@@ -185,6 +186,7 @@ export const NotificationCards = React.memo((props: NotificationCardsProps) => {
}
notification={item}
repoIsKnown={props.repoIsKnown}
swipeable={props.swipeable}
/>
</ErrorBoundary>
)

View File

@@ -1,8 +1,9 @@
import React from 'react'
import { View } from 'react-native'
import { ColumnSubscription } from '@devhub/core'
import { ColumnSubscription, fixURLForPlatform } from '@devhub/core'
import { useReduxAction } from '../../../hooks/use-redux-action'
import { Platform } from '../../../libs/platform'
import * as actions from '../../../redux/actions'
import { sharedStyles } from '../../../styles/shared'
import {
@@ -15,6 +16,8 @@ import { Spacer } from '../../common/Spacer'
import { spacingBetweenLeftAndRightColumn } from '../styles'
export interface CardActionsProps {
commentsCount: number | undefined
commentsLink: string | (() => void) | undefined
isRead: boolean
isSaved: boolean
itemIds: Array<string | number>
@@ -25,6 +28,8 @@ export interface CardActionsProps {
export function CardActions(props: CardActionsProps) {
const {
commentsCount,
commentsLink,
isRead,
isSaved,
itemIds,
@@ -45,11 +50,12 @@ export function CardActions(props: CardActionsProps) {
{leftSpacing > 0 && <Spacer width={leftSpacing} />}
<Link
analyticsCategory="card_action"
analyticsLabel={isSaved ? 'unsave_for_later' : 'save_for_later'}
hitSlop={{
top: contentPadding / 2,
bottom: contentPadding / 2,
left: contentPadding,
left: contentPadding / 4,
right: contentPadding / 4,
}}
onPress={() => saveItemsForLater({ itemIds, save: !isSaved })}
@@ -66,12 +72,13 @@ export function CardActions(props: CardActionsProps) {
<Spacer width={contentPadding / 2} />
<Link
analyticsCategory="card_action"
analyticsLabel={isRead ? 'mark_as_unread' : 'mark_as_read'}
hitSlop={{
top: contentPadding / 2,
bottom: contentPadding / 2,
left: contentPadding / 4,
right: contentPadding,
right: contentPadding / 4,
}}
onPress={() =>
markItemsAsReadOrUnread({ type, itemIds, unread: !!isRead })
@@ -86,6 +93,46 @@ export function CardActions(props: CardActionsProps) {
{isRead ? 'mark as unread' : 'mark as read'}
</Link>
{typeof commentsCount === 'number' &&
commentsCount >= 0 &&
!!commentsLink && (
<>
<Spacer width={contentPadding / 2} />
<Link
analyticsCategory="card_action"
analyticsLabel="commentsCount"
hitSlop={{
top: contentPadding / 2,
bottom: contentPadding / 2,
left: contentPadding / 4,
right: contentPadding / 4,
}}
href={
typeof commentsLink === 'string'
? fixURLForPlatform(commentsLink, Platform.realOS, {
addBottomAnchor: true,
})
: undefined
}
onPress={
typeof commentsLink === 'function' ? commentsLink : undefined
}
openOnNewTab
textProps={{
color: 'foregroundColorMuted50',
style: {
fontSize: smallerTextSize,
},
}}
>
{commentsCount === 1
? 'comment (1)'
: `comments (${commentsCount})`}
</Link>
</>
)}
{rightSpacing > 0 && <Spacer width={rightSpacing} />}
</View>
)

View File

@@ -154,7 +154,7 @@ export function NotificationCardHeader(props: NotificationCardHeaderProps) {
<NotificationReason
backgroundThemeColor={backgroundThemeColor}
// muted={isRead}
muted={isRead}
reason={reason}
/>
</View>

View File

@@ -16,6 +16,7 @@ import { sharedStyles } from '../../../../styles/shared'
import { contentPadding, smallAvatarSize } from '../../../../styles/variables'
import { fixURL } from '../../../../utils/helpers/github/url'
import { Avatar } from '../../../common/Avatar'
import { ConditionalWrap } from '../../../common/ConditionalWrap'
import { IntervalRefresh } from '../../../common/IntervalRefresh'
import { LabelProps } from '../../../common/Label'
import { Link } from '../../../common/Link'
@@ -53,6 +54,7 @@ export interface IssueOrPullRequestRowProps
labels?: GitHubLabel[] | undefined
owner: string
repo: string
rightTitle?: React.ReactNode
showBodyRow: boolean
showCreationDetails: boolean
title: string
@@ -84,6 +86,7 @@ export const IssueOrPullRequestRow = React.memo(
labels,
owner,
repo,
rightTitle,
showBodyRow,
showCreationDetails,
title: _title,
@@ -149,50 +152,67 @@ export const IssueOrPullRequestRow = React.memo(
inlineLabels && sharedStyles.flexWrap,
]}
>
<Link
enableTextWrapper
href={htmlUrl}
style={[
!inlineLabels && sharedStyles.flexGrow,
{ alignSelf: 'flex-start' },
!!inlineLabels &&
labels &&
labels.length > 0 && { marginRight: contentPadding / 2 },
!inlineLabels &&
labels &&
labels.length > 0 && { marginBottom: innerCardSpacing },
]}
textProps={{
color: isRead ? 'foregroundColorMuted50' : 'foregroundColor',
// color: 'foregroundColor',
numberOfLines,
style: [
sharedStyles.flex,
cardStyles.normalText,
bold && cardStyles.boldText,
// isRead && { fontWeight: undefined },
],
}}
// tooltip={`${title}${_body ? `\n\n${_body}` : ''}`}
>
<>
{!hideIcon && (
<>
<ThemedIcon
color={iconColor}
name={iconName}
size={13}
style={[cardStyles.normalText, cardStyles.icon]}
/>{' '}
</>
)}
{title}
<ConditionalWrap
condition={!!rightTitle}
wrap={c => (
<View style={[sharedStyles.flex, sharedStyles.horizontal]}>
<View style={sharedStyles.flex}>{c}</View>
{/* {!!issueOrPullRequestNumber &&
<Spacer width={contentPadding / 2} />
<View style={{ alignSelf: 'flex-start' }}>
{rightTitle}
</View>
</View>
)}
>
<Link
enableTextWrapper
href={htmlUrl}
style={[
!inlineLabels && !rightTitle && sharedStyles.flexGrow,
{ alignSelf: 'flex-start' },
!!inlineLabels &&
labels &&
labels.length > 0 && { marginRight: contentPadding / 2 },
!inlineLabels &&
labels &&
labels.length > 0 && { marginBottom: innerCardSpacing },
]}
textProps={{
color: isRead
? 'foregroundColorMuted50'
: 'foregroundColor',
// color: 'foregroundColor',
numberOfLines,
style: [
sharedStyles.flex,
cardStyles.normalText,
bold && cardStyles.boldText,
// isRead && { fontWeight: undefined },
],
}}
// tooltip={`${title}${_body ? `\n\n${_body}` : ''}`}
>
<>
{!hideIcon && (
<>
<ThemedIcon
color={iconColor}
name={iconName}
size={13}
style={[cardStyles.normalText, cardStyles.icon]}
/>{' '}
</>
)}
{title}
{/* {!!issueOrPullRequestNumber &&
(viewMode === 'compact' || !showCreationDetails) &&
` #${issueOrPullRequestNumber}`} */}
</>
</Link>
</>
</Link>
</ConditionalWrap>
{!!labels && labels.length > 0 && (
<LabelsView
@@ -210,7 +230,7 @@ export const IssueOrPullRequestRow = React.memo(
color: label.color && `#${label.color}`,
name: label.name,
}))}
// muted={isRead}
muted={isRead}
textThemeColor="foregroundColorMuted50"
/>
)}

View File

@@ -3,6 +3,7 @@ import { ScrollView, ViewProps } from 'react-native'
import { GitHubLabel, Omit } from '@devhub/core'
import { sharedStyles } from '../../../../styles/shared'
import { contentPadding } from '../../../../styles/variables'
import { ConditionalWrap } from '../../../common/ConditionalWrap'
import { hiddenLabelSize, Label, LabelProps } from '../../../common/Label'
import { TouchableOpacity } from '../../../common/TouchableOpacity'
@@ -37,7 +38,9 @@ export const LabelsView = (props: LabelsViewProps) => {
scrollViewRef.current.scrollToEnd({ animated: false })
}, [scrollViewRef.current])
const horizontalSpacing = hideText ? -hiddenLabelSize.width / 8 : 1
const horizontalSpacing = hideText
? -hiddenLabelSize.width / 8
: contentPadding / 3
const verticalSpacing = 1
const texts = labels
@@ -92,8 +95,8 @@ export const LabelsView = (props: LabelsViewProps) => {
colorThemeColor={label.color}
containerStyle={{
alignSelf: 'flex-start',
marginHorizontal: horizontalSpacing,
marginVertical: verticalSpacing,
paddingHorizontal: horizontalSpacing,
paddingVertical: verticalSpacing,
}}
hideText={hideText}
outline={false}

View File

@@ -9,12 +9,12 @@ import { Label } from '../../../../common/Label'
export interface NotificationReasonProps {
backgroundThemeColor: keyof ThemeColors | ((theme: ThemeColors) => string)
muted?: boolean
muted: boolean
reason: GitHubNotificationReason
}
export function NotificationReason(props: NotificationReasonProps) {
const { backgroundThemeColor, reason } = props
const { backgroundThemeColor, muted, reason } = props
const reasonDetails = getNotificationReasonMetadata(reason)
@@ -24,9 +24,10 @@ export function NotificationReason(props: NotificationReasonProps) {
<Label
backgroundThemeColor={backgroundThemeColor}
colorThemeColor={reasonDetails.color}
containerStyle={{ alignSelf: 'center' }}
muted={muted}
outline={false}
small
textThemeColor="foregroundColorMuted50"
>
{reasonDetails.label.toLowerCase()}
</Label>

View File

@@ -107,7 +107,7 @@ export function Label(props: LabelProps) {
alignItems: 'center',
justifyContent: 'center',
borderRadius: typeof radius === 'number' ? radius : height / 2,
borderWidth: StyleSheet.hairlineWidth,
borderWidth: outline ? StyleSheet.hairlineWidth : 0,
},
containerProps && containerProps.style,
containerStyle,
@@ -116,7 +116,6 @@ export function Label(props: LabelProps) {
backgroundColor,
},
Boolean(radius) && { borderRadius: radius },
muted && hideText && { opacity: mutedOpacity },
]}
>
{!hideText && (
@@ -127,6 +126,7 @@ export function Label(props: LabelProps) {
{
width: 6,
height: 6,
marginTop: 1,
borderRadius: 6 / 2,
backgroundColor: circleColor,
},
@@ -143,10 +143,10 @@ export function Label(props: LabelProps) {
hideText ? { width } : { minWidth: width },
{
height,
lineHeight: hideText ? height : height - 2,
lineHeight: height,
fontSize: hideText ? 0 : small ? 11 : 12,
color: foregroundColor,
paddingHorizontal: hideText ? 0 : contentPadding / (small ? 3 : 2),
paddingLeft: hideText ? 0 : contentPadding / (small ? 3 : 2),
},
textProps && !hideText && textProps.style,
]}

View File

@@ -11,7 +11,7 @@ export interface ColumnContainerProps {
columnId: string
disableColumnOptions?: boolean
pagingEnabled?: boolean
swipeable?: boolean
swipeable: boolean
pointerEvents: FlatListProps<any>['pointerEvents']
}

View File

@@ -7,9 +7,6 @@ import {
Column,
ColumnFilters,
ColumnSubscription,
EnhancedGitHubEvent,
EnhancedGitHubIssueOrPullRequest,
EnhancedGitHubNotification,
EnhancedItem,
GitHubAPIHeaders,
GitHubEventSubjectType,