override fun onDraw(canvas: Canvas) { super.onDraw(canvas)
val centerX = width / 2f val centerY = height / 2f val horizontalRadius = Math.min(width, height) / 2f - progressPaint1.strokeWidth / 2f val verticalRadius = horizontalRadius / 2f
// Calculate the sweep angles for the progress arcs val progressSweepAngle1 = 360f * progress1 / maxProgress val progressSweepAngle2 = 360f * progress2 / maxProgress
// Calculate the start and end angles for the progress arcs val startAngle1 = -90f val endAngle1 = startAngle1 + progressSweepAngle1 val startAngle2 = endAngle1 val endAngle2 = startAngle2 + progressSweepAngle2
이 앱은 Ver 0.5.0부터 시작합니다. 사유는 회원관리용 앱을 통합해 관리를 했으나, 사용자 관점에서 불편한 부분들이 발생하고 있어서 앱의 역할을 명확하게 분리하고자 하는 생각이 있었습니다.
설정 버튼 : 관리자의 정보 관리를 위한 버튼
뒤로가기 : 앱을 종료하고자 할 때 사용
추가하기 (+) : 현재는 관리자도 바코드 할인쿠폰을 등록할 수 있도록 지원
영수증 관리 : 회원의 제시한 영수증을 관리할 수 있도록 지원
영수증 목록 : 등록된 영수증 목록을 조회할 수 있도록 지원
회원 목록 : 등록된 회원 리스트를 조회하고 알림을 전달할 수 있도록 지원
대기자 목록 : 회원앱과 관리자 앱이 근처에서 활성화된 경우 회원 앱에서 방문 기록을 요청하면 등록되어 조회되도록 지원
홍보성 이미지 관리 : 이곳에서 등록된 이미지는 관리자앱 근처에 나타나는 회원앱이 활성화 된 경우 공유 설정된 이미지를 전달할 수 있도록 지원
기본 버튼의 메뉴는 이상과 같이 관리가 됩니다.
화면 상단에 나타나는 버튼 이미지 입니다. 이 버튼 이미지가 나타났을 때 클릭 하면 관리자 설정에서 생성된 QRCode 을 근처에 도착한 회원 앱으로 전달하는 기능도 지원됩니다.
메인 화면
관리자 설정 (화면이미지의 버전 표시는 변경될 수 있습니다.)
관리자 설정이 필요한 이유는 회원 관리를 하기 위해서는 데이터 저장을 해야 하는 데, 관리를 위해서 온라인으로 진행하고자 합니다. 해서 관리자 설정을 해 주세요.
관리자 등록 화면에서는
먼저 관리자로 사용된 이메일 ID와 비밀번호를 입력하고 관리자 추가를 하게 되면 다음부터는 관리자 확인만 가능합니다
관리자 확인이 되고 나면 QRcode 위에 있는 공유 버튼을 클릭하여 회원 가입 링크를 공유합니다. 그 이후에는 화면에 QRcode 전달을 위한 링크가 생겨 납니다.
그다음부터는 QRCode 을 이용해서 고객 가입을 유도할 수 있습니다.
** 관리자의 비밀번호를 분실한 경우에는 비밀번호 하단의 제일 오른쪽 버튼을 이용하여 등록한 이메일 계정으로 관리자 비밀번호 변경할 수 있는 링크를 전달할 수 있습니다. *** 관리자를 삭제하고 다시 등록하는 경우에는 5회 이상 반복 하게 되면 해당 이메일 계정은 더 이상 등록할 수 없도록 제한될 수 있으니 주의가 필요합니다.
회원가입 링크 공유
회원 가입 유도를 위한 링크 공유는 SNS 또는 SMS , 이메일 등등 모든 공유 수단을 활용할 수 있습니다.
공유방법 선택
공유하는 방법을 선택하는 경우 '한 번만', '항상' 중에서 선택할 수 있는 데, 이 경우
한 번만 하는 경우에는 다음에 또 같은 선택을 해야 합니다.
항상을 선택하는 경우에는 다음번부터 같은 공유 방법으로만 할 수 있기 때문에 주의가 필요합니다. (물론 휴대폰의 설정에서 변경할 수 있습니다.)
** 더 쉬운 방법은 상대방이 앞에 있다면 위 그림의 QRCode 을 상대방의 휴대폰 카메라에 보여주는 것이 제일 수월 합니다. 이 경우에는 상대방 휴대폰 카메라앱에서 바로 링크가 나타납니다. (다만, 안드로이드 폰에서만 가능합니다.)
회원으로 가입이 유도되는 경우 다음과 같이 화면에 변경됩니다. (회원앱의 설명에 근거해 확인해 주세요)
회원 가입 링크를 클릭해 실행된 경우
회원 화면으로 실행된 경우에는 회원의 이름과 연락처만 입력하고 저장하게 되고, 회원 스스로 할인 쿠폰을 관리하고자 하는 경우에는 할인 쿠폰을 등록해 보관 관리 할 수 있도록 지원됩니다.
영수증 등록 하기
영수증 등록해 보기
영수증 등록은 회원정보를 먼저 확인한 이후에 저장 버튼이 활성화됩니다. (저장 버튼의 색갈이 파란색이 됩니다. 준비 시점에는 저장 버튼 색갈이 검은색입니다.)
다음은 영수증 이미지를 선택하여야 합니다.
이미지 선택하기 방법
영수증 이미지 선택 방법은 카메라 직접 촬영을 하거나, 이미 촬영된 이미지를 읽어오는 방법을 선택할 수 있습니다. 가져온 영수증 이미지에서 필요한 부분만 선택적으로 자르기를 할 수 있도록 지원하고 있습니다. 사진 전체에서 이미지를 선택하고 자르기 버튼을 클릭하면 화면에 선택된 부분의 이미지만 가져오는 것을 볼 수 있습니다.
이미지 자르기 전 후
이미지 선택이 된 이후에 회원 정보 위에 있는 문자 인식 버튼을 클릭하여 화면의 내용 중에서 문자로 인식된 부분을 조회해 볼 수 있습니다.
문자 인식된 내용중에서 해당하는 금액 선택 하기
인식된 문자들 중에서 숫자 변환될 수 있는 부분의 내용을 표시하고 있으니 그 부분에서 해당금액이 있는 부분을 선택하면 거래 금액이 표시 되게 됩니다. (** 이 경우에는 거래금액을 수정할 수 없습니다.)
영수증 목록 보기
저장된 이후에는 영수증 목록 보기에서 저장된 목록을 확인할 수 있습니다. 영수증 목록에서는 회원의 연락처 정보를 이용해서 해당 해당 회원만 검색할 수 있도록 지원되고 있습니다.
저장된 영수증 목록 보기
고객 리스트 조회
고객명단은 회원으로 가입된 고객의 리스트를 조회할 수 있도록 지원됩니다. 고객이 많은 경우 이름의 첫 글자부터 한 글자 이상 입력 후 검색해 볼 수 있습니다.
고객 명단 조회
또한 해당 고객에게 알림을 보내고자 하는 경우 간단한 문구를 입력하여 고객이 설치한 앱으로 푸시 알림을 보낼 수 있도록 지원됩니다.
알림 메시지 전송
알림 메시지를 전송하게 되면 고객의 휴대폰으로 푸시 알림이 전송되며, 고객이 알림을 선택하면 고객화면으로 전달된 알림 내용을 확인해 볼 수 있습니다. 고객 화면의 위 부분에는 그동안 수신된 안내 메시지가 나오게 되어 있으며, 아래 부분에는 인식된 영수증의 리스트를 조회할 수 있도록 하고 있습니다.
고객 화면 알림 및 영수증 내역 조회
대기자 목록 조회
대기자 목록 조회는 회원앱과 관리자 앱이 근처(100m 이내)에서 활성화되는 경우 회원앱도 나타나는 근처 인식 버튼을 이용하여 관리자 앱으로 대기 신청을 했을 때 등록된 정보를 조회할 수 있는 화면입니다.
대기리스트 연결 순서
이 그림과 같이 관리자앱과 회원앱이 근처에서 활성화되면 상단에 버튼 이미지가 추가로 나타납니다. 이때 회원 앱에서 해당 버튼을 클릭하면 관리자 앱으로 회원 정보를 전달하게 됩니다. 도달이 완료 되면 대기자 리스트에 추가 되며, 회원앱으로는 대기자 리스트에 등록 되었다는 알림을 전달 하게 됩니다.
광고 이미지 등록 관리
광고 이미지 등록 관리 화면에서
광고 이미지 등록 예시
이 화면에서 관리되는 홍보성 이미지는 대기자 목록 조회에서 처럼 근접한 회원 앱으로 자동 전달 됩니다. 회원은 해당 이미지를 보고 삭제할 수 도 있지만, 전달하고자 하는 의도는 구현이 될 듯합니다.
#스하리1000명프로젝트, Đôi khi thật khó để nói chuyện với người lao động nước ngoài phải không? Tôi đã tạo một ứng dụng đơn giản có ích! Bạn viết bằng ngôn ngữ của bạn và những người khác nhìn thấy nó bằng ngôn ngữ của họ. Nó tự động dịch dựa trên cài đặt. Siêu tiện dụng để trò chuyện dễ dàng. Hãy xem khi bạn có cơ hội! https://play.google.com/store/apps/details?id=com.billcoreatech.multichat416
Certainly! Here's some information about Seoul in 2023:
1. Major Events: Seoul is a vibrant city that hosts numerous events throughout the year. In 2023, you can expect various cultural festivals, music concerts, art exhibitions, and sporting events. Some notable events might include the Seoul Lantern Festival, Seoul International Music Festival, Seoul Fashion Week, and the Seoul Marathon. Make sure to check the local event calendars for specific dates and details.
2. Attractions: Seoul offers a wide range of attractions to explore. You can visit historical landmarks like Gyeongbokgung Palace, Changdeokgung Palace, and Bukchon Hanok Village to experience the city's rich history and traditional architecture. Don't miss the bustling markets such as Namdaemun Market and Dongdaemun Market, known for their shopping and street food. Other popular sites include N Seoul Tower, Myeongdong shopping district, and the Han River Park.
3. Technology and Innovation: Seoul is renowned for its advancements in technology. You can explore high-tech neighborhoods like Gangnam and Digital Media City, where you'll find futuristic buildings, cutting-edge technology, and innovation centers. Don't forget to visit the famous Samsung d'light exhibition center to see the latest gadgets and innovations.
4. Cuisine: Seoul is a food lover's paradise, offering a diverse range of culinary delights. You can savor traditional Korean dishes like bibimbap, bulgogi, and kimchi, as well as enjoy international cuisines in the city's many restaurants. Don't miss the chance to experience street food at popular spots like Gwangjang Market and Myeongdong, where you can try tasty treats like tteokbokki (spicy rice cakes) and hotteok (sweet pancakes).
5. Transportation: Seoul has a well-developed public transportation system, making it easy to navigate the city. You can utilize the subway, buses, and taxis to travel to different parts of Seoul conveniently. Additionally, Seoul offers bike-sharing services and rental cars for more flexibility in exploring the city.
Please note that the above information is based on the current knowledge available up until September 2021, and there might be additional developments and changes in the city by 2023. It's always a good idea to check for the latest information and updates closer to your travel dates.
틀림없이! 2023년 서울에 대한 정보는 다음과 같습니다. 1. 주요 행사: 서울은 연중 수많은 행사가 열리는 활기찬 도시입니다. 2023년에는 다양한 문화제와 음악회, 미술 전시회, 스포츠 행사를 기대할 수 있습니다. 서울빛초롱축제, 서울국제음악제, 서울패션위크, 서울마라톤 등이 대표적이다. 특정 날짜 및 세부 정보는 지역 행사 일정을 확인하십시오. 2. 관광명소: 서울은 탐험할 수 있는 다양한 관광명소를 제공합니다. 경복궁, 창덕궁, 북촌 한옥마을 등의 역사적 명소를 방문하여 도시의 풍부한 역사와 전통 건축물을 경험할 수 있습니다. 쇼핑과 길거리 음식으로 유명한 남대문시장, 동대문시장 등 북적이는 시장을 놓치지 마세요. 다른 인기 명소로는 N서울타워, 명동 쇼핑가, 한강공원 등이 있습니다. 3. 기술과 혁신: 서울은 기술 발전으로 유명합니다. 미래형 건물, 최첨단 기술, 혁신 센터가 있는 강남과 디지털 미디어 시티와 같은 첨단 기술 지역을 탐험할 수 있습니다. 유명한 Samsung d'light 전시 센터를 방문하여 최신 장치와 혁신을 보는 것을 잊지 마십시오. 4. 요리: 서울은 다양한 종류의 요리를 제공하는 미식가의 천국입니다. 비빔밥, 불고기, 김치와 같은 전통 한식을 맛볼 수 있을 뿐만 아니라 도시의 많은 레스토랑에서 세계 각국의 요리를 즐길 수 있습니다. 떡볶이, 호떡 등 맛있는 음식을 맛볼 수 있는 광장시장, 명동 등 인기 명소에서 길거리 음식을 경험할 기회를 놓치지 마세요. 5. 교통: 서울은 대중교통이 잘 발달되어 있어 이동이 편리합니다. 지하철, 버스, 택시를 이용하여 서울의 여러 지역으로 편리하게 이동할 수 있습니다. 또한 서울은 자전거 공유 서비스와 렌터카를 제공하여 보다 유연하게 도시를 둘러볼 수 있습니다. 위의 정보는 2021년 9월까지 사용 가능한 현재 지식을 기반으로 하며 2023년까지 도시에서 추가 개발 및 변경이 있을 수 있습니다. 여행 날짜에 가까운 최신 정보 및 업데이트를 항상 확인하는 것이 좋습니다..
오늘은 앱을 구현하는 동안 알게 된 Nearby Connections API에 대한 이야기를 정리해 두고자 합니다. 이 기능은 wifi 가 되지 않더라도 주변(10m 반경)에 같은 앱을 사용하는 사용자가 있을 때, 데이터, 텍스트, 이미지 등을 공유하는 기능을 구현하기 위해서 사용됩니다.
여러 개의 예제 소스가 있기는 했지만, 가장 필요한 기능에 유사한 것은 간단한 무선통신(워키토키)을 지원하는 코드가 눈에 들어와 실행을 해 보았습니다.
다만, 원래 코드가 2018년쯤에 만들어진 이후 업데이트가 되지 않아서 최신 환경에 맞지 않는 부분들이 있었고, java 코드로 되어 있어 그대로 일단은 실행이 될 수 있도록 하는 부분만 수정해서 개인 계정에는 commit을 해 두었습니다. 저 링크에 있는 코드는 2023년 현재에도 그대로 실행해 볼 수 있는 코드입니다.
저는 그것을 가지고 와서 kotlin을 수정된 코드를 활용해서 만들고 있는 앱에 적용해 보기로 했습니다. 아무튼 기능 구현을 해 보도록 하겠습니다.
/** Nearby Connections에 연결하고 편리한 메서드 및 콜백을 제공하는 클래스입니다. */ @RequiresApi(Build.VERSION_CODES.TIRAMISU) abstract class ConnectionsActivity : ComponentActivity() {
private val dataViewModel : ViewModels by viewModels()
/** * ConnectionsActivity 권한으로 앱에 필요한 모든 권한을 풀링하는 선택적 후크 *요청합니다. * * @return 앱이 제대로 작동하는 데 필요한 모든 권한입니다. */ /** * 이러한 권한은 Nearby Connections에 연결하기 전에 필요합니다. */
protected open val requiredPermissions: Array<String> = arrayOf( Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_ADVERTISE, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, )
private val REQUEST_CODE_REQUIRED_PERMISSIONS = 1
private val wifiManager: WifiManager by lazy { applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager }
/** * 로깅을 위해 [Status]를 영어로 읽을 수 있는 메시지로 변환합니다. * * @param status 현재 상태 * @return 읽을 수 있는 문자열. 예. 파일을 찾을 수 없습니다. */ private fun toString(status: Status): String { return String.format( Locale.US, "[%d]%s", status.statusCode, if (status.statusMessage != null) status.statusMessage else ConnectionsStatusCodes.getStatusCodeString( status.statusCode ) ) }
private fun hasPermissions(context: Context?, vararg permissions: String?): Boolean { if (context != null) { for (permission in permissions) { logD("permission=$permission", "") if (ActivityCompat.checkSelfPermission( context, permission!! ) != PackageManager.PERMISSION_GRANTED ) { return false } } } return true }
/** Nearby Connections에 대한 핸들러입니다. */ lateinit var mConnectionsClient: ConnectionsClient
/** 우리 주변에서 발견한 장치. */ private val mDiscoveredEndpoints: MutableMap<String, Endpoint> = HashMap()
/** * 보류 중인 연결이 있는 장치입니다. [ ][.acceptConnection] 또는 [.rejectConnection]을 호출할 때까지 보류 상태로 유지됩니다. */ private val mPendingConnections: MutableMap<String, Endpoint> = HashMap()
/** * 현재 연결된 장치. 광고주의 경우 이는 클 수 있습니다. 발견자에게는 * 이 맵에는 하나의 항목만 있습니다. */ private val mEstablishedConnections: MutableMap<String, Endpoint?> = HashMap() /** 현재 다른 장치에 연결을 시도하고 있으면 'true'를 반환합니다. */ /** * 검색된 장치에 연결을 요청하는 경우 True입니다. 우리가 묻는 동안, 우리는 다른 것을 요청할 수 없습니다 * 장치. */ protected var isConnecting = false private set /** 현재 검색 중이면 'true'를 반환합니다. */ /** 발견하는 경우 참입니다. */ protected var isDiscovering = false private set /** 현재 광고 중인 경우 'true'를 반환합니다. */ /** 광고하는 경우 참입니다. */ protected var isAdvertising = false private set
/** 다른 장치에 대한 연결을 위한 콜백. */ private val mConnectionLifecycleCallback: ConnectionLifecycleCallback = object : ConnectionLifecycleCallback() { override fun onConnectionInitiated(endpointId: String, connectionInfo: ConnectionInfo) { logD( String.format( "onConnectionInitiated(endpointId=%s, endpointName=%s)", endpointId, connectionInfo.endpointName ), "" ) val endpoint = Endpoint(endpointId, connectionInfo.endpointName) mPendingConnections[endpointId] = endpoint this@ConnectionsActivity.onConnectionInitiated(endpoint, connectionInfo) }
override fun onConnectionResult(endpointId: String, result: ConnectionResolution) { logD( String.format( "onConnectionResponse(endpointId=%s, result=%s)", endpointId, result ), "" )
// We're no longer connecting isConnecting = false if (!result.status.isSuccess) { logW( String.format( "Connection failed. Received status %s.", toString(result.status) ) ) onConnectionFailed(mPendingConnections.remove(endpointId)) return } connectedToEndpoint(mPendingConnections.remove(endpointId)) }
override fun onDisconnected(endpointId: String) { if (!mEstablishedConnections.containsKey(endpointId)) { logW("Unexpected disconnection from endpoint $endpointId") return } disconnectedFromEndpoint(mEstablishedConnections[endpointId]) } }
/** 다른 장치에서 우리에게 보낸 페이로드(데이터 바이트)에 대한 콜백. */ private val mPayloadCallback: PayloadCallback = object : PayloadCallback() { override fun onPayloadReceived(endpointId: String, payload: Payload) { logD( String.format("onPayloadReceived(endpointId=%s, payload=%s)", endpointId, payload), "" ) onReceive(mEstablishedConnections[endpointId], payload) }
/** 활동이 처음 생성될 때 호출됩니다. */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mConnectionsClient = Nearby.getConnectionsClient(this) }
/** 활동이 사용자에게 표시될 때 호출됩니다. */ override fun onStart() { super.onStart() // 이건 33 일때만 적용 가능 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { logD("SDK=${Build.VERSION.SDK_INT}","") requiredPermissions.plus(Manifest.permission.NEARBY_WIFI_DEVICES) } if (!hasPermissions(applicationContext, *requiredPermissions)) { requestPermissions.launch(requiredPermissions) } // startLocalOnlyHotspot() }
/** * 장치를 광고 모드로 설정합니다. 검색 모드에서 다른 장치로 브로드캐스트합니다. * [.onAdvertisingStarted] 또는 [.onAdvertisingFailed] 중 하나가 한 번 호출됩니다. * 이 모드에 성공적으로 진입했는지 확인했습니다. */ protected fun startAdvertising() { isAdvertising = true val localEndpointName = name val advertisingOptions = AdvertisingOptions.Builder() advertisingOptions.setStrategy(strategy!!) mConnectionsClient .startAdvertising( localEndpointName, serviceId, mConnectionLifecycleCallback, advertisingOptions.build() ) .addOnSuccessListener { logV("Now advertising endpoint $localEndpointName") onAdvertisingStarted() } .addOnFailureListener( object : OnFailureListener { override fun onFailure(e: Exception) { isAdvertising = false logW("startAdvertising() failed.", e) onAdvertisingFailed() } }) }
/** Called when advertising successfully starts. Override this method to act on the event. */ protected fun onAdvertisingStarted() {}
/** Called when advertising fails to start. Override this method to act on the event. */ protected fun onAdvertisingFailed() {}
/** * 원격 엔드포인트와의 보류 중인 연결이 생성될 때 호출됩니다. [연결 정보] 사용 * 연결에 대한 메타데이터(예: 수신 대 발신 또는 인증 토큰). 만약에 * 연결을 계속하려면 [.acceptConnection]을 호출합니다. 그렇지 않으면, * [.rejectConnection]을 호출합니다. */ protected open fun onConnectionInitiated( endpoint: Endpoint?, connectionInfo: ConnectionInfo? ) { }
/** Accepts a connection request. */ protected fun acceptConnection(endpoint: Endpoint) { mConnectionsClient .acceptConnection(endpoint.id, mPayloadCallback) .addOnFailureListener { e -> logW("acceptConnection() failed.", e) } }
/** Rejects a connection request. */ protected fun rejectConnection(endpoint: Endpoint) { mConnectionsClient .rejectConnection(endpoint.id) .addOnFailureListener { e -> logW("rejectConnection() failed.", e) } }
/** * 장치를 검색 모드로 설정합니다. 이제 광고 모드에서 장치를 수신합니다. 어느 하나 * [.onDiscoveryStarted] 또는 [.onDiscoveryFailed]는 일단 찾으면 호출됩니다. * 이 모드에 성공적으로 진입한 경우 출력됩니다. */ protected fun startDiscovering() { isDiscovering = true mDiscoveredEndpoints.clear() val discoveryOptions = DiscoveryOptions.Builder() discoveryOptions.setStrategy(strategy!!) mConnectionsClient .startDiscovery( serviceId, object : EndpointDiscoveryCallback() { override fun onEndpointFound(endpointId: String, info: DiscoveredEndpointInfo) { logD( String.format( "onEndpointFound(endpointId=%s, serviceId=%s, endpointName=%s)", endpointId, info.serviceId, info.endpointName ), "" ) if (serviceId == info.serviceId) { val endpoint = Endpoint(endpointId, info.endpointName) mDiscoveredEndpoints[endpointId] = endpoint onEndpointDiscovered(endpoint) } }
/** Called when discovery successfully starts. Override this method to act on the event. */ protected fun onDiscoveryStarted() {}
/** Called when discovery fails to start. Override this method to act on the event. */ protected fun onDiscoveryFailed() {}
/** * Called when a remote endpoint is discovered. To connect to the device, call [ ][.connectToEndpoint]. */ protected open fun onEndpointDiscovered(endpoint: Endpoint?) {}
/** Disconnects from the given endpoint. */ protected fun disconnect(endpoint: Endpoint) { mConnectionsClient.disconnectFromEndpoint(endpoint.id) mEstablishedConnections.remove(endpoint.id) }
/** Disconnects from all currently connected endpoints. */ protected fun disconnectFromAllEndpoints() { for (endpoint in mEstablishedConnections.values) { mConnectionsClient.disconnectFromEndpoint(endpoint!!.id) } mEstablishedConnections.clear() }
/** Resets and clears all state in Nearby Connections. */ protected fun stopAllEndpoints() { mConnectionsClient.stopAllEndpoints() isAdvertising = false isDiscovering = false isConnecting = false mDiscoveredEndpoints.clear() mPendingConnections.clear() mEstablishedConnections.clear() }
/** * Sends a connection request to the endpoint. Either [.onConnectionInitiated] or [.onConnectionFailed] will be called once we've found out * if we successfully reached the device. */ protected fun connectToEndpoint(endpoint: Endpoint) { logV("Sending a connection request to endpoint $endpoint") // Mark ourselves as connecting so we don't connect multiple times isConnecting = true
/** * Called when a connection with this endpoint has failed. Override this method to act on the * event. */ protected open fun onConnectionFailed(endpoint: Endpoint?) {}
/** Called when someone has connected to us. Override this method to act on the event. */ protected open fun onEndpointConnected(endpoint: Endpoint?) {}
/** Called when someone has disconnected. Override this method to act on the event. */ protected open fun onEndpointDisconnected(endpoint: Endpoint?) {}
/** Returns a list of currently connected endpoints. */ protected val discoveredEndpoints: Set<Endpoint> get() = HashSet(mDiscoveredEndpoints.values)
/** Returns a list of currently connected endpoints. */ protected val connectedEndpoints: Set<Endpoint?> get() = HashSet(mEstablishedConnections.values)
/** * 현재 연결된 모든 엔드포인트에 [페이로드]를 보냅니다. * * @param payload 보내려는 데이터. */ protected fun send(payload: Payload) { send(payload, mEstablishedConnections.keys) }
fun send(payload: Payload, endpoints: Set<String>) { mConnectionsClient .sendPayload(ArrayList(endpoints), payload) .addOnFailureListener { e -> logW("sendPayload() failed.", e) } }
/** * 우리와 연결된 누군가가 우리에게 데이터를 보냈습니다. 이벤트에 대해 작동하도록 이 메서드를 재정의합니다. * * @param endpoint 발신자. * @param payload 데이터. */ protected open fun onReceive(endpoint: Endpoint?, payload: Payload?) {}
/** Returns the client's name. Visible to others when connecting. */ protected abstract val name: String
/** * 서비스 ID를 반환합니다. 이것은 이 연결에 대한 작업을 나타냅니다. 발견할 때, * 연결을 고려하기 전에 광고주가 동일한 서비스 ID를 가지고 있는지 확인합니다. */ protected abstract val serviceId: String
/** * 다른 장치에 연결하는 데 사용하는 전략을 반환합니다. 동일한 전략을 사용하는 장치만 * 및 서비스 ID는 검색 시 나타납니다. Stragies는 들어오고 나가는 수를 결정합니다. * 동시에 연결이 가능하며 사용 가능한 대역폭은 얼마입니까? */ protected abstract val strategy: Strategy? @CallSuper protected open fun logV(msg: String) { Log.e(Constants.TAG, msg) }
@CallSuper protected open fun logD(msg: String, s: String) { Log.e(Constants.TAG, String.format("%s %s", msg, s)) }
@CallSuper protected open fun logW(msg: String) { Log.e(Constants.TAG, msg) }
@CallSuper protected open fun logW(msg: String, e: Throwable) { Log.e(Constants.TAG, msg, e) }
@CallSuper protected open fun logE(msg: String, e: Throwable) { Log.e(Constants.TAG, msg, e) }
protected open fun doSendNearBy(auth: FirebaseAuth) {}
protected open fun doAdvertSendNearBy() {}
/** Represents a device we can talk to. */ protected class Endpoint(val id: String, val name: String) {
override fun equals(other: Any?): Boolean { if (other is Endpoint) { return id == other.id } return false }
override fun hashCode(): Int { return id.hashCode() }
오늘은 여기까지 기술해 보겠습니다. 다음 이야기는 테스트 중에 발견된 일부 사항을 수정한 다음 계속해 보겠습니다.
** 어제 확인이 미처 되지 못했던 부분에 대한 확인을 오늘에야 끝냈습니다. 일단, 권한 기술하는 부분에서 android 13에 맞게 기술이 되지 않았던 부분이 확인이 되었습니다. 2023.05.31 이전에 보셨다면 다시 확인해 보셔야 할 것 같습니다.
아무튼 이렇게 기술해서 정리를 하고 나니 앱에서 상호 접속 하는 부분등이 정리가 되는 것을 확인할 수 있었습니다.
neayby 샘플 화면
연결이 되고 나면 오른쪽 상단에 개발자 페이지에 제공된 nearby 공식 이미지를 사이즈만 조금 줄여서 표시가 되도록 하였더니, 노출이 됩니다. 연결되었다는 메시지도 나오고요.
잠깐 동안의 영상을 통해서 접속이 잘 되는 지도 확인해 볼 수 있었습니다.
이렇게 작성된 예제 코드는 아무튼 위에 있는 github을 참고해 보시도록 하시면 되겠습니다. 오늘도 즐 코딩 하세요.
p.s : 한 가지 정리 중인 부분은 payload에 byte 문자열을 보내는 것을 테스트해보고 있는 데, 이미지를 byte 문자열로 해서 보내려고 했더니 아주 작은 사이즈 이미지 말고는 불가능해 보입니다. 그래서 다음번에는 file로 저장해서 전달하는 기능을 구현해 보고 정리를 해 보도록 하겠습니다.
#billcorea #운동동아리관리앱 🏸 Schneedle, một ứng dụng cần có cho các câu lạc bộ cầu lông! 👉 Đấu trận – Ghi điểm & Tìm đối thủ 🎉 Hoàn hảo cho mọi nơi, một mình, với bạn bè hoặc trong câu lạc bộ! 🤝 Nếu bạn thích cầu lông, nhất định phải thử nó
Vào ứng dụng 👉 https://play.google.com/store/apps/details?id=com.billcorea.matchplay
#스하리1000명프로젝트, ¿Perdido en Corea? Incluso si no hablas coreano, esta aplicación te ayuda a moverte fácilmente. Simplemente hable su idioma: traduce, busca y muestra resultados en su idioma. ¡Genial para viajeros! Admite más de 10 idiomas, incluidos inglés, japonés, chino, vietnamita y más. ¡Pruébalo ahora! https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127
1. Draw a beautiful sunset over the ocean. 2. Draw a cute puppy playing with a ball. 3. Draw a majestic mountain range with snow on the peaks. 4. Draw a delicious-looking pizza with all your favorite toppings. 5. Draw a serene forest with a small stream running through it. 6. Draw a futuristic city with flying cars and neon lights. 7. Draw a cozy cabin in the woods with a roaring fire inside. 8. Draw a magical castle with turrets and a moat. 9. Draw a peaceful garden with blooming flowers and a pond. 10. Draw a group of friends having a picnic in a park. 11. Draw a spooky haunted house with ghosts and bats. 12. Draw a bustling city street filled with people and shops. 13. Draw a beautiful butterfly perched on a flower. 14. Draw a majestic unicorn running through a meadow. 15. Draw a delicious-looking ice cream sundae with all the toppings. 16. Draw a serene beach with palm trees and clear blue water. 17. Draw a playful dolphin jumping out of the ocean. 18. Draw a beautiful rainbow over a field of flowers. 19. Draw a cozy coffee shop with comfortable chairs and good music. 20. Draw a fierce dragon guarding its treasure hoard.