Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8549c7912 | ||
|
|
8fc7421bef | ||
|
|
1050b57de8 | ||
|
|
936168b6df | ||
|
|
3b69e5873e | ||
|
|
5e5ed0a11e | ||
|
|
bca2258508 | ||
|
|
7b739dff45 |
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"testRunner": "jest",
|
||||
"testRegex": "\\.visual\\.js$",
|
||||
|
||||
"devices": {
|
||||
|
||||
"simulator": {
|
||||
"type": "ios.simulator",
|
||||
"device": {
|
||||
"type": "iPhone 11 Pro"
|
||||
}
|
||||
}
|
||||
},
|
||||
"apps": {
|
||||
"ios.release": {
|
||||
"name": "StatusIm",
|
||||
"type": "ios.app",
|
||||
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/StatusIm.app",
|
||||
"build": "make release-ios"
|
||||
},
|
||||
"ios.debug": {
|
||||
"name": "StatusIm",
|
||||
"type": "ios.app",
|
||||
"binaryPath": "/Users/erik/Library/Developer/Xcode/DerivedData/StatusIm-dkjkfsbgallhrnchhutvuvbicfsa/Build/Products/Debug-iphonesimulator/StatusIm.app",
|
||||
"build": "make run-ios SIMULATOR='iPhone 11 Pro'"
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"ios.sim.release": {
|
||||
"device": "simulator",
|
||||
"app": "ios.release"
|
||||
},
|
||||
"ios.sim.debug": {
|
||||
"device": "simulator",
|
||||
"app": "ios.debug"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,52 +0,0 @@
|
||||
const waitToNavigate = duration => new Promise(resolve => setTimeout(() => resolve(), duration));
|
||||
|
||||
describe('Example (hello)', () => {
|
||||
beforeAll(async () => {
|
||||
if (device.getPlatform() === 'ios') {
|
||||
await device.setStatusBar({ time: '12:34', dataNetwork: 'wifi', wifiBars: '3', batteryState: 'charging', batteryLevel: '100' });
|
||||
}
|
||||
await device.reloadReactNative();
|
||||
|
||||
await element(by.text('I accept Status Terms of Use')).tap();
|
||||
// close alert
|
||||
await element(by.text('Get started')).tap();
|
||||
await waitToNavigate(200);
|
||||
|
||||
await element(by.text('Generate keys')).tap();
|
||||
await waitToNavigate(200);
|
||||
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
// await element(by.text('Password...')).typeText('infinitbility@gmail.com');
|
||||
// await element(by.text('Confirm your password...')).typeText('infinitbility@gmail.com');
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.text('Maybe later')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.text("Let's go")).tap();
|
||||
await waitToNavigate(700);
|
||||
|
||||
await element(by.text("1")).tap();
|
||||
await waitToNavigate(400);
|
||||
await element(by.text("Quo2.0 Preview")).tap();
|
||||
await waitToNavigate(400);
|
||||
})
|
||||
beforeEach(async () => {
|
||||
});
|
||||
afterEach(async () => {
|
||||
await element(by.text("1")).tap();
|
||||
await waitToNavigate(200);
|
||||
await element(by.text("Quo2.0 Preview")).tap();
|
||||
await waitToNavigate(200);
|
||||
});
|
||||
|
||||
|
||||
it(`button page should match snapshot`, async () => {
|
||||
await element(by.text(`:button`)).tap();
|
||||
await waitToNavigate(200);
|
||||
const res = await jestExpect(`default-render-button`).toMatchImageSnapshot();
|
||||
})
|
||||
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"globalSetup": "./global-setup.js",
|
||||
"globalTeardown": "./global-teardown.js",
|
||||
"setupFilesAfterEnv": ["./setup.js"],
|
||||
"maxWorkers": 1,
|
||||
"testEnvironment": "./environment",
|
||||
"testRunner": "jest-circus/runner",
|
||||
"testTimeout": 120000,
|
||||
"testRegex": "\\.e2e\\.js$",
|
||||
|
||||
"reporters": ["detox/runners/jest/streamlineReporter"],
|
||||
"verbose": true
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
const {
|
||||
DetoxCircusEnvironment,
|
||||
SpecReporter,
|
||||
WorkerAssignReporter,
|
||||
} = require('detox/runners/jest-circus');
|
||||
|
||||
class CustomDetoxEnvironment extends DetoxCircusEnvironment {
|
||||
constructor(config, context) {
|
||||
super(config, context);
|
||||
|
||||
// Can be safely removed, if you are content with the default value (=300000ms)
|
||||
this.initTimeout = 300000;
|
||||
|
||||
// This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
|
||||
// This is strictly optional.
|
||||
this.registerListeners({
|
||||
SpecReporter,
|
||||
WorkerAssignReporter,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CustomDetoxEnvironment;
|
||||
@@ -1,40 +0,0 @@
|
||||
const fs = require('fs-extra');
|
||||
const { execSync } = require('child_process');
|
||||
const detox = require('detox');
|
||||
|
||||
async function globalSetup() {
|
||||
const config = resolveSelectedConfiguration() || {};
|
||||
downloadTestButlerAPKIfNeeded(config);
|
||||
await detox.globalInit();
|
||||
}
|
||||
|
||||
function downloadTestButlerAPKIfNeeded(config) {
|
||||
if (isAndroidConfig(config)) {
|
||||
downloadTestButlerAPK();
|
||||
}
|
||||
}
|
||||
|
||||
function downloadTestButlerAPK() {
|
||||
const version = '2.2.1';
|
||||
const artifactUrl = `https://repo1.maven.org/maven2/com/linkedin/testbutler/test-butler-app/${version}/test-butler-app-${version}.apk`;
|
||||
const filePath = `./cache/test-butler-app.apk`;
|
||||
|
||||
fs.ensureDirSync('./cache');
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.log(`\nDownloading Test-Butler APK v${version}...`);
|
||||
execSync(`curl -f -o ${filePath} ${artifactUrl}`);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveSelectedConfiguration() {
|
||||
const { configurations } = require('../.detoxrc.json');
|
||||
const configName = process.env.DETOX_CONFIGURATION;
|
||||
return configurations[configName];
|
||||
}
|
||||
|
||||
// TODO eventually, this should be made available by Detox more explicitly
|
||||
function isAndroidConfig(config) {
|
||||
return [config.type, process.env.DETOX_CONFIGURATION, config.device].some(s => `${s}`.includes('android'));
|
||||
}
|
||||
|
||||
module.exports = globalSetup;
|
||||
@@ -1,7 +0,0 @@
|
||||
const detox = require('detox');
|
||||
|
||||
async function globalTeardown() {
|
||||
await detox.globalCleanup();
|
||||
}
|
||||
|
||||
module.exports = globalTeardown;
|
||||
@@ -1,41 +0,0 @@
|
||||
const { configureToMatchImageSnapshot } = require('jest-image-snapshot');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const kebabCase = require('lodash/kebabCase');
|
||||
const {expect} = require('expect');
|
||||
|
||||
|
||||
const toMatchImage = configureToMatchImageSnapshot({
|
||||
comparisonMethod: 'ssim', failureThreshold: 0.002, failureThresholdType: 'percent'
|
||||
});
|
||||
|
||||
|
||||
expect.extend({ toMatchImage });
|
||||
|
||||
expect.extend({
|
||||
async toMatchImageSnapshot(screenName) {
|
||||
const platform = await device.getPlatform();
|
||||
const deviceName = await device.name.split(' ').slice(1).join ('') ;
|
||||
const deviceType = 'iPhone 11 Pro' //JSON.parse(deviceName).type.replace(',','');
|
||||
|
||||
const SNAPSHOTS_DIR = `__image_snapshots__/${platform}/${deviceType}`;
|
||||
|
||||
const { testPath, currentTestName } = this;
|
||||
|
||||
const customSnapshotsDir = path.join(path.dirname(testPath), SNAPSHOTS_DIR);
|
||||
const customSnapshotIdentifier = kebabCase(`${path.basename(testPath)}-${currentTestName}-${screenName}`)
|
||||
|
||||
const tempPath = await device.takeScreenshot(screenName);
|
||||
const image = fs.readFileSync(tempPath);
|
||||
expect(image).toMatchImage({ customSnapshotIdentifier, customSnapshotsDir });
|
||||
|
||||
return { pass: true }
|
||||
},
|
||||
});
|
||||
|
||||
global.jestExpect = expect
|
||||
|
||||
|
||||
beforeAll(async () => {
|
||||
await device.launchApp();
|
||||
});
|
||||
+1
-1
@@ -640,7 +640,7 @@ SPEC CHECKSUMS:
|
||||
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
||||
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||
glog: 997518ea2aa2d8cd5df9797b641b758d52ecf2bc
|
||||
glog: 36ce0530c6d2c3a5a4326885ef4069564887a1db
|
||||
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
|
||||
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
|
||||
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
65F6941A25780A4F00A45E76 /* Bridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F6941825780A4F00A45E76 /* Bridge.swift */; };
|
||||
65F6941B25780A4F00A45E76 /* Bridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F6941825780A4F00A45E76 /* Bridge.swift */; };
|
||||
70ADBB5ECF934DCF8A0E4919 /* Inter-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 1426DF592BA248FC81D955CB /* Inter-Regular.otf */; };
|
||||
715D8132290BE850006F5C88 /* UbuntuMono-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 715D8131290BE850006F5C88 /* UbuntuMono-Regular.ttf */; };
|
||||
715D8133290BE850006F5C88 /* UbuntuMono-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 715D8131290BE850006F5C88 /* UbuntuMono-Regular.ttf */; };
|
||||
74B758FC20D7C00B003343C3 /* launch-image-universal.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */; };
|
||||
8391E8E0E93C41A98AAA6631 /* Inter-SemiBoldItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = A4F2BBE8D4DD4140A6CCAC39 /* Inter-SemiBoldItalic.otf */; };
|
||||
A0093AB50DA85E1D01818CCA /* libPods-Status-StatusIm-StatusImTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E88D313E5D854BE6BC81FC1 /* libPods-Status-StatusIm-StatusImTests.a */; };
|
||||
@@ -121,6 +123,7 @@
|
||||
65F6941725780A4E00A45E76 /* StatusImTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StatusImTests-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
65F6941825780A4F00A45E76 /* Bridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bridge.swift; sourceTree = "<group>"; };
|
||||
693A62DB37BC4CD5A30E5C96 /* Inter-SemiBold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-SemiBold.otf"; path = "../resources/fonts/Inter-SemiBold.otf"; sourceTree = "<group>"; };
|
||||
715D8131290BE850006F5C88 /* UbuntuMono-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "UbuntuMono-Regular.ttf"; path = "../resources/fonts/UbuntuMono-Regular.ttf"; sourceTree = "<group>"; };
|
||||
74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "launch-image-universal.storyboard"; sourceTree = "<group>"; };
|
||||
7AFBE28450C0239119FBDBA2 /* Pods-Status-StatusIm-StatusImTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm-StatusImTests.debug.xcconfig"; path = "Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
8B9A886A2CB448B1ABA0EB62 /* libc++.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
@@ -229,6 +232,7 @@
|
||||
693A62DB37BC4CD5A30E5C96 /* Inter-SemiBold.otf */,
|
||||
A4F2BBE8D4DD4140A6CCAC39 /* Inter-SemiBoldItalic.otf */,
|
||||
9C76AF5A418D4D65A4CAD1D9 /* InterStatus-Regular.otf */,
|
||||
715D8131290BE850006F5C88 /* UbuntuMono-Regular.ttf */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -475,6 +479,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74B758FC20D7C00B003343C3 /* launch-image-universal.storyboard in Resources */,
|
||||
715D8132290BE850006F5C88 /* UbuntuMono-Regular.ttf in Resources */,
|
||||
B2F2D1BC1D9D531B00B7B453 /* Images.xcassets in Resources */,
|
||||
D84616FB563A48EBB1678699 /* Inter-Bold.otf in Resources */,
|
||||
D99C50E5E18942A39C8DDF61 /* Inter-BoldItalic.otf in Resources */,
|
||||
@@ -493,6 +498,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3AAD2ACA24A3A60E0075D594 /* launch-image-universal.storyboard in Resources */,
|
||||
715D8133290BE850006F5C88 /* UbuntuMono-Regular.ttf in Resources */,
|
||||
3AAD2ACB24A3A60E0075D594 /* Images.xcassets in Resources */,
|
||||
3AAD2ACC24A3A60E0075D594 /* Inter-Bold.otf in Resources */,
|
||||
3AAD2ACD24A3A60E0075D594 /* Inter-BoldItalic.otf in Resources */,
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
<string>Inter-Thin-BETA.otf</string>
|
||||
<string>Inter-ThinItalic-BETA.otf</string>
|
||||
<string>InterStatus-Regular.otf</string>
|
||||
<string>UbuntuMono-Regular.ttf</string>
|
||||
</array>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
<string>Inter-Thin-BETA.otf</string>
|
||||
<string>Inter-ThinItalic-BETA.otf</string>
|
||||
<string>InterStatus-Regular.otf</string>
|
||||
<string>UbuntuMono-Regular.ttf</string>
|
||||
</array>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
|
||||
+3
-9
@@ -10,11 +10,7 @@
|
||||
"app:compile:android": "shadow-cljs compile android",
|
||||
"app:watch": "shadow-cljs watch android",
|
||||
"app:packager": "react-native start --host 0.0.0.0 --port 8081",
|
||||
"app:android": "react-native run-android",
|
||||
"detox": "detox build --configuration ios.sim.debug",
|
||||
"visual-test": "detox test --configuration ios.sim.debug --config e2e/config.json",
|
||||
"help": "detox test -- --help"
|
||||
|
||||
"app:android": "react-native run-android"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
@@ -74,6 +70,7 @@
|
||||
"react-native-svg": "^9.8.4",
|
||||
"react-native-touch-id": "^4.4.1",
|
||||
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#refs/tags/v11.16.0-status",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"rn-emoji-keyboard": "git+https://github.com/status-im/rn-emoji-keyboard.git#refs/tags/v0.4.3",
|
||||
"tdigest": "^0.1.1"
|
||||
},
|
||||
@@ -84,10 +81,7 @@
|
||||
"@babel/preset-env": "7.1.0",
|
||||
"@babel/register": "7.0.0",
|
||||
"@mapbox/node-pre-gyp": "^1.0.9",
|
||||
"@types/jest": "^28.1.6",
|
||||
"detox": "^19.9.1",
|
||||
"jest-image-snapshot": "^5.1.0",
|
||||
"jest": "^28.1.3",
|
||||
"jest": "^25.1.0",
|
||||
"nodemon": "^2.0.16",
|
||||
"nyc": "^14.1.1",
|
||||
"process": "0.11.10",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 246 B |
Binary file not shown.
|
Before Width: | Height: | Size: 972 B After Width: | Height: | Size: 286 B |
@@ -4,40 +4,50 @@
|
||||
[quo.haptic :as haptic]
|
||||
[quo.gesture-handler :as gh]
|
||||
[quo.design-system.spacing :as spacing]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.components.text :as text]
|
||||
[quo.design-system.colors :as quo.colors]
|
||||
[clojure.string :as string]
|
||||
[quo.components.controls.view :as controls]
|
||||
[quo.components.tooltip :as tooltip]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.icon :as quo2.icons]
|
||||
[quo.components.animated.pressable :as animated]))
|
||||
|
||||
(defn- icons-lib [icon-name props]
|
||||
(if (-> icon-name
|
||||
namespace
|
||||
(string/includes? "main-icons2"))
|
||||
[quo2.icons/icon icon-name props]
|
||||
[icons/icon icon-name props]))
|
||||
|
||||
(defn themes [theme]
|
||||
(case theme
|
||||
:main {:icon-color (:icon-04 @colors/theme)
|
||||
:icon-bg-color (:interactive-02 @colors/theme)
|
||||
:active-background (:interactive-02 @colors/theme)
|
||||
:passive-background (:ui-background @colors/theme)
|
||||
:text-color (:text-01 @colors/theme)}
|
||||
:accent {:icon-color (:icon-04 @colors/theme)
|
||||
:icon-bg-color (:interactive-02 @colors/theme)
|
||||
:active-background (:interactive-02 @colors/theme)
|
||||
:passive-background (:ui-background @colors/theme)
|
||||
:text-color (:text-04 @colors/theme)}
|
||||
:negative {:icon-color (:negative-01 @colors/theme)
|
||||
:icon-bg-color (:negative-02 @colors/theme)
|
||||
:active-background (:negative-02 @colors/theme)
|
||||
:passive-background (:ui-background @colors/theme)
|
||||
:text-color (:negative-01 @colors/theme)}
|
||||
:positive {:icon-color (:positive-01 @colors/theme)
|
||||
:icon-bg-color (:positive-02 @colors/theme)
|
||||
:active-background (:positive-02 @colors/theme)
|
||||
:passive-background (:ui-background @colors/theme)
|
||||
:text-color (:positive-01 @colors/theme)}
|
||||
:disabled {:icon-color (:icon-02 @colors/theme)
|
||||
:icon-bg-color (:ui-01 @colors/theme)
|
||||
:active-background (:ui-01 @colors/theme)
|
||||
:passive-background (:ui-background @colors/theme)
|
||||
:text-color (:text-02 @colors/theme)}))
|
||||
:main {:icon-color (:icon-04 @quo.colors/theme)
|
||||
:icon-bg-color (:interactive-02 @quo.colors/theme)
|
||||
:active-background (:interactive-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:text-01 @quo.colors/theme)}
|
||||
:accent {:icon-color (:icon-04 @quo.colors/theme)
|
||||
:icon-bg-color (:interactive-02 @quo.colors/theme)
|
||||
:active-background (:interactive-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:text-04 @quo.colors/theme)}
|
||||
:negative {:icon-color (:negative-01 @quo.colors/theme)
|
||||
:icon-bg-color (:negative-02 @quo.colors/theme)
|
||||
:active-background (:negative-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:negative-01 @quo.colors/theme)}
|
||||
:positive {:icon-color (:positive-01 @quo.colors/theme)
|
||||
:icon-bg-color (:positive-02 @quo.colors/theme)
|
||||
:active-background (:positive-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:positive-01 @quo.colors/theme)}
|
||||
:disabled {:icon-color (:icon-02 @quo.colors/theme)
|
||||
:icon-bg-color (:ui-01 @quo.colors/theme)
|
||||
:active-background (:ui-01 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:text-02 @quo.colors/theme)}))
|
||||
|
||||
(defn size->icon-size [size]
|
||||
(case size
|
||||
@@ -51,13 +61,13 @@
|
||||
|
||||
(defn size->single-title-size [size]
|
||||
(case size
|
||||
:small :base
|
||||
:large))
|
||||
:small :paragraph-1
|
||||
:paragraph-1))
|
||||
|
||||
(defn container [{:keys [size container-style]} & children]
|
||||
(into [rn/view {:style (merge (:tiny spacing/padding-horizontal)
|
||||
(defn container [{:keys [size container-style container-padding-horizontal container-padding-vertical]} & children]
|
||||
(into [rn/view {:style (merge (or container-padding-horizontal (:tiny spacing/padding-horizontal))
|
||||
{:min-height (size->container-size size)
|
||||
:padding-vertical 8
|
||||
:padding-vertical (or container-padding-vertical 8)
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between} container-style)}]
|
||||
@@ -78,17 +88,18 @@
|
||||
:justify-content :center
|
||||
:border-radius (/ icon-size 2)
|
||||
:background-color icon-bg-color}}
|
||||
[icons/icon icon {:color icon-color}]])])))
|
||||
(icons-lib icon {:color icon-color})])])))
|
||||
|
||||
(defn title-column
|
||||
[{:keys [title text-color subtitle subtitle-max-lines subtitle-secondary
|
||||
title-accessibility-label size text-size title-text-weight
|
||||
right-side-present?]}]
|
||||
[rn/view {:style (merge (:tiny spacing/padding-horizontal)
|
||||
right-side-present? title-column-style]}]
|
||||
[rn/view {:style (or title-column-style
|
||||
(merge (:tiny spacing/padding-horizontal)
|
||||
;; make left-side title grow if nothing is present on right-side
|
||||
(when-not right-side-present?
|
||||
{:flex 1
|
||||
:justify-content :center}))}
|
||||
(when-not right-side-present?
|
||||
{:flex 1
|
||||
:justify-content :center})))}
|
||||
(cond
|
||||
|
||||
(and title subtitle)
|
||||
@@ -109,6 +120,7 @@
|
||||
:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :tail
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
subtitle]
|
||||
@@ -116,6 +128,7 @@
|
||||
:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :middle
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
"•"]
|
||||
@@ -123,6 +136,7 @@
|
||||
:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :middle
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
subtitle-secondary]]
|
||||
@@ -130,6 +144,7 @@
|
||||
[text/text {:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :tail
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
subtitle]
|
||||
@@ -184,19 +199,19 @@
|
||||
accessory)]
|
||||
(when (and chevron platform/ios?)
|
||||
[rn/view {:style {:padding-right (:tiny spacing/spacing)}}
|
||||
[icons/icon :main-icons/next {:container-style {:opacity 0.4
|
||||
(icons-lib :main-icons/next {:container-style {:opacity 0.4
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
:resize-mode :center
|
||||
:color (:icon-02 @colors/theme)}]])]))
|
||||
:color (:icon-02 @quo.colors/theme)})])]))
|
||||
|
||||
(defn list-item
|
||||
[{:keys [theme accessory disabled subtitle-max-lines icon icon-container-style
|
||||
left-side-alignment icon-color icon-bg-color
|
||||
left-side-alignment icon-color icon-bg-color title-column-style
|
||||
title subtitle subtitle-secondary active on-press on-long-press chevron size text-size
|
||||
accessory-text accessibility-label title-accessibility-label accessory-style
|
||||
haptic-feedback haptic-type error animated animated-accessory? title-text-weight container-style
|
||||
active-background-enabled background-color]
|
||||
active-background-enabled background-color container-padding-horizontal container-padding-vertical]
|
||||
:or {subtitle-max-lines 1
|
||||
theme :main
|
||||
haptic-feedback true
|
||||
@@ -236,7 +251,7 @@
|
||||
{:on-long-press (fn []
|
||||
(optional-haptic)
|
||||
(on-long-press))}))
|
||||
[container {:size size :container-style container-style}
|
||||
[container {:size size :container-style container-style :container-padding-vertical container-padding-vertical :container-padding-horizontal container-padding-horizontal }
|
||||
[left-side {:icon-color icon-color
|
||||
:text-color (if on-press
|
||||
text-color
|
||||
@@ -253,7 +268,8 @@
|
||||
:subtitle subtitle
|
||||
:subtitle-max-lines subtitle-max-lines
|
||||
:subtitle-secondary subtitle-secondary
|
||||
:right-side-present? (or accessory chevron)}]
|
||||
:right-side-present? (or accessory chevron)
|
||||
:title-column-style title-column-style}]
|
||||
[right-side {:chevron chevron
|
||||
:active active
|
||||
:disabled disabled
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
const data = require('./visual-tests.json')
|
||||
|
||||
const waitToNavigate = duration => new Promise(resolve => setTimeout(() => resolve(), duration));
|
||||
|
||||
describe('Example (hello)', () => {
|
||||
beforeAll(async () => {
|
||||
if (device.getPlatform() === 'ios') {
|
||||
await device.setStatusBar({ time: '12:34', dataNetwork: 'wifi', wifiBars: '3', batteryState: 'charging', batteryLevel: '100' });
|
||||
}
|
||||
await device.reloadReactNative();
|
||||
|
||||
await element(by.text('I accept Status Terms of Use')).tap();
|
||||
// close alert
|
||||
await element(by.text('Get started')).tap();
|
||||
await waitToNavigate(200);
|
||||
|
||||
await element(by.text('Generate keys')).tap();
|
||||
await waitToNavigate(200);
|
||||
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
// await element(by.text('Password...')).typeText('infinitbility@gmail.com');
|
||||
// await element(by.text('Confirm your password...')).typeText('infinitbility@gmail.com');
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.text('Maybe later')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.text("Let's go")).tap();
|
||||
await waitToNavigate(700);
|
||||
|
||||
await element(by.text("1")).tap();
|
||||
await waitToNavigate(400);
|
||||
await element(by.text("Quo2.0 Preview")).tap();
|
||||
await waitToNavigate(400);
|
||||
})
|
||||
beforeEach(async () => {
|
||||
});
|
||||
afterEach(async () => {
|
||||
await element(by.text("1")).tap();
|
||||
await waitToNavigate(200);
|
||||
await element(by.text("Quo2.0 Preview")).tap();
|
||||
await waitToNavigate(200);
|
||||
});
|
||||
|
||||
const pages = Object.keys(data)
|
||||
|
||||
it(`button page should match snapshot`, async () => {
|
||||
await element(by.text(`:button`)).tap();
|
||||
await waitToNavigate(200);
|
||||
const res = await jestExpect(`default-render-button`).toMatchImageSnapshot();
|
||||
})
|
||||
|
||||
});
|
||||
@@ -0,0 +1,154 @@
|
||||
(ns quo2.components.code.snippet
|
||||
(:require ["react-native" :as react-native]
|
||||
["react-syntax-highlighter" :default Highlighter]
|
||||
[cljs-bean.core :as bean]
|
||||
[clojure.string :as str]
|
||||
[oops.core :as oops]
|
||||
[quo.react-native :as rn]
|
||||
[quo.theme :as theme]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.components.react :as react]))
|
||||
|
||||
;; Example themes:
|
||||
;; https://github.com/react-syntax-highlighter/react-syntax-highlighter/tree/master/src/styles/hljs
|
||||
(def ^:private themes
|
||||
{:light {:hljs-comment {:color colors/neutral-40},
|
||||
:hljs-title {:color (colors/custom-color :blue 50)},
|
||||
:hljs-keyword {:color (colors/custom-color :green 50)},
|
||||
:hljs-string {:color (colors/custom-color :turquoise 50)},
|
||||
:hljs-literal {:color (colors/custom-color :turquoise 50)}
|
||||
:hljs-number {:color (colors/custom-color :turquoise 50)}
|
||||
:line-number {:color colors/neutral-40}}
|
||||
:dark {:hljs-comment {:color colors/neutral-60},
|
||||
:hljs-title {:color (colors/custom-color :blue 60)},
|
||||
:hljs-keyword {:color (colors/custom-color :green 60)},
|
||||
:hljs-string {:color (colors/custom-color :turquoise 60)},
|
||||
:hljs-literal {:color (colors/custom-color :turquoise 60)}
|
||||
:hljs-number {:color (colors/custom-color :turquoise 60)}
|
||||
:line-number {:color colors/neutral-40}}})
|
||||
|
||||
(defn- text-style [class-names]
|
||||
(->> class-names
|
||||
(map keyword)
|
||||
(reduce #(merge %1 (get-in themes [(theme/get-theme) %2]))
|
||||
{:flex-shrink 1
|
||||
;; Round to a nearest whole number to achieve consistent
|
||||
;; spacing (also important for calculating `max-text-height`).
|
||||
;; Line height seems to be inconsistent between text being
|
||||
;; wrapped and text being rendered on a newline using Flexbox
|
||||
;; layout.
|
||||
:line-height 18})))
|
||||
|
||||
(defn- render-nodes [nodes]
|
||||
(map (fn [{:keys [children value] :as node}]
|
||||
;; Node can have :children or a :value.
|
||||
(if children
|
||||
(into [text/text {:weight :code
|
||||
:size :paragraph-2
|
||||
:style (text-style (get-in node [:properties :className]))}]
|
||||
(render-nodes children))
|
||||
;; Remove newlines as we already render each line separately.
|
||||
(-> value str/trim-newline)))
|
||||
nodes))
|
||||
|
||||
(defn- code-block [{:keys [rows line-number-width]}]
|
||||
[into [:<>]
|
||||
(->> rows
|
||||
(render-nodes)
|
||||
;; Line numbers
|
||||
(map-indexed (fn [idx row]
|
||||
(conj [rn/view {:style {:flex-direction :row}}
|
||||
[rn/view {:style {:width line-number-width
|
||||
;; 8+12 margin
|
||||
:margin-right 20}}
|
||||
[text/text {:weight :code
|
||||
:size :paragraph-2
|
||||
:style (text-style ["line-number"])}
|
||||
(inc idx)]]]
|
||||
row))))])
|
||||
|
||||
(defn- native-renderer []
|
||||
(let [text-height (reagent/atom nil)]
|
||||
(fn [{:keys [rows max-lines on-copy-press]}]
|
||||
(let [background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-80-opa-40)
|
||||
background-color-left (colors/theme-colors
|
||||
colors/neutral-5
|
||||
colors/neutral-80)
|
||||
border-color (colors/theme-colors
|
||||
colors/neutral-20
|
||||
colors/neutral-80)
|
||||
rows (bean/->clj rows)
|
||||
font-scale (:font-scale (rn/use-window-dimensions))
|
||||
max-rows (or max-lines (count rows)) ;; Cut down on rows to process.
|
||||
max-line-digits (-> rows count (min max-rows) str count)
|
||||
;; ~ 9 is char width, 18 is width used in Figma.
|
||||
line-number-width (* font-scale (max 18 (* 9 max-line-digits)))
|
||||
max-text-height (some-> max-lines (* font-scale 18)) ;; 18 is font's line height.
|
||||
truncated? (and max-text-height (< max-text-height @text-height))
|
||||
maybe-mask-wrapper (if truncated?
|
||||
[react/masked-view
|
||||
{:mask-element
|
||||
(reagent/as-element
|
||||
[react/linear-gradient {:colors ["black" "transparent"]
|
||||
:locations [0.75 1]
|
||||
:style {:flex 1}}])}]
|
||||
[:<>])]
|
||||
|
||||
[rn/view {:style {:overflow :hidden
|
||||
:padding 8
|
||||
:background-color background-color
|
||||
:border-color border-color
|
||||
:border-width 1
|
||||
:border-radius 8
|
||||
;; Hide on intial render to avoid flicker when mask-wrapper is shown.
|
||||
:opacity (if @text-height 1 0)}}
|
||||
;; Line number container
|
||||
[rn/view {:style {:position :absolute
|
||||
:bottom 0
|
||||
:top 0
|
||||
:left 0
|
||||
:width (+ line-number-width 8 8)
|
||||
:background-color background-color-left
|
||||
:border-right-color border-color
|
||||
:border-right-width 1}}]
|
||||
(conj maybe-mask-wrapper [rn/view {:max-height max-text-height}
|
||||
[rn/view {:on-layout (fn [evt]
|
||||
(let [height (oops/oget evt "nativeEvent.layout.height")]
|
||||
(reset! text-height height)))}
|
||||
[code-block {:rows (take max-rows rows)
|
||||
:line-number-width line-number-width}]]])
|
||||
|
||||
;; Copy button
|
||||
[rn/view {:style {:position :absolute
|
||||
:bottom 8
|
||||
:right 8}}
|
||||
[button/button {:icon true
|
||||
:type :grey
|
||||
:size 24
|
||||
:on-press on-copy-press}
|
||||
:main-icons/copy]]]))))
|
||||
|
||||
(defn- wrap-renderer-fn [f {:keys [max-lines on-copy-press]}]
|
||||
(fn [^js props]
|
||||
(reagent/as-element [:f> f {:rows (.-rows props)
|
||||
:max-lines max-lines
|
||||
:on-copy-press on-copy-press}])))
|
||||
|
||||
(defn snippet [{:keys [language max-lines on-copy-press]} children]
|
||||
[:> Highlighter {:language language
|
||||
:renderer (wrap-renderer-fn
|
||||
native-renderer {:max-lines max-lines
|
||||
:on-copy-press #(when on-copy-press
|
||||
(on-copy-press children))})
|
||||
;; Default props to adapt Highlighter for react-native.
|
||||
:CodeTag react-native/View
|
||||
:PreTag react-native/View
|
||||
:show-line-numbers false
|
||||
:style #js {}
|
||||
:custom-style #js {:backgroundColor nil}}
|
||||
children])
|
||||
@@ -5,13 +5,14 @@
|
||||
[quo2.foundations.typography :as typography]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn text-style [{:keys [size align weight style]}]
|
||||
(defn text-style [{:keys [size align weight style secondary-color]}]
|
||||
(merge (case (or weight :regular)
|
||||
:regular typography/font-regular
|
||||
:medium typography/font-medium
|
||||
:semi-bold typography/font-semi-bold
|
||||
:bold typography/font-bold
|
||||
:monospace typography/monospace
|
||||
:code typography/code
|
||||
:inherit nil)
|
||||
(case (or size :paragraph-1)
|
||||
:label typography/label
|
||||
@@ -23,7 +24,8 @@
|
||||
{:text-align (or align :auto)}
|
||||
(if (:color style)
|
||||
style
|
||||
(assoc style :color (if (= (theme/get-theme) :dark) colors/white colors/neutral-100)))))
|
||||
(assoc style :color (or secondary-color
|
||||
(colors/theme-colors colors/neutral-100 colors/white))))))
|
||||
|
||||
(defn text []
|
||||
(let [this (reagent/current-component)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[quo.react-native :as rn]
|
||||
[quo.theme :as theme]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[status-im.ui.components.icons.icons :as icons]))
|
||||
[quo2.components.icon :as icons]))
|
||||
|
||||
(def themes {:light {:background-color colors/neutral-20}
|
||||
:dark {:background-color colors/neutral-80}})
|
||||
@@ -76,23 +76,19 @@
|
||||
:or
|
||||
{size :small border-color (colors/custom-color-by-theme :purple 50 60)}}]
|
||||
|
||||
[tag {:size size
|
||||
[tag {:size size
|
||||
:token-img-src token-img-src
|
||||
:border-color (when is-required border-color)
|
||||
:border-color (when is-required border-color)
|
||||
:overlay
|
||||
(when (or is-required is-purchasable)
|
||||
[rn/view
|
||||
{:style (merge icon-container-styles
|
||||
{:width 15.5
|
||||
:height 15.5
|
||||
:background-color border-color
|
||||
:border-color (if (= (theme/get-theme) :dark) colors/neutral-100 colors/white)
|
||||
:border-width 1
|
||||
:right (get-value-from-size size -3.75 -5.75)
|
||||
:bottom (get-value-from-size size (- 32 7.75 4) (- 24 7.75 2)) ; (- height (icon-height/2) spacing)
|
||||
})}
|
||||
[icons/icon (if is-required :main-icons2/required-checkmark12 :main-icons2/purchasable12)
|
||||
{:background-color border-color
|
||||
:border-color (if (= (theme/get-theme) :dark) colors/neutral-100 colors/white)
|
||||
:border-width 1
|
||||
:right (get-value-from-size size -3.75 -5.75)
|
||||
:bottom (get-value-from-size size (- 32 7.75 4) (- 24 7.75 2))})}
|
||||
[icons/icon (if is-required :main-icons2/hold :main-icons2/add)
|
||||
{:no-color true
|
||||
:width 13.5
|
||||
:height 13.5}]])}
|
||||
:size 12}]])}
|
||||
(str value " " token)]))
|
||||
|
||||
@@ -45,3 +45,5 @@
|
||||
(def font-bold {:font-family "Inter-Bold"}) ; 700
|
||||
|
||||
(def monospace {:font-family "InterStatus-Regular"})
|
||||
|
||||
(def code {:font-family "UbuntuMono-Regular"})
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
(ns quo2.screens.code.snippet
|
||||
(:require [quo.previews.preview :as preview]
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.code.snippet :as snippet]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(def go-example "func (s *Server) listenAndServe() {
|
||||
cfg := &tls.Config{Certificates: []tls.Certificate{*s.cert}, ServerName: s.hostname, MinVersion: tls.VersionTLS12}
|
||||
|
||||
// in case of restart, we should use the same port as the first start in order not to break existing links
|
||||
listener, err := tls.Listen(\"tcp\", s.getHost(), cfg)
|
||||
if err != nil {
|
||||
s.logger.Error(\"failed to start server, retrying\", zap.Error(err))
|
||||
s.ResetPort()
|
||||
err = s.Start()
|
||||
if err != nil {
|
||||
s.logger.Error(\"server start failed, giving up\", zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = s.SetPort(listener.Addr().(*net.TCPAddr).Port)
|
||||
if err != nil {
|
||||
s.logger.Error(\"failed to set Server.port\", zap.Error(err))
|
||||
return
|
||||
}
|
||||
}")
|
||||
|
||||
(def clojure-example "(defn request->xhrio-options
|
||||
[{:as request
|
||||
:keys [on-success on-failure]
|
||||
:or {on-success [:http-no-on-success]
|
||||
on-failure [:http-no-on-failure]}}]
|
||||
; wrap events in cljs-ajax callback
|
||||
(let [api (new goog.net.XhrIo)]
|
||||
(-> request
|
||||
(assoc
|
||||
:api api
|
||||
:handler (partial ajax-xhrio-handler
|
||||
#(dispatch (conj on-success %))
|
||||
#(dispatch (conj on-failure %))
|
||||
api))
|
||||
(dissoc :on-success :on-failure :on-request))))")
|
||||
|
||||
(def examples {:clojure {:language :clojure
|
||||
:text clojure-example}
|
||||
:go {:language :go
|
||||
:text go-example}})
|
||||
|
||||
(def descriptor [{:label "Language:"
|
||||
:key :language
|
||||
:type :select
|
||||
:options [{:key :clojure
|
||||
:value :clojure}
|
||||
{:key :go
|
||||
:value :go}]}
|
||||
{:label "Max lines:"
|
||||
:key :max-lines
|
||||
:type :text}
|
||||
{:label "Syntax highlight:"
|
||||
:key :syntax
|
||||
:type :boolean}])
|
||||
|
||||
(defn cool-preview []
|
||||
(let [state (reagent/atom {:language :clojure
|
||||
:max-lines ""
|
||||
:syntax true})]
|
||||
(fn []
|
||||
(let [language (if (:syntax @state) (:language @state) :text)
|
||||
text (-> (:language @state) examples :text)
|
||||
max-lines (as-> (:max-lines @state) max-lines
|
||||
(js/parseInt max-lines)
|
||||
(when-not (js/Number.isNaN max-lines)
|
||||
max-lines))]
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:style {:padding-bottom 150}}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view {:style {:padding-vertical 60
|
||||
:padding-horizontal 16}}
|
||||
[snippet/snippet {:language language
|
||||
:max-lines max-lines
|
||||
:on-copy-press #(js/alert %)}
|
||||
text]]]]))))
|
||||
|
||||
(defn preview-code-snippet []
|
||||
[rn/view {:background-color (colors/theme-colors colors/white colors/neutral-90)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:key-fn str}]])
|
||||
@@ -14,6 +14,7 @@
|
||||
[quo2.screens.avatars.wallet-user-avatar :as wallet-user-avatar]
|
||||
[quo2.screens.buttons.button :as button]
|
||||
[quo2.screens.buttons.dynamic-button :as dynamic-button]
|
||||
[quo2.screens.code.snippet :as code-snippet]
|
||||
[quo2.screens.counter.counter :as counter]
|
||||
[quo2.screens.community.community-card-view :as community-card]
|
||||
[quo2.screens.dividers.divider-label :as divider-label]
|
||||
@@ -76,6 +77,9 @@
|
||||
{:name :dynamic-button
|
||||
:insets {:top false}
|
||||
:component dynamic-button/preview-dynamic-button}]
|
||||
:code [{:name :snippet
|
||||
:insets {:top false}
|
||||
:component code-snippet/preview-code-snippet}]
|
||||
:community [{:name :community-cards
|
||||
:insets {:top false}
|
||||
:component community-card/preview-community-card}]
|
||||
|
||||
@@ -73,15 +73,15 @@
|
||||
(dissoc :members)))
|
||||
|
||||
(defn <-rpc-js [^js chat]
|
||||
(-> {:name (.-name chat)
|
||||
:description (.-description chat)
|
||||
:color (.-color chat)
|
||||
:emoji (.-emoji chat)
|
||||
:timestamp (.-timestamp chat)
|
||||
:alias (.-alias chat)
|
||||
:identicon (.-identicon chat)
|
||||
:muted (.-muted chat)
|
||||
:joined (.-joined chat)
|
||||
(-> {:name (.-name chat)
|
||||
:description (.-description chat)
|
||||
:color (.-color chat)
|
||||
:emoji (.-emoji chat)
|
||||
:timestamp (.-timestamp chat)
|
||||
:alias (.-alias chat)
|
||||
:identicon (.-identicon chat)
|
||||
:muted (.-muted chat)
|
||||
:joined (.-joined chat)
|
||||
|
||||
:chat-id (.-id chat)
|
||||
:community-id (.-communityId chat)
|
||||
@@ -98,7 +98,8 @@
|
||||
:last-clock-value (.-lastClockValue chat)
|
||||
:profile-public-key (.-profile chat)
|
||||
:highlight (.-highlight chat)
|
||||
:active (.-active chat)}
|
||||
:active (.-active chat)
|
||||
:members (types/js->clj (.-members chat))}
|
||||
rpc->type
|
||||
unmarshal-members))
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
(def members-added-type 3)
|
||||
|
||||
(defn member?
|
||||
[public-key {:keys [contacts]}]
|
||||
(contains? contacts public-key))
|
||||
[public-key {:keys [members contacts users]}]
|
||||
(let [members-list (into #{} (concat (keys users) contacts (map #(:id %) members)))]
|
||||
(contains? members-list public-key)))
|
||||
|
||||
(defn invited?
|
||||
[my-public-key {:keys [contacts]}]
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
(= view :add-new)
|
||||
(merge home.sheet/add-new)
|
||||
|
||||
(= view :add-new-sheet-view)
|
||||
(merge home.sheet/add-new-sheet)
|
||||
|
||||
(= view :keycard.login/more)
|
||||
(merge keycard/more-sheet)
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
[quo.core :as quo]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.ui.components.invite.views :as invite]))
|
||||
[status-im.ui.components.invite.views :as invite]
|
||||
[quo.theme :as theme]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn hide-sheet-and-dispatch [event]
|
||||
(re-frame/dispatch [:bottom-sheet/hide])
|
||||
@@ -57,5 +59,36 @@
|
||||
[invite/list-item
|
||||
{:accessibility-label :chats-menu-invite-friends-button}]])
|
||||
|
||||
(defn add-new-sheet-view []
|
||||
[react/view
|
||||
[quo/list-item
|
||||
{:theme :main
|
||||
:title (i18n/label :t/new-chat)
|
||||
:icon-bg-color :transparent
|
||||
:icon-container-style {:padding-horizontal 0}
|
||||
:container-padding-horizontal {:padding-horizontal 4}
|
||||
:container-padding-vertical 12
|
||||
:title-column-style {:margin-left 2}
|
||||
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:accessibility-label :start-a-new-chat
|
||||
:icon :main-icons2/new-message
|
||||
:on-press #(hide-sheet-and-dispatch [:open-modal :new-chat])}]
|
||||
[quo/list-item
|
||||
{:theme :main
|
||||
:title (i18n/label :t/add-a-contact)
|
||||
:icon-bg-color :transparent
|
||||
:icon-container-style {:padding-horizontal 0}
|
||||
:container-padding-horizontal {:padding-horizontal 4}
|
||||
:container-padding-vertical 12
|
||||
:title-column-style {:margin-left 2}
|
||||
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:accessibility-label :add-a-contact
|
||||
:subtitle (i18n/label :t/enter-a-chat-key)
|
||||
:icon :main-icons2/add-user
|
||||
:on-press #(hide-sheet-and-dispatch [:open-modal :new-contact])}]])
|
||||
|
||||
(def add-new-sheet
|
||||
{:content add-new-sheet-view})
|
||||
|
||||
(def add-new
|
||||
{:content add-new-view})
|
||||
|
||||
@@ -204,8 +204,11 @@
|
||||
(first @(re-frame/subscribe [:contacts/contact-two-names-by-identity chat-id])))])
|
||||
|
||||
(defn home-list-item [home-item opts]
|
||||
(let [{:keys [chat-id chat-name color group-chat muted emoji highlight edit? public? unviewed-messages-count contacts]} home-item
|
||||
background-color (when highlight (colors/get-color :interactive-02))]
|
||||
(let [{:keys [chat-id chat-name color group-chat muted emoji highlight edit? public? unviewed-messages-count contacts users members]} home-item
|
||||
background-color (when highlight (colors/get-color :interactive-02))
|
||||
group-members-public-keys (->> (concat (keys users) contacts (map #(:id %) members))
|
||||
(into #{})
|
||||
(remove nil?))]
|
||||
[react/touchable-opacity (merge {:style {:height 64 :background-color background-color}} opts)
|
||||
[:<>
|
||||
(when (pos? unviewed-messages-count)
|
||||
@@ -245,7 +248,7 @@
|
||||
:margin-right 4}}]
|
||||
[quo2.text/text {:weight :medium
|
||||
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-50 quo2.colors/neutral-40)}}
|
||||
(i18n/label :t/members-count {:count (count contacts)})]]
|
||||
(i18n/label :t/members-count {:count (count group-members-public-keys)})]]
|
||||
[quo2.text/text {:monospace true
|
||||
:weight :medium
|
||||
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-50 quo2.colors/neutral-40)}
|
||||
|
||||
@@ -323,11 +323,19 @@
|
||||
|
||||
(views/defview plus-button []
|
||||
(views/letsubs [logging-in? [:multiaccounts/login]]
|
||||
[components.plus-button/plus-button
|
||||
{:on-press (when-not logging-in?
|
||||
#(re-frame/dispatch [:bottom-sheet/show-sheet :add-new {}]))
|
||||
:loading logging-in?
|
||||
:accessibility-label :new-chat-button}]))
|
||||
[components.plus-button/plus-button
|
||||
{:on-press (when-not logging-in?
|
||||
#(re-frame/dispatch [:bottom-sheet/show-sheet :add-new {}]))
|
||||
:loading logging-in?
|
||||
:accessibility-label :new-chat-button}]))
|
||||
|
||||
(views/defview plus-button-new-messages []
|
||||
(views/letsubs [logging-in? [:multiaccounts/login]]
|
||||
[components.plus-button/plus-button
|
||||
{:on-press (when-not logging-in?
|
||||
#(re-frame/dispatch [:bottom-sheet/show-sheet :add-new-sheet-view {}]))
|
||||
:loading logging-in?
|
||||
:accessibility-label :new-chat-button}]))
|
||||
|
||||
(views/defview notifications-button []
|
||||
(views/letsubs [notif-count [:activity.center/notifications-count]]
|
||||
@@ -383,29 +391,27 @@
|
||||
:chat-icon chat-icon.styles/chat-icon-chat-list}]]))
|
||||
|
||||
(defn home []
|
||||
[:f>
|
||||
(fn []
|
||||
(quo.react/effect! #(re-frame/dispatch [:get-activity-center-notifications]))
|
||||
[rn/keyboard-avoiding-view {:style {:flex 1
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
|
||||
:ignore-offset true}
|
||||
[topbar/topbar {:navigation :none
|
||||
:use-insets true
|
||||
:background (colors/theme-colors colors/neutral-5 colors/neutral-95)
|
||||
:left-component [rn/view {:flex-direction :row :margin-left 20}
|
||||
[profile-button]]
|
||||
:right-component [rn/view {:flex-direction :row :margin-right 20}
|
||||
[scan-button]
|
||||
[qr-button]
|
||||
[notifications-button]]
|
||||
:border-bottom false}]
|
||||
[rn/view {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:margin-horizontal 20
|
||||
:margin-top 15
|
||||
:margin-bottom 20}
|
||||
[quo2.text/text {:size :heading-1 :weight :semi-bold} (i18n/label :t/messages)]
|
||||
[plus-button]]
|
||||
[chats-list]
|
||||
[tabbar/tabs-counts-subscriptions]])])
|
||||
[rn/keyboard-avoiding-view {:style {:flex 1
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
|
||||
:ignore-offset true}
|
||||
[topbar/topbar {:navigation :none
|
||||
:use-insets true
|
||||
:background (colors/theme-colors colors/neutral-5 colors/neutral-95)
|
||||
:left-component [rn/view {:flex-direction :row :margin-left 20}
|
||||
[profile-button]]
|
||||
:right-component [rn/view {:flex-direction :row :margin-right 20}
|
||||
[scan-button]
|
||||
[qr-button]
|
||||
[notifications-button]]
|
||||
:border-bottom false}]
|
||||
[rn/view {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:margin-horizontal 20
|
||||
:margin-top 15
|
||||
:margin-bottom 8}
|
||||
[quo2.text/text {:size :heading-1 :weight :semi-bold} (i18n/label :t/messages)]
|
||||
[plus-button-new-messages]]
|
||||
[chats-list]
|
||||
[tabbar/tabs-counts-subscriptions]])
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
(ns status-im.utils.number)
|
||||
(ns status-im.utils.number
|
||||
(:require [goog.string :as gstring]
|
||||
[goog.string.format]))
|
||||
|
||||
(defn naive-round
|
||||
"Quickly and naively round number `n` up to `decimal-places`.
|
||||
@@ -13,3 +15,61 @@
|
||||
(let [scale (Math/pow 10 decimal-places)]
|
||||
(/ (Math/round (* n scale))
|
||||
scale)))
|
||||
|
||||
(defn- caught-invalid-number []
|
||||
(throw (js/Error "Invalid Number")))
|
||||
|
||||
(defn- with-precision [precision input-number]
|
||||
(gstring/format (str "%." precision "f") input-number))
|
||||
|
||||
(defn- is-bad-number [number-string]
|
||||
(nil? (re-find #"^\d+(\.\d{1,9})?$" number-string)))
|
||||
|
||||
(defn- with-precision-division [numerator-num denominator-num precision]
|
||||
(->> (/ numerator-num denominator-num)
|
||||
(with-precision precision)))
|
||||
|
||||
(defn- number->formatted-number [number-string precision]
|
||||
(let [parsed-number (js/parseInt number-string 10)
|
||||
numeric-value (if (or (neg? number-string)
|
||||
(is-bad-number (str number-string)))
|
||||
(caught-invalid-number)
|
||||
parsed-number)
|
||||
million 1000000
|
||||
billion 1000000000
|
||||
>=-and-< #(and
|
||||
(>= %1 %2)
|
||||
(< %1 %3))
|
||||
unit (cond
|
||||
(>=-and-< parsed-number billion js/Number.MAX_SAFE_INTEGER) "b"
|
||||
(>=-and-< parsed-number million billion) "m"
|
||||
:else
|
||||
"k")
|
||||
denominator (cond
|
||||
(= unit "m") million
|
||||
(= unit "b") billion
|
||||
:else 1000)]
|
||||
(if (js/isNaN numeric-value)
|
||||
(caught-invalid-number)
|
||||
(if (>= numeric-value 1000)
|
||||
(str (with-precision-division numeric-value denominator precision)
|
||||
unit)
|
||||
(str numeric-value)))))
|
||||
|
||||
(defn format-number
|
||||
"Returns the thousands in a number in kilo format
|
||||
|
||||
Arguments:
|
||||
|
||||
number-string (or string int) The input of value of the number
|
||||
|
||||
Examples:
|
||||
[1000 0] -> 1k
|
||||
[1001 0] -> 1k
|
||||
[10000 0] -> 10k
|
||||
[5000 0] -> 5k
|
||||
[5000 0] -> 5k
|
||||
[5000000 0] -> 5m
|
||||
[5000 0] -> 5k"
|
||||
[number-string precision]
|
||||
(number->formatted-number number-string precision))
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
(ns status-im.utils.number-test
|
||||
(:require [cljs.test :refer-macros [deftest testing are]]
|
||||
[status-im.utils.number :as number]))
|
||||
|
||||
(deftest format-number-test
|
||||
(testing "Positive cases"
|
||||
(are [input-number precision expected] (= (number/format-number input-number precision) expected)
|
||||
"100" 0 "100"
|
||||
"1000" 0 "1k"
|
||||
"10000" 0 "10k"
|
||||
"11000" 1 "11.0k"
|
||||
"11000" 0 "11k"
|
||||
"11010" 3 "11.010k"
|
||||
"5200000" 3 "5.200m"
|
||||
"1000000000" 0 "1b"
|
||||
"1110000000" 2 "1.11b"
|
||||
"9000000" 0 "9m"))
|
||||
(testing "Negative cases"
|
||||
(are [input-number precision] (thrown-with-msg? js/Error #"Invalid Number" (number/format-number input-number precision))
|
||||
js/undefined 0
|
||||
nil 0
|
||||
"-1" 0
|
||||
"" 0
|
||||
js/NaN 0
|
||||
"1e3" 0
|
||||
"10,2" 0
|
||||
"6hello" 0)))
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "659ab120b66dca9521c93cbd8516582634059074",
|
||||
"commit-sha1": "659ab120b66dca9521c93cbd8516582634059074",
|
||||
"src-sha256": "1x5pasyf4ivrw92pil4ljl6cfw3g6wn4drgxxszcdzih0pwzggx4"
|
||||
"version": "bfab85f73bfa727db5b6e8078f9ce9ec191161ca",
|
||||
"commit-sha1": "bfab85f73bfa727db5b6e8078f9ce9ec191161ca",
|
||||
"src-sha256": "184zcv531cgwdg7zr7ryav7w9qwd90jgqb9nmmhy4l2pmcm1mlc9"
|
||||
}
|
||||
|
||||
@@ -1456,6 +1456,8 @@
|
||||
"set-custom-fee": "Set custom fee",
|
||||
"not-enough-snt": "Not enough SNT",
|
||||
"add-new-contact": "Add new contact",
|
||||
"add-a-contact": "Add a contact",
|
||||
"enter-a-chat-key": "Enter a chat key or scan a QR",
|
||||
"you-dont-have-contacts": "You don’t have any contacts yet.",
|
||||
"set-max": "Set max",
|
||||
"continue-anyway": "Continue anyway",
|
||||
|
||||
Reference in New Issue
Block a user