Skip to content

Commit f997426

Browse files
committed
Fix camera switching on scanner component
1 parent c174d6b commit f997426

File tree

1 file changed

+144
-75
lines changed

1 file changed

+144
-75
lines changed

client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx

Lines changed: 144 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import { default as Button } from "antd/es/button";
2-
import { default as Dropdown } from "antd/es/dropdown";
3-
import { default as Menu } from "antd/es/menu";
42
import { default as Skeleton } from "antd/es/skeleton";
53
import {
64
Button100,
@@ -14,16 +12,29 @@ import { DropdownStyle } from "comps/controls/styleControlConstants";
1412
import { withDefault } from "comps/generators";
1513
import { UICompBuilder } from "comps/generators/uiCompBuilder";
1614
import { CustomModal, Section, sectionNames } from "lowcoder-design";
17-
import styled from "styled-components";
18-
import { CommonNameConfig, NameConfig, withExposingConfigs } from "../../generators/withExposing";
19-
import { hiddenPropertyView, disabledPropertyView, showDataLoadingIndicatorsPropertyView } from "comps/utils/propertyUtils";
15+
import styled, { keyframes } from "styled-components";
16+
import {
17+
CommonNameConfig,
18+
NameConfig,
19+
withExposingConfigs,
20+
} from "../../generators/withExposing";
21+
import {
22+
hiddenPropertyView,
23+
disabledPropertyView,
24+
showDataLoadingIndicatorsPropertyView,
25+
} from "comps/utils/propertyUtils";
2026
import { trans } from "i18n";
21-
import React, { Suspense, useEffect, useRef, useState, useContext } from "react";
27+
import React, {
28+
Suspense,
29+
useEffect,
30+
useRef,
31+
useState,
32+
useContext,
33+
} from "react";
2234
import { arrayStringExposingStateControl } from "comps/controls/codeStateControl";
2335
import { BoolControl } from "comps/controls/boolControl";
24-
import type { ItemType } from "antd/es/menu/interface";
2536
import { RefControl } from "comps/controls/refControl";
26-
import { EditorContext } from "comps/editorState";
37+
import { EditorContext } from "comps/editorState";
2738

2839
const Error = styled.div`
2940
color: #f5222d;
@@ -51,6 +62,50 @@ const Wrapper = styled.div`
5162
}
5263
`;
5364

65+
const dropdownShow = keyframes`
66+
from {
67+
opacity: 0;
68+
transform: translateY(-8px) scaleY(0.98);
69+
}
70+
to {
71+
opacity: 1;
72+
transform: translateY(0) scaleY(1);
73+
}
74+
`;
75+
76+
const DropdownContainer = styled.div`
77+
position: absolute;
78+
top: 44px;
79+
right: 0;
80+
min-width: 150px;
81+
background: #fff;
82+
border: 1px solid #e0e0e0;
83+
border-radius: 8px;
84+
box-shadow:
85+
0 8px 24px rgba(0, 0, 0, 0.12),
86+
0 1.5px 3px rgba(0, 0, 0, 0.08);
87+
z-index: 1000;
88+
padding: 6px 0;
89+
animation: ${dropdownShow} 0.22s cubic-bezier(0.22, 1, 0.36, 1);
90+
transition: box-shadow 0.2s;
91+
`;
92+
93+
const DropdownItem = styled.div`
94+
padding: 10px 20px;
95+
cursor: pointer;
96+
font-size: 14px;
97+
color: #222;
98+
background: transparent;
99+
transition: background 0.15s;
100+
&:hover {
101+
background: #f0f5ff;
102+
color: #1677ff;
103+
}
104+
&:active {
105+
background: #e6f7ff;
106+
}
107+
`;
108+
54109
const CustomModalStyled = styled(CustomModal)`
55110
top: 10vh;
56111
.react-draggable {
@@ -59,7 +114,9 @@ const CustomModalStyled = styled(CustomModal)`
59114
}
60115
`;
61116

62-
const BarcodeScannerComponent = React.lazy(() => import("react-qr-barcode-scanner"));
117+
const BarcodeScannerComponent = React.lazy(
118+
() => import("react-qr-barcode-scanner")
119+
);
63120

64121
const ScannerTmpComp = (function () {
65122
const childrenMap = {
@@ -70,17 +127,20 @@ const ScannerTmpComp = (function () {
70127
maskClosable: withDefault(BoolControl, true),
71128
onEvent: ScannerEventHandlerControl,
72129
disabled: BoolCodeControl,
73-
style: styleControl(DropdownStyle, 'style'),
130+
style: styleControl(DropdownStyle, "style"),
74131
viewRef: RefControl<HTMLElement>,
75132
};
76133
return new UICompBuilder(childrenMap, (props) => {
77134
const [showModal, setShowModal] = useState(false);
78135
const [errMessage, setErrMessage] = useState("");
79-
const [videoConstraints, setVideoConstraints] = useState<MediaTrackConstraints>({
80-
facingMode: "environment",
81-
});
82-
const [modeList, setModeList] = useState<ItemType[]>([]);
83-
const [dropdownShow, setDropdownShow] = useState(false);
136+
const [videoConstraints, setVideoConstraints] =
137+
useState<MediaTrackConstraints>({
138+
facingMode: "environment",
139+
});
140+
const [modeList, setModeList] = useState<{ label: string; key: string }[]>(
141+
[]
142+
);
143+
const [handleDropdown, setHandleDropdown] = useState(false);
84144
const [success, setSuccess] = useState(false);
85145

86146
useEffect(() => {
@@ -92,7 +152,7 @@ const ScannerTmpComp = (function () {
92152
const continuousValue = useRef<string[]>([]);
93153

94154
const handleUpdate = (err: any, result: any) => {
95-
if (!!result) {
155+
if (result) {
96156
if (props.continuous) {
97157
continuousValue.current = [...continuousValue.current, result.text];
98158
const val = props.uniqueData
@@ -109,15 +169,16 @@ const ScannerTmpComp = (function () {
109169
setSuccess(false);
110170
}
111171
};
172+
112173
const handleErr = (err: any) => {
113174
if (typeof err === "string") {
114175
setErrMessage(err);
176+
} else if (
177+
err.message === "getUserMedia is not implemented in this browser"
178+
) {
179+
setErrMessage(trans("scanner.errTip"));
115180
} else {
116-
if (err.message === "getUserMedia is not implemented in this browser") {
117-
setErrMessage(trans("scanner.errTip"));
118-
} else {
119-
setErrMessage(err.message);
120-
}
181+
setErrMessage(err.message);
121182
}
122183
setSuccess(false);
123184
};
@@ -157,6 +218,8 @@ const ScannerTmpComp = (function () {
157218
onCancel={() => {
158219
setShowModal(false);
159220
props.onEvent("close");
221+
setVideoConstraints({ facingMode: "environment" });
222+
setHandleDropdown(false);
160223
}}
161224
>
162225
{!!errMessage ? (
@@ -173,36 +236,33 @@ const ScannerTmpComp = (function () {
173236
videoConstraints={videoConstraints}
174237
/>
175238
</Suspense>
176-
<div
177-
style={{ height: "42px" }}
178-
onClick={() => {
179-
setDropdownShow(false);
180-
}}
181-
>
182-
<Dropdown
183-
placement="bottomRight"
184-
trigger={["click"]}
185-
open={dropdownShow}
186-
onOpenChange={(value) => setDropdownShow(value)}
187-
dropdownRender={() => (
188-
<Menu
189-
items={modeList}
190-
onClick={(value) =>
191-
setVideoConstraints({ ...videoConstraints, deviceId: value.key })
192-
}
193-
/>
194-
)}
239+
240+
<div style={{ position: "relative", marginTop: 10 }}>
241+
<Button
242+
style={{ float: "right" }}
243+
onClick={() => {
244+
getModeList();
245+
setHandleDropdown(!handleDropdown);
246+
}}
195247
>
196-
<Button
197-
style={{ float: "right", marginTop: "10px" }}
198-
onClick={(e) => {
199-
e.stopPropagation();
200-
getModeList();
201-
}}
202-
>
203-
{trans("scanner.changeCamera")}
204-
</Button>
205-
</Dropdown>
248+
{trans("scanner.changeCamera")}
249+
</Button>
250+
251+
{handleDropdown && (
252+
<DropdownContainer>
253+
{modeList.map(({ key, label }) => (
254+
<DropdownItem
255+
key={key}
256+
onClick={() => {
257+
setVideoConstraints({ deviceId: { exact: key } });
258+
setHandleDropdown(false);
259+
}}
260+
>
261+
{label}
262+
</DropdownItem>
263+
))}
264+
</DropdownContainer>
265+
)}
206266
</div>
207267
</Wrapper>
208268
)
@@ -211,35 +271,44 @@ const ScannerTmpComp = (function () {
211271
</ButtonCompWrapper>
212272
);
213273
})
214-
.setPropertyViewFn((children) => {
215-
return (
216-
<>
217-
<Section name={sectionNames.basic}>
218-
{children.text.propertyView({ label: trans("text") })}
219-
</Section>
274+
.setPropertyViewFn((children) => (
275+
<>
276+
<Section name={sectionNames.basic}>
277+
{children.text.propertyView({ label: trans("text") })}
278+
</Section>
220279

221-
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (
222-
<><Section name={sectionNames.interaction}>
223-
{children.onEvent.getPropertyView()}
224-
{disabledPropertyView(children)}
225-
{hiddenPropertyView(children)}
226-
{showDataLoadingIndicatorsPropertyView(children)}
227-
</Section>
228-
<Section name={sectionNames.advanced}>
229-
{children.continuous.propertyView({ label: trans("scanner.continuous") })}
280+
{(useContext(EditorContext).editorModeStatus === "logic" ||
281+
useContext(EditorContext).editorModeStatus === "both") && (
282+
<>
283+
<Section name={sectionNames.interaction}>
284+
{children.onEvent.getPropertyView()}
285+
{disabledPropertyView(children)}
286+
{hiddenPropertyView(children)}
287+
{showDataLoadingIndicatorsPropertyView(children)}
288+
</Section>
289+
<Section name={sectionNames.advanced}>
290+
{children.continuous.propertyView({
291+
label: trans("scanner.continuous"),
292+
})}
230293
{children.continuous.getView() &&
231-
children.uniqueData.propertyView({ label: trans("scanner.uniqueData") })}
232-
{children.maskClosable.propertyView({ label: trans("scanner.maskClosable") })}
294+
children.uniqueData.propertyView({
295+
label: trans("scanner.uniqueData"),
296+
})}
297+
{children.maskClosable.propertyView({
298+
label: trans("scanner.maskClosable"),
299+
})}
233300
</Section>
234-
</>
235-
)}
301+
</>
302+
)}
236303

237-
{(useContext(EditorContext).editorModeStatus === "layout" || useContext(EditorContext).editorModeStatus === "both") && (
238-
<><Section name={sectionNames.style}>{children.style.getPropertyView()}</Section></>
239-
)}
240-
</>
241-
);
242-
})
304+
{(useContext(EditorContext).editorModeStatus === "layout" ||
305+
useContext(EditorContext).editorModeStatus === "both") && (
306+
<Section name={sectionNames.style}>
307+
{children.style.getPropertyView()}
308+
</Section>
309+
)}
310+
</>
311+
))
243312
.setExposeMethodConfigs(buttonRefMethods)
244313
.build();
245314
})();

0 commit comments

Comments
 (0)