Skip to content

Commit

Permalink
Merge branch 'main' into arrow-feature-signed
Browse files Browse the repository at this point in the history
  • Loading branch information
JediWattson committed Jan 4, 2023
2 parents d2d4e76 + 5af5d30 commit d9d1889
Show file tree
Hide file tree
Showing 58 changed files with 596 additions and 474 deletions.
37 changes: 17 additions & 20 deletions .github/workflows/testBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,33 @@ jobs:
validateActor:
runs-on: ubuntu-latest
outputs:
READY_TO_BUILD: ${{steps.readyToBuild.outputs.READY_TO_BUILD}}
READY_TO_BUILD: ${{ fromJSON(steps.isUserTeamMember.outputs.isTeamMember) && fromJSON(steps.hasReadyToBuildLabel.outputs.HAS_READY_TO_BUILD_LABEL) }}
steps:
- id: isUserTeamMember
uses: tspascoal/get-user-teams-membership@baf2e6adf4c3b897bd65a7e3184305c165aec872
with:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
username: ${{ github.actor }}
team: expensify-expensify
- name: Remove label if it was added by an unauthorized user
if: ${{ !fromJSON(steps.isUserTeamMember.outputs.isTeamMember) && github.event.label.name == 'Ready To Build' }}
uses: actions-ecosystem/action-remove-labels@v1
with:
labels: 'Ready To Build'
- name: Throw exception if label was added by an unauthorized user
if: ${{ !fromJSON(steps.isUserTeamMember.outputs.isTeamMember) && github.event.label.name == 'Ready To Build' }}
run: |
echo "The 'Ready To Build' label was added by an unauthorized user"
exit 1
- id: readyToBuild
name: Set READY_TO_BUILD flag
run: echo "READY_TO_BUILD=${{ fromJSON(steps.isUserTeamMember.outputs.isTeamMember) || contains(github.event.pull_request.labels.*.name, 'Ready To Build') }}" >> "$GITHUB_OUTPUT"
team: 'Expensify/expensify'

- id: hasReadyToBuildLabel
name: Set HAS_READY_TO_BUILD_LABEL flag
run: echo "HAS_READY_TO_BUILD_LABEL=$(gh pr view "${{ env.PULL_REQUEST_NUMBER }}" --repo Expensify/App --json labels --jq '.labels[].name' | grep -q 'Ready To Build' && echo 'true')" >> "$GITHUB_OUTPUT"
env:
PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }}
GITHUB_TOKEN: ${{ github.token }}

getBranchRef:
runs-on: ubuntu-latest
needs: validateActor
if: ${{ needs.validateActor.outputs.READY_TO_BUILD == 'true' }}
if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }}
outputs:
REF: ${{steps.getHeadRef.outputs.REF}}
steps:
- name: Checkout
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8

- name: Check if pull request number is correct
if: ${{ github.event_name == 'workflow_dispatch' }}
id: getHeadRef
Expand All @@ -62,7 +57,7 @@ jobs:
android:
name: Build and deploy Android for testing
needs: [validateActor, getBranchRef]
if: ${{ needs.validateActor.outputs.READY_TO_BUILD == 'true' }}
if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }}
runs-on: ubuntu-latest
env:
PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }}
Expand Down Expand Up @@ -112,7 +107,7 @@ jobs:
iOS:
name: Build and deploy iOS for testing
needs: [validateActor, getBranchRef]
if: ${{ needs.validateActor.outputs.READY_TO_BUILD == 'true' }}
if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }}
env:
PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }}
runs-on: macos-12
Expand Down Expand Up @@ -168,7 +163,7 @@ jobs:
desktop:
name: Build and deploy Desktop for testing
needs: [validateActor, getBranchRef]
if: ${{ needs.validateActor.outputs.READY_TO_BUILD == 'true' }}
if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }}
env:
PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }}
runs-on: macos-12
Expand Down Expand Up @@ -205,7 +200,7 @@ jobs:
web:
name: Build and deploy Web
needs: [validateActor, getBranchRef]
if: ${{ needs.validateActor.outputs.READY_TO_BUILD == 'true' }}
if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }}
env:
PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }}
runs-on: ubuntu-latest
Expand All @@ -214,7 +209,9 @@ jobs:
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || needs.getBranchRef.outputs.REF }}

