@apps-in-toss/framework 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-presets.cjs +24 -0
- package/dist/cli-presets.d.cts +1 -0
- package/dist/cli-presets.js +1 -23
- package/dist/index.cjs +230 -0
- package/dist/index.d.cts +557 -0
- package/dist/index.d.ts +483 -1
- package/dist/index.js +152 -32
- package/package.json +24 -12
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,162 @@
|
|
|
1
|
+
import { EmitterSubscription } from 'react-native';
|
|
2
|
+
|
|
3
|
+
interface EventEmitterSchema<K extends string, P extends unknown[]> {
|
|
4
|
+
name: K;
|
|
5
|
+
params: P;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 위치 정확도 옵션이에요.
|
|
10
|
+
*/
|
|
11
|
+
declare enum Accuracy {
|
|
12
|
+
/**
|
|
13
|
+
* 오차범위 3KM 이내
|
|
14
|
+
*/
|
|
15
|
+
Lowest = 1,
|
|
16
|
+
/**
|
|
17
|
+
* 오차범위 1KM 이내
|
|
18
|
+
*/
|
|
19
|
+
Low = 2,
|
|
20
|
+
/**
|
|
21
|
+
* 오차범위 몇 백미터 이내
|
|
22
|
+
*/
|
|
23
|
+
Balanced = 3,
|
|
24
|
+
/**
|
|
25
|
+
* 오차범위 10M 이내
|
|
26
|
+
*/
|
|
27
|
+
High = 4,
|
|
28
|
+
/**
|
|
29
|
+
* 가장 높은 정확도
|
|
30
|
+
*/
|
|
31
|
+
Highest = 5,
|
|
32
|
+
/**
|
|
33
|
+
* 네비게이션을 위한 최고 정확도
|
|
34
|
+
*/
|
|
35
|
+
BestForNavigation = 6
|
|
36
|
+
}
|
|
37
|
+
interface Location {
|
|
38
|
+
/**
|
|
39
|
+
* Android에서만 지원하는 옵션이에요.
|
|
40
|
+
*
|
|
41
|
+
* - `FINE`: 정확한 위치
|
|
42
|
+
* - `COARSE`: 대략적인 위치
|
|
43
|
+
*
|
|
44
|
+
* @see https://developer.android.com/codelabs/approximate-location
|
|
45
|
+
*/
|
|
46
|
+
accessLocation?: 'FINE' | 'COARSE';
|
|
47
|
+
/**
|
|
48
|
+
* 위치가 업데이트된 시점의 유닉스 타임스탬프예요.
|
|
49
|
+
*/
|
|
50
|
+
timestamp: number;
|
|
51
|
+
coords: {
|
|
52
|
+
latitude: number;
|
|
53
|
+
longitude: number;
|
|
54
|
+
altitude: number;
|
|
55
|
+
accuracy: number;
|
|
56
|
+
altitudeAccuracy: number;
|
|
57
|
+
heading: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 사진 조회 결과를 나타내는 타입이에요.
|
|
62
|
+
*/
|
|
63
|
+
interface ImageResponse {
|
|
64
|
+
/** 가져온 사진의 고유 ID예요. */
|
|
65
|
+
id: string;
|
|
66
|
+
/** 사진의 데이터 URI예요. `base64` 옵션이 `true`인 경우 Base64 문자열로 반환돼요. */
|
|
67
|
+
dataUri: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface StartUpdateLocationOptions {
|
|
71
|
+
/**
|
|
72
|
+
* 위치 정확도를 설정해요.
|
|
73
|
+
*/
|
|
74
|
+
accuracy: Accuracy;
|
|
75
|
+
/**
|
|
76
|
+
* 위치 업데이트 주기를 밀리초(ms) 단위로 설정해요.
|
|
77
|
+
*/
|
|
78
|
+
timeInterval: number;
|
|
79
|
+
/**
|
|
80
|
+
* 위치 변경 거리를 미터(m) 단위로 설정해요.
|
|
81
|
+
*/
|
|
82
|
+
distanceInterval: number;
|
|
83
|
+
/**
|
|
84
|
+
* 위치 정보가 변경될 때 호출되는 콜백 함수예요.
|
|
85
|
+
*/
|
|
86
|
+
callback: (location: Location) => void;
|
|
87
|
+
}
|
|
88
|
+
interface StartUpdateLocationSubscription extends EmitterSubscription {
|
|
89
|
+
remove: () => Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* @name UpdateLocationEventEmitter
|
|
93
|
+
* @kind typedef
|
|
94
|
+
* @description
|
|
95
|
+
* 디바이스의 위치 정보 변경을 감지해요
|
|
96
|
+
* @extends {EventEmitterSchema<'updateLocation', [Location]>}
|
|
97
|
+
*/
|
|
98
|
+
interface UpdateLocationEventEmitter extends EventEmitterSchema<'updateLocation', [Location]> {
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* @public
|
|
102
|
+
* @tag AppsInTossModule
|
|
103
|
+
* @category AppsInTossModules
|
|
104
|
+
* @kind function
|
|
105
|
+
* @name startUpdateLocation
|
|
106
|
+
* @description 디바이스의 위치 정보를 지속적으로 감지하고, 위치가 변경되면 콜백을 실행하는 함수예요. 콜백 함수를 등록하면 위치가 변경될 때마다 자동으로 호출돼요.
|
|
107
|
+
* 실시간 위치 추적이 필요한 기능을 구현할 때 사용할 수 있어요. 예를 들어 지도 앱에서 사용자의 현재 위치를 실시간으로 업데이트할 때, 운동 앱에서 사용자의 이동 거리를 기록할 때 등이에요.
|
|
108
|
+
* 위치 업데이트 주기와 정확도를 조정해 배터리 소모를 최소화하면서도 필요한 정보를 얻을 수 있어요.
|
|
109
|
+
*
|
|
110
|
+
* @param {StartUpdateLocationOptions} options - 위치 정보 감지에 필요한 설정 객체에요.
|
|
111
|
+
* @param {number} [options.accuracy] 위치 정확도를 설정해요.
|
|
112
|
+
* @param {number} [options.timeInterval] 위치 정보를 업데이트하는 최소 주기로, 단위는 밀리초(ms)예요. 이 값은 위치 업데이트가 발생하는 가장 짧은 간격을 설정하지만, 시스템이나 환경의 영향을 받아 지정한 주기보다 더 긴 간격으로 업데이트될 수 있어요.
|
|
113
|
+
* @param {number} [options.distanceInterval] 위치 변경 거리를 미터(m) 단위로 설정해요.
|
|
114
|
+
* @param {(location: Location) => void} [options.callback] 위치 정보가 변경될 때 호출되는 콜백 함수예요.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ### 위치 정보 변경 감지하기
|
|
118
|
+
*
|
|
119
|
+
* ```tsx
|
|
120
|
+
* import React, { useState, useEffect } from 'react';
|
|
121
|
+
* import { View, Text, Button } from 'react-native';
|
|
122
|
+
* import { startUpdateLocation } from '@apps-in-toss/framework';
|
|
123
|
+
*
|
|
124
|
+
* // 위치 정보 변경 감지하기
|
|
125
|
+
* function LocationWatcher() {
|
|
126
|
+
* const [location, setLocation] = useState(null);
|
|
127
|
+
*
|
|
128
|
+
* useEffect(() => {
|
|
129
|
+
* const subscription = startUpdateLocation({
|
|
130
|
+
* accuracy: Accuracy.Default,
|
|
131
|
+
* timeInterval: 3000,
|
|
132
|
+
* distanceInterval: 10,
|
|
133
|
+
* callback: (location) => {
|
|
134
|
+
* setLocation(location);
|
|
135
|
+
* },
|
|
136
|
+
* });
|
|
137
|
+
*
|
|
138
|
+
* return () => subscription.remove();
|
|
139
|
+
* }, []);
|
|
140
|
+
*
|
|
141
|
+
* if (location == null) {
|
|
142
|
+
* return <Text>위치 정보를 가져오는 중이에요...</Text>;
|
|
143
|
+
* }
|
|
144
|
+
*
|
|
145
|
+
* return (
|
|
146
|
+
* <View>
|
|
147
|
+
* <Text>위도: {location.coords.latitude}</Text>
|
|
148
|
+
* <Text>경도: {location.coords.longitude}</Text>
|
|
149
|
+
* <Text>위치 정확도: {location.coords.accuracy}m</Text>
|
|
150
|
+
* <Text>높이: {location.coords.altitude}m</Text>
|
|
151
|
+
* <Text>고도 정확도: {location.coords.altitudeAccuracy}m</Text>
|
|
152
|
+
* <Text>방향: {location.coords.heading}°</Text>
|
|
153
|
+
* </View>
|
|
154
|
+
* );
|
|
155
|
+
* }
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
declare function startUpdateLocation(options: StartUpdateLocationOptions): Promise<StartUpdateLocationSubscription>;
|
|
159
|
+
|
|
1
160
|
/**
|
|
2
161
|
* @public
|
|
3
162
|
* @tag AppsInTossModule
|
|
@@ -72,4 +231,327 @@ declare function setClipboardText(text: string): Promise<void>;
|
|
|
72
231
|
*/
|
|
73
232
|
declare function getClipboardText(): Promise<string>;
|
|
74
233
|
|
|
75
|
-
|
|
234
|
+
/**
|
|
235
|
+
* 연락처 정보를 나타내는 타입이에요.
|
|
236
|
+
*/
|
|
237
|
+
interface ContactEntity {
|
|
238
|
+
/** 연락처 이름이에요. */
|
|
239
|
+
name: string;
|
|
240
|
+
/** 연락처 전화번호로, 문자열 형식이에요. */
|
|
241
|
+
phoneNumber: string;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* @public
|
|
245
|
+
* @tag AppsInTossModule
|
|
246
|
+
* @category AppsInTossModules
|
|
247
|
+
* @kind function
|
|
248
|
+
* @name fetchContacts
|
|
249
|
+
* @description 사용자의 연락처 목록을 페이지 단위로 가져오는 함수예요.
|
|
250
|
+
* @param size - 한 번에 가져올 연락처 개수예요. 예를 들어, 10을 전달하면 최대 10개의 연락처를 가져와요.
|
|
251
|
+
* @param offset - 가져올 연락처의 시작 지점이에요. 처음 호출할 때는 `0`을 전달해야 해요. 이후에는 이전 호출에서 반환된 `nextOffset` 값을 사용해요.
|
|
252
|
+
* @param query - 추가적인 필터링 옵션이에요.
|
|
253
|
+
* @param query.contains - 이름에 특정 문자열이 포함된 연락처만 가져오고 싶을 때 사용해요. 이 값을 전달하지 않으면 모든 연락처를 가져와요.
|
|
254
|
+
* @returns {Promise<{result: { name: string; phoneNumber: string }[]; nextOffset: number | null; done: boolean}>}
|
|
255
|
+
* 연락처 목록과 페이지네이션 정보를 포함한 객체를 반환해요.
|
|
256
|
+
* - `result`: 가져온 연락처 목록이에요.
|
|
257
|
+
* - `nextOffset`: 다음 호출에 사용할 오프셋 값이에요. 더 가져올 연락처가 없으면 `null`이에요.
|
|
258
|
+
* - `done`: 모든 연락처를 다 가져왔는지 여부를 나타내요. 모두 가져왔다면 `true`예요.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ### 특정 문자열이 포함된 연락처 목록 가져오기
|
|
262
|
+
*
|
|
263
|
+
* ```tsx
|
|
264
|
+
* import React, { useState } from 'react';
|
|
265
|
+
* import { View, Text, Button } from 'react-native';
|
|
266
|
+
* import { fetchContacts } from '@apps-in-toss/framework';
|
|
267
|
+
*
|
|
268
|
+
* // 특정 문자열을 포함한 연락처 목록을 가져와 화면에 표시하는 컴포넌트
|
|
269
|
+
* function ContactsList() {
|
|
270
|
+
* const [contacts, setContacts] = useState({
|
|
271
|
+
* result: [],
|
|
272
|
+
* nextOffset: null,
|
|
273
|
+
* done: false,
|
|
274
|
+
* });
|
|
275
|
+
*
|
|
276
|
+
* const handlePress = async () => {
|
|
277
|
+
* try {
|
|
278
|
+
* if (contacts.done) {
|
|
279
|
+
* console.log('모든 연락처를 가져왔어요.');
|
|
280
|
+
* return;
|
|
281
|
+
* }
|
|
282
|
+
*
|
|
283
|
+
* const response = await fetchContacts({
|
|
284
|
+
* size: 10,
|
|
285
|
+
* offset: contacts.nextOffset ?? 0,
|
|
286
|
+
* query: { contains: '홍길동' },
|
|
287
|
+
* });
|
|
288
|
+
* setContacts((prev) => ({
|
|
289
|
+
* result: [...prev.result, ...response.result],
|
|
290
|
+
* nextOffset: response.nextOffset,
|
|
291
|
+
* done: response.done,
|
|
292
|
+
* }));
|
|
293
|
+
* } catch (error) {
|
|
294
|
+
* console.error('연락처를 가져오는 데 실패했어요:', error);
|
|
295
|
+
* }
|
|
296
|
+
* };
|
|
297
|
+
*
|
|
298
|
+
* return (
|
|
299
|
+
* <View>
|
|
300
|
+
* {contacts.result.map((contact, index) => (
|
|
301
|
+
* <Text key={index}>{contact.name}: {contact.phoneNumber}</Text>
|
|
302
|
+
* ))}
|
|
303
|
+
* <Button
|
|
304
|
+
* title={contacts.done ? '모든 연락처를 가져왔어요.' : '다음 연락처 가져오기'}
|
|
305
|
+
* disabled={contacts.done}
|
|
306
|
+
* onPress={handlePress}
|
|
307
|
+
* />
|
|
308
|
+
* </View>
|
|
309
|
+
* );
|
|
310
|
+
* }
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
declare function fetchContacts({ size, offset, query, }: {
|
|
314
|
+
size: number;
|
|
315
|
+
offset: number;
|
|
316
|
+
query?: {
|
|
317
|
+
contains?: string;
|
|
318
|
+
};
|
|
319
|
+
}): Promise<{
|
|
320
|
+
result: ContactEntity[];
|
|
321
|
+
nextOffset: number | null;
|
|
322
|
+
done: boolean;
|
|
323
|
+
}>;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* 앨범 사진을 조회할 때 사용하는 옵션 타입이에요.
|
|
327
|
+
*/
|
|
328
|
+
interface FetchAlbumPhotosOptions {
|
|
329
|
+
/** 가져올 사진의 최대 개수를 설정해요. 숫자를 입력하고 기본값은 10이에요. */
|
|
330
|
+
maxCount?: number;
|
|
331
|
+
/** 사진의 최대 폭을 제한해요. 단위는 픽셀이고 기본값은 1024이에요. */
|
|
332
|
+
maxWidth?: number;
|
|
333
|
+
/** 이미지를 base64 형식으로 반환할지 설정해요. 기본값은 `false`예요. */
|
|
334
|
+
base64?: boolean;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* @public
|
|
338
|
+
* @tag AppsInTossModule
|
|
339
|
+
* @category AppsInTossModules
|
|
340
|
+
* @kind function
|
|
341
|
+
* @name fetchAlbumPhotos
|
|
342
|
+
* @description
|
|
343
|
+
* 사용자의 앨범에서 사진 목록을 불러오는 함수예요.
|
|
344
|
+
* 최대 개수와 해상도를 설정할 수 있고 갤러리 미리보기, 이미지 선택 기능 등에 활용할 수 있어요.
|
|
345
|
+
*
|
|
346
|
+
* @param options - 조회 옵션을 담은 객체예요.
|
|
347
|
+
* @param {number} [options.maxCount=10] 가져올 사진의 최대 개수를 설정해요. 숫자로 입력하며 기본값은 10이에요.
|
|
348
|
+
* @param {number} [options.maxWidth=1024] 사진의 최대 폭을 제한해요. 단위는 픽셀이며 기본값은 `1024`이에요.
|
|
349
|
+
* @param {boolean} [options.base64=false] 이미지를 base64 형식으로 반환할지 설정해요. 기본값은 `false`예요.
|
|
350
|
+
* @returns {Promise<AlbumResponse[]>}
|
|
351
|
+
* 앨범 사진의 고유 ID와 데이터 URI를 포함한 배열을 반환해요.
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ### 사진의 최대 폭을 360px로 제한하여 가져오기
|
|
355
|
+
*
|
|
356
|
+
* ```tsx
|
|
357
|
+
* import React, { useState } from 'react';
|
|
358
|
+
* import { View, Text, Button } from 'react-native';
|
|
359
|
+
* import { fetchAlbumPhotos } from '@apps-in-toss/framework';
|
|
360
|
+
*
|
|
361
|
+
* // 앨범 사진 목록을 가져와 화면에 표시하는 컴포넌트
|
|
362
|
+
* function AlbumPhotoList() {
|
|
363
|
+
* const [albumPhotos, setAlbumPhotos] = useState([]);
|
|
364
|
+
*
|
|
365
|
+
* const handlePress = async () => {
|
|
366
|
+
* try {
|
|
367
|
+
* const response = await fetchAlbumPhotos({
|
|
368
|
+
* maxWidth: 360,
|
|
369
|
+
* });
|
|
370
|
+
* setAlbumPhotos((prev) => ([...prev, ...response]));
|
|
371
|
+
* } catch (error) {
|
|
372
|
+
* console.error('앨범을 가져오는 데 실패했어요:', error);
|
|
373
|
+
* }
|
|
374
|
+
* };
|
|
375
|
+
*
|
|
376
|
+
* return (
|
|
377
|
+
* <View>
|
|
378
|
+
* {albumPhotos.map((album) => (
|
|
379
|
+
* <Text key={album.id}>{album.dataUri}</Text>
|
|
380
|
+
* ))}
|
|
381
|
+
* <Button title="앨범 가져오기" onPress={handlePress} />
|
|
382
|
+
* </View>
|
|
383
|
+
* );
|
|
384
|
+
* }
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
declare function fetchAlbumPhotos(options: FetchAlbumPhotosOptions): Promise<ImageResponse[]>;
|
|
388
|
+
|
|
389
|
+
interface GetCurrentLocationOptions {
|
|
390
|
+
/**
|
|
391
|
+
* 위치 정보를 가져올 정확도 수준이에요.
|
|
392
|
+
*/
|
|
393
|
+
accuracy: Accuracy;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* @public
|
|
397
|
+
* @tag AppsInTossModule
|
|
398
|
+
* @category AppsInTossModules
|
|
399
|
+
* @kind function
|
|
400
|
+
* @name getCurrentLocation
|
|
401
|
+
* @description 디바이스의 현재 위치 정보를 가져오는 함수예요.
|
|
402
|
+
* 위치 기반 서비스를 구현할 때 사용되고, 한 번만 호출되어 현재 위치를 즉시 반환해요.
|
|
403
|
+
* 예를 들어 지도 앱에서 사용자의 현재 위치를 한 번만 가져올 때, 날씨 앱에서 사용자의 위치를 기반으로 기상 정보를 제공할 때, 매장 찾기 기능에서 사용자의 위치를 기준으로 가까운 매장을 검색할 때 사용하면 유용해요.
|
|
404
|
+
*
|
|
405
|
+
* @param {GetCurrentLocationOptions} options 위치 정보를 가져올 때 사용하는 옵션 객체예요.
|
|
406
|
+
* @param {Accuracy} [options.accuracy] 위치 정보의 정확도 수준이에요. 정확도는 `Accuracy` 타입으로 설정돼요.
|
|
407
|
+
* @returns {Promise<Location>} 디바이스의 위치 정보가 담긴 객체를 반환해요.
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ### 디바이스의 현재 위치 정보 가져오기
|
|
411
|
+
*
|
|
412
|
+
* ```tsx
|
|
413
|
+
* import React, { useState } from 'react';
|
|
414
|
+
* import { View, Text, Button } from 'react-native';
|
|
415
|
+
* import { getCurrentLocation } from '@apps-in-toss/framework';
|
|
416
|
+
*
|
|
417
|
+
* // 현재 위치 정보를 가져와 화면에 표시하는 컴포넌트
|
|
418
|
+
* function CurrentPosition() {
|
|
419
|
+
* const [position, setPosition] = useState(null);
|
|
420
|
+
*
|
|
421
|
+
* const handlePress = async () => {
|
|
422
|
+
* try {
|
|
423
|
+
* const response = await getCurrentLocation({ accuracy: Accuracy.Balanced });
|
|
424
|
+
* setPosition(response);
|
|
425
|
+
* } catch (error) {
|
|
426
|
+
* console.error('위치 정보를 가져오는 데 실패했어요:', error);
|
|
427
|
+
* }
|
|
428
|
+
* };
|
|
429
|
+
*
|
|
430
|
+
* return (
|
|
431
|
+
* <View>
|
|
432
|
+
* {position ? (
|
|
433
|
+
* <Text>위치: {position.coords.latitude}, {position.coords.longitude}</Text>
|
|
434
|
+
* ) : (
|
|
435
|
+
* <Text>위치 정보를 아직 가져오지 않았어요</Text>
|
|
436
|
+
* )}
|
|
437
|
+
* <Button title="현재 위치 정보 가져오기" onPress={handlePress} />
|
|
438
|
+
* </View>
|
|
439
|
+
* );
|
|
440
|
+
* }
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
declare function getCurrentLocation(options: GetCurrentLocationOptions): Promise<Location>;
|
|
444
|
+
|
|
445
|
+
interface OpenCameraOptions {
|
|
446
|
+
/**
|
|
447
|
+
* 이미지를 Base64 형식으로 반환할지 여부를 나타내는 불리언 값이에요.
|
|
448
|
+
*
|
|
449
|
+
* 기본값: `false`.
|
|
450
|
+
*/
|
|
451
|
+
base64?: boolean;
|
|
452
|
+
/**
|
|
453
|
+
* 이미지의 최대 너비를 나타내는 숫자 값이에요.
|
|
454
|
+
*
|
|
455
|
+
* 기본값: `1024`.
|
|
456
|
+
*/
|
|
457
|
+
maxWidth?: number;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* @public
|
|
461
|
+
* @tag AppsInTossModule
|
|
462
|
+
* @category AppsInTossModules
|
|
463
|
+
* @kind function
|
|
464
|
+
* @name openCamera
|
|
465
|
+
* @description 카메라를 실행해서 촬영된 이미지를 반환하는 함수예요.
|
|
466
|
+
* @param {OpenCameraOptions} options - 카메라 실행 시 사용되는 옵션 객체예요.
|
|
467
|
+
* @param {boolean} [options.base64=false] - 이미지를 Base64 형식으로 반환할지 여부를 나타내는 불리언 값이에요. 기본값은 `false`예요. `true`로 설정하면 `dataUri` 대신 Base64 인코딩된 문자열을 반환해요.
|
|
468
|
+
* @param {boolean} [options.maxWidth=1024] - 이미지를 Base64 형식으로 반환할지 여부를 나타내는 불리언 값이에요. 기본값은 `false`예요. `true`로 설정하면 `dataUri` 대신 Base64 인코딩된 문자열을 반환해요.
|
|
469
|
+
* @returns {Promise<ImageResponse>}
|
|
470
|
+
* 촬영된 이미지 정보를 포함한 객체를 반환해요. 반환 객체의 구성은 다음과 같아요:
|
|
471
|
+
* - `id`: 이미지의 고유 식별자예요.
|
|
472
|
+
* - `dataUri`: 이미지 데이터를 표현하는 데이터 URI예요.
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ### 카메라 실행 후 촬영된 사진 가져오기
|
|
476
|
+
*
|
|
477
|
+
* ```tsx
|
|
478
|
+
* import React, { useState } from 'react';
|
|
479
|
+
* import { View, Text, Button, Image } from 'react-native';
|
|
480
|
+
* import { openCamera } from '@apps-in-toss/framework';
|
|
481
|
+
*
|
|
482
|
+
* // 카메라를 실행하고 촬영된 이미지를 화면에 표시하는 컴포넌트
|
|
483
|
+
* function Camera() {
|
|
484
|
+
* const [image, setImage] = useState(null);
|
|
485
|
+
*
|
|
486
|
+
* const handlePress = async () => {
|
|
487
|
+
* try {
|
|
488
|
+
* const response = await openCamera({ base64: false });
|
|
489
|
+
* setImage(response);
|
|
490
|
+
* } catch (error) {
|
|
491
|
+
* console.error('사진을 가져오는 데 실패했어요:', error);
|
|
492
|
+
* }
|
|
493
|
+
* };
|
|
494
|
+
*
|
|
495
|
+
* return (
|
|
496
|
+
* <View>
|
|
497
|
+
* {image ? (
|
|
498
|
+
* <Image source={{ uri: image.dataUri }} style={{ width: 200, height: 200 }} />
|
|
499
|
+
* ) : (
|
|
500
|
+
* <Text>사진이 없어요</Text>
|
|
501
|
+
* )}
|
|
502
|
+
* <Button title="사진 촬영하기" onPress={handlePress} />
|
|
503
|
+
* </View>
|
|
504
|
+
* );
|
|
505
|
+
* }
|
|
506
|
+
* ```
|
|
507
|
+
*/
|
|
508
|
+
declare function openCamera(options?: OpenCameraOptions): Promise<ImageResponse>;
|
|
509
|
+
|
|
510
|
+
type UseGeolocationOptions = Omit<StartUpdateLocationOptions, 'callback'>;
|
|
511
|
+
/**
|
|
512
|
+
* @public
|
|
513
|
+
* @tag AppsInTossModule
|
|
514
|
+
* @category AppsInTossModules
|
|
515
|
+
* @kind function
|
|
516
|
+
* @name useGeolocation
|
|
517
|
+
* @description 디바이스의 위치 정보를 반환하는 훅이에요. 위치가 변경되면 값도 변경돼요.
|
|
518
|
+
* GPS 정보를 활용해 현재 위치를 감지하고, 사용자의 이동에 따라 자동으로 업데이트돼요.
|
|
519
|
+
* 예를 들어, 지도 기반 서비스에서 사용자의 현재 위치를 표시하거나, 배달 앱에서 실시간 이동 경로를 추적할 때 활용할 수 있어요.
|
|
520
|
+
* 위치 정보의 정확도와 업데이트 주기를 조정할 수 있어서 배터리 소모를 최소화하면서도 필요한 수준의 정확도를 유지할 수 있어요.
|
|
521
|
+
*
|
|
522
|
+
* @param {UseGeolocationOptions} options - 위치 정보 감지에 필요한 설정 객체에요.
|
|
523
|
+
* @param {Accuracy} [options.accuracy] 위치 정확도를 설정해요. `Accuracy.Lowest`: 오차범위 3KM 이내, `Accuracy.Low`: 오차범위 1KM 이내, `Accuracy.Balanced`: 오차범위 몇 백미터 이내, `Accuracy.High`: 오차범위 10M 이내, `Accuracy.Highest`: 가장 높은 정확도, `Accuracy.BestForNavigation`: 네비게이션을 위한 최고 정확도
|
|
524
|
+
* @param {number} [options.timeInterval] 위치 정보를 업데이트하는 최소 주기로, 단위는 밀리초(ms)예요. 이 값은 위치 업데이트가 발생하는 가장 짧은 간격을 설정하지만, 시스템이나 환경의 영향을 받아 지정한 주기보다 더 긴 간격으로 업데이트될 수 있어요.
|
|
525
|
+
* @param {number} [options.distanceInterval] 위치 변경 거리를 미터(m) 단위로 설정해요.
|
|
526
|
+
*
|
|
527
|
+
* @example
|
|
528
|
+
* ### 위치 정보 변경 감지하기
|
|
529
|
+
*
|
|
530
|
+
* ```ts
|
|
531
|
+
* import React, { useState, useCallback } from 'react';
|
|
532
|
+
* import { View, Text } from 'react-native';
|
|
533
|
+
* import { useGeolocation, Accuracy } from '@apps-in-toss/framework';
|
|
534
|
+
*
|
|
535
|
+
* // 위치 정보 변경 감지하기
|
|
536
|
+
* function LocationWatcher() {
|
|
537
|
+
* const location = useGeolocation({
|
|
538
|
+
* accuracy: Accuracy.Balanced,
|
|
539
|
+
* distanceInterval: 10,
|
|
540
|
+
* timeInterval: 1000,
|
|
541
|
+
* });
|
|
542
|
+
*
|
|
543
|
+
* if (location == null) {
|
|
544
|
+
* return <Text>위치 정보를 가져오는 중이에요...</Text>;
|
|
545
|
+
* }
|
|
546
|
+
*
|
|
547
|
+
* return (
|
|
548
|
+
* <View>
|
|
549
|
+
* <Text>위치 정보: {location.latitude}, {location.longitude}</Text>
|
|
550
|
+
* </View>
|
|
551
|
+
* );
|
|
552
|
+
* }
|
|
553
|
+
* ```
|
|
554
|
+
*/
|
|
555
|
+
declare function useGeolocation({ accuracy, distanceInterval, timeInterval }: UseGeolocationOptions): Location | null;
|
|
556
|
+
|
|
557
|
+
export { Accuracy, type ContactEntity, type FetchAlbumPhotosOptions, type GetCurrentLocationOptions, type ImageResponse, type Location, type OpenCameraOptions, type StartUpdateLocationOptions, type StartUpdateLocationSubscription, type UpdateLocationEventEmitter, type UseGeolocationOptions, fetchAlbumPhotos, fetchContacts, getClipboardText, getCurrentLocation, openCamera, setClipboardText, startUpdateLocation, useGeolocation };
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var src_exports = {};
|
|
22
|
-
__export(src_exports, {
|
|
23
|
-
getClipboardText: () => getClipboardText,
|
|
24
|
-
setClipboardText: () => setClipboardText
|
|
25
|
-
});
|
|
26
|
-
module.exports = __toCommonJS(src_exports);
|
|
1
|
+
// src/native-event-emitter/nativeEventEmitter.ts
|
|
2
|
+
import { NativeEventEmitter } from "react-native";
|
|
27
3
|
|
|
28
4
|
// src/native-modules/AppsInTossModule.ts
|
|
29
|
-
|
|
30
|
-
var
|
|
5
|
+
import { NativeModules } from "react-native";
|
|
6
|
+
var AppsInTossModuleInstance = NativeModules.AppsInTossModule;
|
|
7
|
+
var AppsInTossModule = AppsInTossModuleInstance;
|
|
8
|
+
|
|
9
|
+
// src/native-event-emitter/nativeEventEmitter.ts
|
|
10
|
+
var nativeEventEmitter = new NativeEventEmitter(AppsInTossModuleInstance);
|
|
31
11
|
|
|
32
12
|
// src/native-modules/getPermission.ts
|
|
33
13
|
function getPermission(permission) {
|
|
@@ -51,6 +31,33 @@ async function requestPermission(permission) {
|
|
|
51
31
|
}
|
|
52
32
|
}
|
|
53
33
|
|
|
34
|
+
// src/native-event-emitter/startUpdateLocation.ts
|
|
35
|
+
async function startUpdateLocation(options) {
|
|
36
|
+
const { callback, ...nativeOptions } = options;
|
|
37
|
+
const permissionStatus = await requestPermission({ name: "geolocation", access: "access" });
|
|
38
|
+
if (permissionStatus === "denied") {
|
|
39
|
+
throw new Error("\uC704\uCE58 \uAD8C\uD55C\uC774 \uAC70\uBD80\uB418\uC5C8\uC5B4\uC694.");
|
|
40
|
+
}
|
|
41
|
+
await AppsInTossModuleInstance.startUpdateLocation(nativeOptions);
|
|
42
|
+
const subscription = nativeEventEmitter.addListener("updateLocation", callback);
|
|
43
|
+
subscriptionCount++;
|
|
44
|
+
const subscriptionProxy = new Proxy(subscription, {
|
|
45
|
+
get: (target, key, receiver) => {
|
|
46
|
+
const result = Reflect.get(target, key, receiver);
|
|
47
|
+
if (key === "remove") {
|
|
48
|
+
return async () => {
|
|
49
|
+
await (--subscriptionCount === 0 && AppsInTossModuleInstance.stopUpdateLocation({}));
|
|
50
|
+
const remove = result;
|
|
51
|
+
remove();
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return subscriptionProxy;
|
|
58
|
+
}
|
|
59
|
+
var subscriptionCount = 0;
|
|
60
|
+
|
|
54
61
|
// src/native-modules/setClipboardText.ts
|
|
55
62
|
async function setClipboardText(text) {
|
|
56
63
|
const permissionStatus = await requestPermission({ name: "clipboard", access: "write" });
|
|
@@ -68,8 +75,121 @@ async function getClipboardText() {
|
|
|
68
75
|
}
|
|
69
76
|
return AppsInTossModule.getClipboardText({});
|
|
70
77
|
}
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
|
|
79
|
+
// src/native-modules/fetchContacts.ts
|
|
80
|
+
async function fetchContacts({
|
|
81
|
+
size,
|
|
82
|
+
offset,
|
|
83
|
+
query
|
|
84
|
+
}) {
|
|
85
|
+
const permissionStatus = await requestPermission({ name: "contacts", access: "read" });
|
|
86
|
+
if (permissionStatus === "denied") {
|
|
87
|
+
throw new Error("\uC5F0\uB77D\uCC98 \uAD8C\uD55C\uC774 \uAC70\uBD80\uB418\uC5C8\uC5B4\uC694.");
|
|
88
|
+
}
|
|
89
|
+
const contacts = await AppsInTossModule.fetchContacts({
|
|
90
|
+
size,
|
|
91
|
+
offset,
|
|
92
|
+
query
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
result: contacts.result,
|
|
96
|
+
nextOffset: contacts.nextOffset ?? null,
|
|
97
|
+
done: contacts.done
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/native-modules/fetchAlbumPhotos.ts
|
|
102
|
+
var DEFAULT_MAX_COUNT = 10;
|
|
103
|
+
var DEFAULT_MAX_WIDTH = 1024;
|
|
104
|
+
async function fetchAlbumPhotos(options) {
|
|
105
|
+
const permissionStatus = await requestPermission({ name: "photos", access: "read" });
|
|
106
|
+
if (permissionStatus === "denied") {
|
|
107
|
+
throw new Error("\uC0AC\uC9C4\uCCA9 \uAD8C\uD55C\uC774 \uAC70\uBD80\uB418\uC5C8\uC5B4\uC694.");
|
|
108
|
+
}
|
|
109
|
+
const albumPhotos = await AppsInTossModule.fetchAlbumPhotos({
|
|
110
|
+
...options,
|
|
111
|
+
maxCount: options.maxCount ?? DEFAULT_MAX_COUNT,
|
|
112
|
+
maxWidth: options.maxWidth ?? DEFAULT_MAX_WIDTH
|
|
113
|
+
});
|
|
114
|
+
return albumPhotos;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/native-modules/getCurrentLocation.ts
|
|
118
|
+
async function getCurrentLocation(options) {
|
|
119
|
+
const permissionStatus = await requestPermission({ name: "geolocation", access: "access" });
|
|
120
|
+
if (permissionStatus === "denied") {
|
|
121
|
+
throw new Error("\uC704\uCE58 \uAD8C\uD55C\uC774 \uAC70\uBD80\uB418\uC5C8\uC5B4\uC694.");
|
|
122
|
+
}
|
|
123
|
+
const position = await AppsInTossModule.getCurrentLocation(options);
|
|
124
|
+
return position;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/native-modules/openCamera.ts
|
|
128
|
+
async function openCamera(options) {
|
|
129
|
+
const permissionStatus = await requestPermission({ name: "camera", access: "access" });
|
|
130
|
+
if (permissionStatus === "denied") {
|
|
131
|
+
throw new Error("\uCE74\uBA54\uB77C \uAD8C\uD55C\uC774 \uAC70\uBD80\uB418\uC5C8\uC5B4\uC694.");
|
|
132
|
+
}
|
|
133
|
+
const photo = await AppsInTossModule.openCamera({ base64: false, maxWidth: 1024, ...options });
|
|
134
|
+
return photo;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/hooks/useGeolocation.ts
|
|
138
|
+
import { useState, useCallback, useEffect, useRef } from "react";
|
|
139
|
+
import { useVisibility } from "react-native-bedrock";
|
|
140
|
+
function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
|
|
141
|
+
const isVisible = useVisibility();
|
|
142
|
+
const subscriptionRef = useRef();
|
|
143
|
+
const [location, setLocation] = useState(null);
|
|
144
|
+
const subscribe = useCallback(async () => {
|
|
145
|
+
try {
|
|
146
|
+
const subscription = await startUpdateLocation({
|
|
147
|
+
accuracy,
|
|
148
|
+
distanceInterval,
|
|
149
|
+
timeInterval,
|
|
150
|
+
callback: setLocation
|
|
151
|
+
});
|
|
152
|
+
subscriptionRef.current = subscription;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error("failed to subscribe location", error);
|
|
155
|
+
}
|
|
156
|
+
}, [accuracy, distanceInterval, timeInterval]);
|
|
157
|
+
const cleanup = useCallback(async () => {
|
|
158
|
+
try {
|
|
159
|
+
const prevSubscription = subscriptionRef.current;
|
|
160
|
+
subscriptionRef.current = void 0;
|
|
161
|
+
await prevSubscription?.remove();
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error("failed to cleanup location subscription", error);
|
|
164
|
+
}
|
|
165
|
+
}, []);
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
if (subscriptionRef.current == null && isVisible) {
|
|
168
|
+
subscribe();
|
|
169
|
+
}
|
|
170
|
+
return () => void cleanup();
|
|
171
|
+
}, [subscribe, cleanup, isVisible]);
|
|
172
|
+
return location;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/types.ts
|
|
176
|
+
var Accuracy = /* @__PURE__ */ ((Accuracy2) => {
|
|
177
|
+
Accuracy2[Accuracy2["Lowest"] = 1] = "Lowest";
|
|
178
|
+
Accuracy2[Accuracy2["Low"] = 2] = "Low";
|
|
179
|
+
Accuracy2[Accuracy2["Balanced"] = 3] = "Balanced";
|
|
180
|
+
Accuracy2[Accuracy2["High"] = 4] = "High";
|
|
181
|
+
Accuracy2[Accuracy2["Highest"] = 5] = "Highest";
|
|
182
|
+
Accuracy2[Accuracy2["BestForNavigation"] = 6] = "BestForNavigation";
|
|
183
|
+
return Accuracy2;
|
|
184
|
+
})(Accuracy || {});
|
|
185
|
+
export {
|
|
186
|
+
Accuracy,
|
|
187
|
+
fetchAlbumPhotos,
|
|
188
|
+
fetchContacts,
|
|
73
189
|
getClipboardText,
|
|
74
|
-
|
|
75
|
-
|
|
190
|
+
getCurrentLocation,
|
|
191
|
+
openCamera,
|
|
192
|
+
setClipboardText,
|
|
193
|
+
startUpdateLocation,
|
|
194
|
+
useGeolocation
|
|
195
|
+
};
|