-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve QR Code scan ability (#1036)
* qr scan library upgrade + google ML function * QR scan check bounce * add white border to QR code image for scanning support * typescript changes QRGen code * typescript fixes qrGen * update test snapshot QRCode * add test for QRGen * minor change; review changes * update QRGen test * revert google ml function for qr scan * update QRGen tests * update QRGen tests * qrGen minor fix * merge master * minor fix QRGen * remove stale snapshot qrGen * gradle fix qrGen
- Loading branch information
Showing
12 changed files
with
2,186 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import _QRCode from 'qrcode' | ||
import React, { PureComponent } from 'react' | ||
import Svg, { Path, Rect } from 'react-native-svg' | ||
|
||
export function genMatrix(value: any, errorCorrectionLevel: string) { | ||
const arr = Array.prototype.slice.call( | ||
_QRCode.create(value, { errorCorrectionLevel }).modules.data, | ||
0 | ||
) | ||
const sqrt = Math.sqrt(arr.length) | ||
return arr.reduce( | ||
(rows, key, index) => | ||
(index % sqrt === 0 ? rows.push([key]) : rows[rows.length - 1].push(key)) && rows, | ||
[] | ||
) | ||
} | ||
|
||
/* calculate the size of the cell and draw the path */ | ||
export function calculateMatrix(props: any) { | ||
const { value, size, ecl, onError } = props | ||
try { | ||
const reducedSize = size - 20 | ||
const matrix = genMatrix(value, ecl) | ||
const cellSize = reducedSize / matrix.length | ||
return { | ||
cellSize, | ||
path: transformMatrixIntoPath(cellSize, matrix), | ||
} | ||
} catch (error) { | ||
if (onError && typeof onError === 'function') { | ||
onError(error) | ||
} else { | ||
// Pass the error when no handler presented | ||
throw error | ||
} | ||
} | ||
return {} | ||
} | ||
|
||
/* project the matrix into path draw */ | ||
export function transformMatrixIntoPath(cellSize: number, matrix: any) { | ||
// adjust origin | ||
let d = '' | ||
matrix.forEach((row: any, i: number) => { | ||
let needDraw = false | ||
row.forEach((column: any, j: number) => { | ||
if (column) { | ||
if (!needDraw) { | ||
d += `M${cellSize * j + 10} ${cellSize / 2 + cellSize * i + 10} ` | ||
needDraw = true | ||
} | ||
if (needDraw && j === matrix.length - 1) { | ||
d += `L${cellSize * (j + 1) + 10} ${cellSize / 2 + cellSize * i + 10} ` | ||
} | ||
} else { | ||
if (needDraw) { | ||
d += `L${cellSize * j + 10} ${cellSize / 2 + cellSize * i + 10} ` | ||
needDraw = false | ||
} | ||
} | ||
}) | ||
}) | ||
return d | ||
} | ||
|
||
interface QRProps { | ||
value: string | ||
size: number | ||
color: string | ||
backgroundColor: string | ||
getRef: any | ||
ecl: string | ||
onError: any | ||
} | ||
|
||
interface QRState { | ||
cellSize?: number | undefined | ||
path?: string | undefined | ||
} | ||
|
||
/** | ||
* A simple component for displaying QR Code using svg | ||
*/ | ||
export default class QRCode extends PureComponent<QRProps, QRState> { | ||
static defaultProps = { | ||
value: 'This is a QR Code.', | ||
size: 100, | ||
color: 'black', | ||
backgroundColor: 'white', | ||
ecl: 'M', | ||
onError: undefined, | ||
} | ||
|
||
static getDerivedStateFromProps(props: any, state: any) { | ||
// if value has changed, re-calculateMatrix | ||
if (props.value !== state.value || props.size !== state.size) { | ||
return calculateMatrix(props) | ||
} | ||
return null | ||
} | ||
|
||
constructor(props: any) { | ||
super(props) | ||
this.state = calculateMatrix(props) | ||
} | ||
|
||
render() { | ||
const { getRef, size, color, backgroundColor } = this.props | ||
const { cellSize, path } = this.state | ||
return ( | ||
<Svg ref={getRef} width={size} height={size}> | ||
<Rect width={size} height={size} fill={backgroundColor} /> | ||
{path && cellSize && <Path d={path} stroke={color} strokeWidth={cellSize} />} | ||
</Svg> | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import * as React from 'react' | ||
import * as renderer from 'react-test-renderer' | ||
import QRCode, { genMatrix } from 'src/qrcode/QRGen' | ||
|
||
describe('QRCode', () => { | ||
it('renders correctly', () => { | ||
const tree = renderer.create(<QRCode value="celo" getRef={jest.fn()} />).toJSON() | ||
expect(tree).toMatchSnapshot() | ||
}) | ||
|
||
// Simulate big data passed to QRCode and check if onError Callback | ||
// Called properly | ||
it('calls onError in case of issue with code generating', () => { | ||
const onErrorMock = jest.fn() | ||
// Rendering with big amount of data that should | ||
// throw an exception | ||
renderer.create( | ||
<QRCode value={new Array(1000000).join('123')} onError={onErrorMock} getRef={jest.fn()} /> | ||
) | ||
expect(onErrorMock.mock.calls.length).toBe(2) | ||
}) | ||
|
||
it('does not call onError in case if value is fine', () => { | ||
const onErrorMock = jest.fn() | ||
renderer.create(<QRCode value="123" onError={onErrorMock} getRef={jest.fn()} />) | ||
expect(onErrorMock.mock.calls.length).toBe(0) | ||
}) | ||
}) | ||
|
||
describe('QRCode Matrix', () => { | ||
it('generates with ecl:M correctly', () => { | ||
const matrix = genMatrix('test', 'M') | ||
expect(matrix).toMatchSnapshot() | ||
}) | ||
|
||
it('generates with ecl:L correctly', () => { | ||
const matrix = genMatrix('test', 'L') | ||
expect(matrix).toMatchSnapshot() | ||
}) | ||
|
||
it('generates with ecl:H correctly', () => { | ||
const matrix = genMatrix('test', 'H') | ||
expect(matrix).toMatchSnapshot() | ||
}) | ||
|
||
it('generates with ecl:Q correctly', () => { | ||
const matrix = genMatrix('test', 'Q') | ||
expect(matrix).toMatchSnapshot() | ||
}) | ||
}) |
Oops, something went wrong.