- uses: Expensify/App/.github/actions/composite/setupNode@main

- name: Configure AWS Credentials
uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main
with:
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001024600
versionName "1.2.46-0"
versionCode 1001024700
versionName "1.2.47-0"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()

if (isNewArchitectureEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.content.Context;
import android.database.CursorWindow;

import androidx.appcompat.app.AppCompatDelegate;
import androidx.multidex.MultiDexApplication;

import com.expensify.chat.bootsplash.BootSplashPackage;
Expand Down Expand Up @@ -64,6 +65,10 @@ public ReactNativeHost getReactNativeHost() {
@Override
public void onCreate() {
super.onCreate();

// Use night (dark) mode so native UI defaults to dark theme.
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);

// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
SoLoader.init(this, /* native exopackage */ false);
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<style name="AppTheme" parent="BaseAppTheme"/>

<!-- Base application theme. Applied to all Android versions -->
<style name="BaseAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<style name="BaseAppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:textColor">@color/dark</item>
<item name="android:colorEdgeEffect">@color/gray4</item>
<item name="android:statusBarColor">#061B09</item>
Expand Down
6 changes: 4 additions & 2 deletions ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.46</string>
<string>1.2.47</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.2.46.0</string>
<string>1.2.47.0</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down Expand Up @@ -111,6 +111,8 @@
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Dark</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
Expand Down
4 changes: 2 additions & 2 deletions ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.46</string>
<string>1.2.47</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.2.46.0</string>
<string>1.2.47.0</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.2.46-0",
"version": "1.2.47-0",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
11 changes: 8 additions & 3 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ const CONST = {
// Minimum width and height size in px for a selected image
AVATAR_MIN_WIDTH_PX: 80,
AVATAR_MIN_HEIGHT_PX: 80,

// Maximum width and height size in px for a selected image
AVATAR_MAX_WIDTH_PX: 4096,
AVATAR_MAX_HEIGHT_PX: 4096,

NEW_EXPENSIFY_URL: ACTIVE_EXPENSIFY_URL,
APP_DOWNLOAD_LINKS: {
ANDROID: `https://play.google.com/store/apps/details?id=${ANDROID_PACKAGE_NAME}`,
Expand Down Expand Up @@ -455,7 +460,7 @@ const CONST = {

EMOJI_FREQUENT_ROW_COUNT: 3,

EMOJI_INVISIBLE_CODEPOINTS: ['fe0f', '200d'],
INVISIBLE_CODEPOINTS: ['fe0f', '200d', '2066'],

TOOLTIP_MAX_LINES: 3,

Expand Down Expand Up @@ -754,8 +759,7 @@ const CONST = {
HYPERLINK: /^(?:(?:(?:https?|ftp):\/\/)?)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i,

// eslint-disable-next-line max-len, no-misleading-character-class
EMOJIS: /(?:\uD83D(?:\uDC41\u200D\uD83D\uDDE8|\uDC68\u200D\uD83D[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uDC69\u200D\uD83D\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c\ude32-\ude3a]|[\ud83c\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g,

EMOJIS: /[\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu,
TAX_ID: /^\d{9}$/,
NON_NUMERIC: /\D/g,

Expand All @@ -765,6 +769,7 @@ const CONST = {
EMOJI_NAME: /:[\w+-]+:/g,
EMOJI_SUGGESTIONS: /:[a-zA-Z]{1,20}(\s[a-zA-Z]{0,20})?$/,
AFTER_FIRST_LINE_BREAK: /\n.*/g,
CODE_2FA: /^\d{6}$/,
},

PRONOUNS: {
Expand Down
4 changes: 4 additions & 0 deletions src/Expensify.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import * as User from './libs/actions/User';
import NetworkConnection from './libs/NetworkConnection';
import Navigation from './libs/Navigation/Navigation';

// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
// eslint-disable-next-line no-unused-vars
import UnreadIndicatorUpdater from './libs/UnreadIndicatorUpdater';

Onyx.registerLogger(({level, message}) => {
if (level === 'alert') {
Log.alert(message);
Expand Down
2 changes: 2 additions & 0 deletions src/components/AttachmentPicker/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ function getDataForUpload(fileData) {
const fileResult = {
name: fileName,
type: fileData.type,
width: fileData.width,
height: fileData.height,
uri: fileData.fileCopyUri || fileData.uri,
size: fileData.fileSize || fileData.size,
};
Expand Down
106 changes: 106 additions & 0 deletions src/components/AutoUpdateTime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* Displays the user's local time and updates it every minute.
* The time auto-update logic is extracted to this component to avoid re-rendering a more complex component, e.g. DetailsPage.
*/
import {View} from 'react-native';
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import styles from '../styles/styles';
import DateUtils from '../libs/DateUtils';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import Text from './Text';

const propTypes = {
/** Timezone of the user from their personal details */
timezone: PropTypes.shape({
/** Value of selected timezone */
selected: PropTypes.string,

/** Whether timezone is automatically set */
automatic: PropTypes.bool,
}).isRequired,
...withLocalizePropTypes,
};

class AutoUpdateTime extends PureComponent {
constructor(props) {
super(props);
this.getCurrentUserLocalTime = this.getCurrentUserLocalTime.bind(this);
this.updateCurrentTime = this.updateCurrentTime.bind(this);
this.getTimezoneName = this.getTimezoneName.bind(this);
this.state = {
currentUserLocalTime: this.getCurrentUserLocalTime(),
};
}

componentDidMount() {
this.updateCurrentTime();
}

componentDidUpdate() {
// Make sure the interval is up to date every time the component updates
this.updateCurrentTime();
}

componentWillUnmount() {
clearTimeout(this.timer);
}

/**
* @returns {moment} Returns the locale moment object
*/
getCurrentUserLocalTime() {
return DateUtils.getLocalMomentFromDatetime(
this.props.preferredLocale,
null,
this.props.timezone.selected,
);
}

/**
* @returns {string} Returns the timezone name in string, e.g.: GMT +07
*/
getTimezoneName() {
// With non-GMT timezone, moment.zoneAbbr() will return the name of that timezone, so we can use it directly.
if (Number.isNaN(Number(this.state.currentUserLocalTime.zoneAbbr()))) {
return this.state.currentUserLocalTime.zoneAbbr();
}

// With GMT timezone, moment.zoneAbbr() will return a number, so we need to display it as GMT {abbreviations} format, e.g.: GMT +07
return `GMT ${this.state.currentUserLocalTime.zoneAbbr()}`;
}

/**
* Update the user's local time at the top of every minute
*/
updateCurrentTime() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
const millisecondsUntilNextMinute = (60 - this.state.currentUserLocalTime.seconds()) * 1000;
this.timer = setTimeout(() => {
this.setState({
currentUserLocalTime: this.getCurrentUserLocalTime(),
});
}, millisecondsUntilNextMinute);
}

render() {
return (
<View style={[styles.mb6, styles.detailsPageSectionContainer]}>
<Text style={[styles.formLabel, styles.mb2]} numberOfLines={1}>
{this.props.translate('detailsPage.localTime')}
</Text>
<Text numberOfLines={1}>
{this.state.currentUserLocalTime.format('LT')}
{' '}
{this.getTimezoneName()}
</Text>
</View>
);
}
}

AutoUpdateTime.propTypes = propTypes;
export default withLocalize(AutoUpdateTime);
Loading

0 comments on commit d9d1889

Please sign in to comment.