messenger-android

Android graphical user interfaces for GNUnet Messenger
Log | Files | Refs | README | LICENSE

LobbyJoinFragment.kt (5878B)


      1 /*
      2    This file is part of GNUnet.
      3    Copyright (C) 2021--2025 GNUnet e.V.
      4 
      5    GNUnet is free software: you can redistribute it and/or modify it
      6    under the terms of the GNU Affero General Public License as published
      7    by the Free Software Foundation, either version 3 of the License,
      8    or (at your option) any later version.
      9 
     10    GNUnet is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    Affero General Public License for more details.
     14 
     15    You should have received a copy of the GNU Affero General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18    SPDX-License-Identifier: AGPL3.0-or-later
     19  */
     20 /*
     21  * @author t3sserakt
     22  * @file GNUnetMessenger/app/src/main/java/org/gnunet/gnunetmessenger/ui/contact/LobbyJoinFragment.kt
     23  */
     24 
     25 package org.gnunet.gnunetmessenger.ui.contact
     26 
     27 import android.Manifest
     28 import android.content.pm.PackageManager
     29 import android.os.Bundle
     30 import android.util.Log
     31 import android.view.*
     32 import android.widget.Button
     33 import android.widget.EditText
     34 import androidx.annotation.OptIn
     35 import androidx.camera.core.*
     36 import androidx.camera.lifecycle.ProcessCameraProvider
     37 import androidx.camera.view.PreviewView
     38 import androidx.core.app.ActivityCompat
     39 import androidx.core.content.ContextCompat
     40 import androidx.fragment.app.Fragment
     41 import androidx.lifecycle.lifecycleScope
     42 import androidx.navigation.fragment.findNavController
     43 import org.gnunet.gnunetmessenger.R
     44 import com.google.mlkit.vision.barcode.BarcodeScanning
     45 import com.google.mlkit.vision.common.InputImage
     46 import org.gnunet.gnunetmessenger.MainActivity
     47 import java.util.concurrent.Executors
     48 import kotlinx.coroutines.launch
     49 
     50 class LobbyJoinFragment : Fragment() {
     51 
     52     private lateinit var previewView: PreviewView
     53     private lateinit var qrText: EditText
     54     private lateinit var joinButton: Button
     55     private lateinit var cancelButton: Button
     56 
     57     private val cameraExecutor = Executors.newSingleThreadExecutor()
     58 
     59     override fun onCreateView(
     60         inflater: LayoutInflater,
     61         container: ViewGroup?,
     62         savedInstanceState: Bundle?
     63     ): View {
     64         val view = inflater.inflate(R.layout.fragment_join_lobby, container, false)
     65 
     66         previewView = view.findViewById(R.id.camera_preview)
     67         qrText = view.findViewById(R.id.qr_text)
     68         joinButton = view.findViewById(R.id.join_button)
     69         cancelButton = view.findViewById(R.id.cancel_button)
     70 
     71         joinButton.setOnClickListener {
     72             val lobbyId = qrText.text.toString()
     73             val activity = activity as MainActivity
     74             val gnunetChat = activity.getGnunetChatInstance()
     75             val handle = activity.getChatHandle()
     76             viewLifecycleOwner.lifecycleScope.launch {
     77                 try {
     78                     gnunetChat.lobbyJoin(handle, lobbyId)
     79                     findNavController().popBackStack()
     80                 } catch (t: Throwable) {
     81                     android.util.Log.e("LobbyJoinFragment", "lobbyJoin failed", t)
     82                 }
     83             }
     84         }
     85 
     86         cancelButton.setOnClickListener {
     87             findNavController().popBackStack()
     88         }
     89 
     90         if (allPermissionsGranted()) {
     91             startCamera()
     92         } else {
     93             requestPermissions(arrayOf(Manifest.permission.CAMERA), 10)
     94         }
     95 
     96         return view
     97     }
     98 
     99     private fun startCamera() {
    100         val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
    101 
    102         cameraProviderFuture.addListener({
    103             val cameraProvider = cameraProviderFuture.get()
    104             val preview = Preview.Builder().build().also {
    105                 it.setSurfaceProvider(previewView.surfaceProvider)
    106             }
    107 
    108             val barcodeScanner = BarcodeScanning.getClient()
    109 
    110             val analysis = ImageAnalysis.Builder()
    111                 .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    112                 .build()
    113 
    114             analysis.setAnalyzer(cameraExecutor) { imageProxy ->
    115                 processImageProxy(barcodeScanner, imageProxy)
    116             }
    117 
    118             val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
    119 
    120             try {
    121                 cameraProvider.unbindAll()
    122                 cameraProvider.bindToLifecycle(this, cameraSelector, preview, analysis)
    123             } catch (e: Exception) {
    124                 Log.e("LobbyJoinFragment", "Camera binding failed", e)
    125             }
    126 
    127         }, ContextCompat.getMainExecutor(requireContext()))
    128     }
    129 
    130     @OptIn(ExperimentalGetImage::class)
    131     private fun processImageProxy(scanner: com.google.mlkit.vision.barcode.BarcodeScanner, imageProxy: ImageProxy) {
    132         val mediaImage = imageProxy.image ?: run {
    133             imageProxy.close()
    134             return
    135         }
    136 
    137         val inputImage = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
    138         scanner.process(inputImage)
    139             .addOnSuccessListener { barcodes ->
    140                 for (barcode in barcodes) {
    141                     val rawValue = barcode.rawValue
    142                     if (!rawValue.isNullOrBlank()) {
    143                         requireActivity().runOnUiThread {
    144                             qrText.setText(rawValue)
    145                         }
    146                         break
    147                     }
    148                 }
    149             }
    150             .addOnFailureListener {
    151                 Log.e("LobbyJoinFragment", "Barcode scan failed", it)
    152             }
    153             .addOnCompleteListener {
    154                 imageProxy.close()
    155             }
    156     }
    157 
    158     private fun allPermissionsGranted() =
    159         ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
    160 
    161     override fun onDestroy() {
    162         super.onDestroy()
    163         cameraExecutor.shutdown()
    164     }
    165 }