Skip to content

Commit

Permalink
Merge branch 'main' into sheena-accountsettings
Browse files Browse the repository at this point in the history
  • Loading branch information
blimpich authored Sep 16, 2024
2 parents fcefad8 + 57d6880 commit 9db5451
Show file tree
Hide file tree
Showing 56 changed files with 385 additions and 143 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.github/actions/**/index.js
*.config.js
**/.eslintrc.js
**/.eslintrc.changed.js
**/node_modules/**
**/dist/**
android/**/build/**
Expand Down
10 changes: 10 additions & 0 deletions .eslintrc.changed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
plugins: ['@typescript-eslint', 'deprecation'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
},
rules: {
'deprecation/deprecation': 'error',
},
};
7 changes: 0 additions & 7 deletions .eslintrc.pr.js

This file was deleted.

32 changes: 32 additions & 0 deletions .github/workflows/lint-changed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Changed files ESLint check

on:
workflow_call:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
paths: ['**.js', '**.ts', '**.tsx', '**.json', '**.mjs', '**.cjs', 'config/.editorconfig', '.watchmanconfig', '.imgbotconfig']

concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-changed-lint
cancel-in-progress: true

jobs:
lint-changed:
name: Changed files ESLint check
if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: ./.github/actions/composite/setupNode

- name: Run ESLint to check for deprecation warnings
run: |
# This will just fetch the latest commit from main
git fetch origin main --no-tags --depth=1
# shellcheck disable=SC2046
npm run lint-changed
22 changes: 2 additions & 20 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Lint code
name: ESLint check

on:
workflow_call:
Expand All @@ -13,7 +13,7 @@ concurrency:

jobs:
lint:
name: Run ESLint
name: ESLint check
if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
runs-on: ubuntu-latest
steps:
Expand All @@ -27,21 +27,3 @@ jobs:
run: npm run lint
env:
CI: true

- name: Run ESLint with stricter checks on changed files
run: |
# shellcheck disable=SC2046
npx eslint --config ./.eslintrc.pr.js $(git diff --diff-filter=AM --name-only main -- "*.js" "*.ts" "*.tsx")
- name: Verify there's no Prettier diff
run: |
npm run prettier -- --loglevel silent
if ! git diff --name-only --exit-code; then
# shellcheck disable=SC2016
echo 'Error: Prettier diff detected! Please run `npm run prettier` and commit the changes.'
exit 1
fi
- name: Run unused style searcher
shell: bash
run: ./.github/scripts/findUnusedKeys.sh
3 changes: 3 additions & 0 deletions .github/workflows/preDeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ jobs:
lint:
uses: ./.github/workflows/lint.yml

prettier:
uses: ./.github/workflows/prettier.yml

test:
uses: ./.github/workflows/test.yml

Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Prettier check

on:
workflow_call:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
paths: ['**.js', '**.ts', '**.tsx', '**.json', '**.mjs', '**.cjs', 'config/.editorconfig', '.watchmanconfig', '.imgbotconfig']

concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-prettier
cancel-in-progress: true

jobs:
prettier:
name: Prettier check
if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: ./.github/actions/composite/setupNode

- name: Verify there's no Prettier diff
run: |
npm run prettier -- --loglevel silent
if ! git diff --name-only --exit-code; then
# shellcheck disable=SC2016
echo 'Error: Prettier diff detected! Please run `npm run prettier` and commit the changes.'
exit 1
fi
- name: Run unused style searcher
shell: bash
run: ./.github/scripts/findUnusedKeys.sh
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1009003507
versionName "9.0.35-7"
versionCode 1009003600
versionName "9.0.36-0"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.database.CursorWindow
import android.os.Process
import androidx.multidex.MultiDexApplication
import com.expensify.chat.bootsplash.BootSplashPackage
import com.expensify.chat.shortcutManagerModule.ShortcutManagerPackage
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
Expand All @@ -29,6 +30,7 @@ class MainApplication : MultiDexApplication(), ReactApplication {
PackageList(this).packages.apply {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage());
add(ShortcutManagerPackage())
add(BootSplashPackage())
add(ExpensifyAppPackage())
add(RNTextInputResetPackage())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
Expand All @@ -30,10 +31,13 @@
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.Person;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
import androidx.versionedparcelable.ParcelUtils;

import com.expensify.chat.R;
import com.expensify.chat.shortcutManagerModule.ShortcutManagerUtils;
import com.urbanairship.AirshipConfigOptions;
import com.urbanairship.json.JsonMap;
import com.urbanairship.json.JsonValue;
Expand All @@ -47,6 +51,7 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
Expand Down Expand Up @@ -205,44 +210,47 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil

// Use the formatted alert message from the backend. Otherwise fallback on the message in the Onyx data.
String message = alert != null ? alert : messageData.get("message").getList().get(0).getMap().get("text").getString();
String conversationName = payload.get("roomName") == null ? "" : payload.get("roomName").getString("");
String roomName = payload.get("roomName") == null ? "" : payload.get("roomName").getString("");

// create the Person object who sent the latest report comment
// Create the Person object who sent the latest report comment
Bitmap personIcon = fetchIcon(context, avatar);
builder.setLargeIcon(personIcon);

Person person = createMessagePersonObject(IconCompat.createWithBitmap(personIcon), accountID, name);

ShortcutManagerUtils.addDynamicShortcut(context, reportID, name, accountID, personIcon, person);

// Create latest received message object
long createdTimeInMillis = getMessageTimeInMillis(messageData.get("created").getString(""));
NotificationCompat.MessagingStyle.Message newMessage = new NotificationCompat.MessagingStyle.Message(message, createdTimeInMillis, person);

// Conversational styling should be applied to groups chats, rooms, and any 1:1 chats with more than one notification (ensuring the large profile image is always shown)
if (!conversationName.isEmpty() || hasExistingNotification) {
// Create the messaging style notification builder for this notification, associating it with the person who sent the report comment
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(person)
.setGroupConversation(true)
.setConversationTitle(conversationName);
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(person);

// Add all conversation messages to the notification, including the last one we just received.
List<NotificationCompat.MessagingStyle.Message> messages;
if (hasExistingNotification) {
NotificationCompat.MessagingStyle previousStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(existingReportNotification.getNotification());
messages = previousStyle != null ? previousStyle.getMessages() : new ArrayList<>(List.of(recreatePreviousMessage(existingReportNotification)));
} else {
messages = new ArrayList<>();
}

// Add all conversation messages to the notification, including the last one we just received.
List<NotificationCompat.MessagingStyle.Message> messages;
if (hasExistingNotification) {
NotificationCompat.MessagingStyle previousStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(existingReportNotification.getNotification());
messages = previousStyle != null ? previousStyle.getMessages() : new ArrayList<>(List.of(recreatePreviousMessage(existingReportNotification)));
} else {
messages = new ArrayList<>();
}

// add the last one message we just received.
messages.add(newMessage);
// add the last one message we just received.
messages.add(newMessage);

for (NotificationCompat.MessagingStyle.Message activeMessage : messages) {
messagingStyle.addMessage(activeMessage);
}
for (NotificationCompat.MessagingStyle.Message activeMessage : messages) {
messagingStyle.addMessage(activeMessage);
}

builder.setStyle(messagingStyle);
// Conversational styling should be applied to groups chats, rooms, and any 1:1 chats with more than one notification (ensuring the large profile image is always shown)
if (!roomName.isEmpty()) {
// Create the messaging style notification builder for this notification, associating it with the person who sent the report comment
messagingStyle
.setGroupConversation(true)
.setConversationTitle(roomName);
}
builder.setStyle(messagingStyle);
builder.setShortcutId(accountID);

// save reportID and person info for future merging
builder.addExtras(createMessageExtrasBundle(reportID, person));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.expensify.chat.shortcutManagerModule;

import static androidx.core.app.NotificationCompat.CATEGORY_MESSAGE;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.Person;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.util.Collections;

import com.expensify.chat.customairshipextender.CustomNotificationProvider;

public class ShortcutManagerModule extends ReactContextBaseJavaModule {
private ReactApplicationContext context;

public ShortcutManagerModule(ReactApplicationContext context) {
super(context);
this.context = context;
}

@NonNull
@Override
public String getName() {
return "ShortcutManager";
}

@ReactMethod
public void removeAllDynamicShortcuts() {
ShortcutManagerUtils.removeAllDynamicShortcuts(context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.expensify.chat.shortcutManagerModule;

import androidx.annotation.NonNull;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ShortcutManagerPackage implements ReactPackage {

@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ShortcutManagerModule(reactContext));
return modules;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.expensify.chat.shortcutManagerModule;

import static androidx.core.app.NotificationCompat.CATEGORY_MESSAGE;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;

import androidx.core.app.Person;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;

import java.util.Collections;

public class ShortcutManagerUtils {
public static void removeAllDynamicShortcuts(Context context) {
ShortcutManagerCompat.removeAllDynamicShortcuts(context);
}

public static void addDynamicShortcut(Context context, long reportID, String name, String accountID, Bitmap personIcon, Person person) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("new-expensify://r/" + reportID));

ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, accountID)
.setShortLabel(name)
.setLongLabel(name)
.setCategories(Collections.singleton(CATEGORY_MESSAGE))
.setIntent(intent)
.setLongLived(true)
.setPerson(person)
.setIcon(IconCompat.createWithBitmap(personIcon))
.build();
ShortcutManagerCompat.pushDynamicShortcut(context, shortcutInfo);
}

}
Loading

0 comments on commit 9db5451

Please sign in to comment.