feat/refactor: добавил индикатор при просмотре кружков/гс, сделал запись кружков нормальным членом общества

This commit is contained in:
Jganenokk
2026-08-08 00:36:20 +07:00
parent 7a9e08f5c7
commit 7bbc77192a
24 changed files with 1614 additions and 198 deletions
@@ -84,6 +84,7 @@ class MainActivity : FlutterActivity() {
const val NFC_PHASE_MIN_MS = 350L
const val NFC_PHASE_JITTER_MS = 400
const val BLE_PERMS_REQUEST = 7711
const val CAMERA_PERM_REQUEST = 7712
val NFC_READER_FLAGS = NfcAdapter.FLAG_READER_NFC_A or
NfcAdapter.FLAG_READER_NFC_B or
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK
@@ -241,6 +242,7 @@ class MainActivity : FlutterActivity() {
"ru.komet.app/video_note",
).setMethodCallHandler { call, result ->
when (call.method) {
"permission" -> requestCameraPermission(result)
"init" -> {
val front = call.argument<Boolean>("front") ?: true
val size = call.argument<Int>("size") ?: 480
@@ -258,6 +260,10 @@ class MainActivity : FlutterActivity() {
"start" -> noteRecorder?.start(result)
?: result.error("NOT_READY", "recorder not initialized", null)
"switch" -> noteRecorder?.switchCamera(result)
"torch" -> noteRecorder?.setTorch(
call.argument<Boolean>("on") ?: false,
result,
)
?: result.error("NOT_READY", "recorder not initialized", null)
"stop" -> noteRecorder?.stop(result)
?: result.error("NOT_READY", "recorder not initialized", null)
@@ -595,12 +601,42 @@ class MainActivity : FlutterActivity() {
}
}
private var cameraPermResult: MethodChannel.Result? = null
private fun requestCameraPermission(result: MethodChannel.Result) {
val granted = ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA,
) == PackageManager.PERMISSION_GRANTED
if (granted) {
result.success(true); return
}
if (cameraPermResult != null) {
result.success(false); return
}
cameraPermResult = result
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
CAMERA_PERM_REQUEST,
)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray,
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == CAMERA_PERM_REQUEST) {
val pending = cameraPermResult
cameraPermResult = null
pending?.success(
grantResults.isNotEmpty() &&
grantResults.all { it == PackageManager.PERMISSION_GRANTED },
)
return
}
if (requestCode != BLE_PERMS_REQUEST) return
if (!NfcExchange.active) return
val granted = grantResults.isNotEmpty() &&
@@ -62,6 +62,9 @@ class VideoNoteRecorder(
private var fpsRange: Range<Int>? = null
private var hasOis = false
private var hasEis = false
private var hasFlash = false
private var torchOn = false
private var previewRequest: CaptureRequest.Builder? = null
private var cameraDevice: CameraDevice? = null
private var session: CameraCaptureSession? = null
@@ -119,6 +122,8 @@ class VideoNoteRecorder(
)?.contains(
CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_ON,
) == true
hasFlash = ch.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true
if (!hasFlash) torchOn = false
return true
}
}
@@ -310,13 +315,21 @@ class VideoNoteRecorder(
CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON,
)
}
previewRequest = req
applyTorch(req)
s.setRepeatingRequest(req.build(), null, camHandler)
Log.i(
tag,
"preview session configured fpsRange=$fpsRange " +
"ois=$hasOis eis=$hasEis",
"ois=$hasOis eis=$hasEis flash=$hasFlash",
)
result.success(
mapOf(
"textureId" to textureId,
"size" to edge,
"hasFlash" to hasFlash,
),
)
result.success(mapOf("textureId" to textureId, "size" to edge))
}
} catch (e: Exception) {
Log.e(tag, "preview session failed", e)
@@ -377,6 +390,38 @@ class VideoNoteRecorder(
// Смена камеры на лету (в т.ч. во время записи): GL-конвейер и
// MediaRecorder не трогаем, пересоздаются только CameraDevice и сессия —
// кадры новой камеры продолжают приходить в тот же SurfaceTexture.
private fun applyTorch(req: CaptureRequest.Builder) {
req.set(
CaptureRequest.FLASH_MODE,
if (torchOn && hasFlash) {
CaptureRequest.FLASH_MODE_TORCH
} else {
CaptureRequest.FLASH_MODE_OFF
},
)
}
fun setTorch(on: Boolean, result: MethodChannel.Result) {
if (!hasFlash) {
result.success(false); return
}
val s = session
val req = previewRequest
if (s == null || req == null) {
result.error("NOT_READY", "no preview session", null); return
}
torchOn = on
try {
applyTorch(req)
s.setRepeatingRequest(req.build(), null, camHandler)
result.success(torchOn)
} catch (e: Exception) {
Log.e(tag, "torch failed", e)
torchOn = false
result.error("TORCH_FAILED", e.message, null)
}
}
fun switchCamera(rawResult: MethodChannel.Result) {
val result = OnceResult(rawResult)
if (cameraDevice == null || !glReady) {
@@ -389,6 +434,7 @@ class VideoNoteRecorder(
}
try { session?.close() } catch (_: Exception) {}
session = null
previewRequest = null
try { cameraDevice?.close() } catch (_: Exception) {}
cameraDevice = null
if (!selectCamera(newFacing)) {