Skip to content

Commit

Permalink
Merge branch 'trunk' into feature/notifications_refresh_p2
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonis Lilis committed May 31, 2024
2 parents 4f00ccc + ec01193 commit e52ef49
Show file tree
Hide file tree
Showing 48 changed files with 953 additions and 384 deletions.
2 changes: 1 addition & 1 deletion RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

25.1
-----

* [*] [internal] Block editor: Add onContentUpdate bridge functionality [https://github.com/wordpress-mobile/gutenberg-mobile/pull/20852]

25.0
-----
Expand Down
6 changes: 3 additions & 3 deletions WordPress/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,15 @@ dependencies {
implementation (project(path:':libs:editor')) {
exclude group: 'org.wordpress', module: 'utils'
}
implementation("$gradle.ext.fluxCBinaryPath") {
implementation("$gradle.ext.fluxCBinaryPath:$wordPressFluxCVersion") {
version {
strictly wordPressFluxCVersion
}
exclude group: "com.android.volley"
exclude group: 'org.wordpress', module: 'utils'
exclude group: 'com.android.support', module: 'support-annotations'
}
implementation ("$gradle.ext.wputilsBinaryPath") {
implementation ("$gradle.ext.wputilsBinaryPath:$wordPressUtilsVersion") {
version {
strictly wordPressUtilsVersion
}
Expand All @@ -383,7 +383,7 @@ dependencies {
}
implementation "$gradle.ext.aboutAutomatticBinaryPath:$automatticAboutVersion"

implementation("$gradle.ext.tracksBinaryPath") {
implementation("$gradle.ext.tracksBinaryPath:$automatticTracksVersion") {
version {
strictly automatticTracksVersion
}
Expand Down
3 changes: 3 additions & 0 deletions WordPress/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
android:name="android.permission.DUMP"
tools:ignore="ProtectedPermissions" />

<!-- Adds this permission temporarily here until Voice to content project is released -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

<application
android:name=".WordPressDebug"
android:supportsRtl="true"
Expand Down
1 change: 1 addition & 0 deletions WordPress/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<!-- Required for storing and retrieving screenshots, taking photos, accessing media files -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ import org.wordpress.android.util.config.OpenWebLinksWithJetpackFlowFeatureConfi
import org.wordpress.android.util.enqueuePeriodicUploadWorkRequestForAllSites
import org.wordpress.android.util.experiments.ExPlat
import org.wordpress.android.util.image.ImageManager
import org.wordpress.android.widgets.AppRatingDialog
import org.wordpress.android.widgets.AppReviewManager
import org.wordpress.android.workers.WordPressWorkersFactory
import java.io.File
import java.io.IOException
Expand Down Expand Up @@ -303,7 +303,7 @@ class AppInitializer @Inject constructor(
initWpDb()
context?.let { enableHttpResponseCache(it) }

AppRatingDialog.init(application)
AppReviewManager.init(application)

if (!initialized) {
// EventBus setup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
import org.wordpress.android.ui.sitecreation.SiteCreationStep;
import org.wordpress.android.ui.sitecreation.SiteCreationStepsProvider;
import org.wordpress.android.util.BuildConfigWrapper;
import org.wordpress.android.util.audio.AudioRecorder;
import org.wordpress.android.util.audio.IAudioRecorder;
import org.wordpress.android.util.audio.RecordingStrategy;
import org.wordpress.android.util.audio.RecordingStrategy.VoiceToContentRecordingStrategy;
import org.wordpress.android.util.audio.VoiceToContentStrategy;
import org.wordpress.android.util.config.InAppUpdatesFeatureConfig;
import org.wordpress.android.util.config.RemoteConfigWrapper;
import org.wordpress.android.util.wizard.WizardManager;
Expand Down Expand Up @@ -121,4 +126,19 @@ public static ActivityNavigator provideActivityNavigator(@ApplicationContext Con
public static SensorManager provideSensorManager(@ApplicationContext Context context) {
return (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
}

@VoiceToContentStrategy
@Provides
public static IAudioRecorder provideAudioRecorder(
@ApplicationContext Context context,
@VoiceToContentStrategy RecordingStrategy recordingStrategy
) {
return new AudioRecorder(context, recordingStrategy);
}

@VoiceToContentStrategy
@Provides
public static RecordingStrategy provideVoiceToContentRecordingStrategy() {
return new VoiceToContentRecordingStrategy();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import org.wordpress.android.ui.reader.viewmodels.ReaderPostListViewModel;
import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel;
import org.wordpress.android.ui.reader.viewmodels.SubfilterPageViewModel;
import org.wordpress.android.ui.review.ReviewViewModel;
import org.wordpress.android.ui.stats.refresh.lists.DaysListViewModel;
import org.wordpress.android.ui.stats.refresh.lists.InsightsDetailListViewModel;
import org.wordpress.android.ui.stats.refresh.lists.InsightsListViewModel;
Expand Down Expand Up @@ -461,11 +460,6 @@ abstract class ViewModelModule {
@ViewModelKey(UnifiedCommentListViewModel.class)
abstract ViewModel unifiedCommentListViewModel(UnifiedCommentListViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(ReviewViewModel.class)
abstract ViewModel reviewViewModel(ReviewViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(BloggingRemindersViewModel.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,20 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import org.wordpress.android.ui.compose.theme.AppTheme
import androidx.camera.core.Preview as CameraPreview

@Composable
fun BarcodeScanner(
codeScanner: CodeScanner,
onScannedResult: (Flow<CodeScannerStatus>) -> Unit
onScannedResult: CodeScannerCallback
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val cameraProviderFuture = remember {
ProcessCameraProvider.getInstance(context)
}

Column(
modifier = Modifier.fillMaxSize()
) {
Expand All @@ -51,30 +50,27 @@ fun BarcodeScanner(
.setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context)) { imageProxy ->
onScannedResult(codeScanner.startScan(imageProxy))
val callback = object : CodeScannerCallback {
override fun run(status: CodeScannerStatus?) {
status?.let { onScannedResult.run(it) }
}
}
codeScanner.startScan(imageProxy, callback)
}
try {
cameraProviderFuture.get().bindToLifecycle(lifecycleOwner, selector, preview, imageAnalysis)
} catch (e: IllegalStateException) {
onScannedResult(
flowOf(
CodeScannerStatus.Failure(
e.message
?: "Illegal state exception while binding camera provider to lifecycle",
CodeScanningErrorType.Other(e)
)
)
)
onScannedResult.run(CodeScannerStatus.Failure(
e.message
?: "Illegal state exception while binding camera provider to lifecycle",
CodeScanningErrorType.Other(e)
))
} catch (e: IllegalArgumentException) {
onScannedResult(
flowOf(
CodeScannerStatus.Failure(
e.message
?: "Illegal argument exception while binding camera provider to lifecycle",
CodeScanningErrorType.Other(e)
)
)
)
onScannedResult.run(CodeScannerStatus.Failure(
e.message
?: "Illegal argument exception while binding camera provider to lifecycle",
CodeScanningErrorType.Other(e)
))
}
previewView
},
Expand All @@ -84,8 +80,8 @@ fun BarcodeScanner(
}

class DummyCodeScanner : CodeScanner {
override fun startScan(imageProxy: ImageProxy): Flow<CodeScannerStatus> {
return flowOf(CodeScannerStatus.Success("", GoogleBarcodeFormatMapper.BarcodeFormat.FormatUPCA))
override fun startScan(imageProxy: ImageProxy, callback: CodeScannerCallback) {
callback.run(CodeScannerStatus.Success("", GoogleBarcodeFormatMapper.BarcodeFormat.FormatUPCA))
}
}

Expand All @@ -94,6 +90,10 @@ class DummyCodeScanner : CodeScanner {
@Composable
private fun BarcodeScannerScreenPreview() {
AppTheme {
BarcodeScanner(codeScanner = DummyCodeScanner(), onScannedResult = {})
BarcodeScanner(codeScanner = DummyCodeScanner(), onScannedResult = object : CodeScannerCallback {
override fun run(status: CodeScannerStatus?) {
// no-ops
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.wordpress.android.R
import kotlinx.coroutines.flow.Flow
import org.wordpress.android.ui.compose.theme.AppTheme

@Composable
fun BarcodeScannerScreen(
codeScanner: CodeScanner,
permissionState: BarcodeScanningViewModel.PermissionState,
onResult: (Boolean) -> Unit,
onScannedResult: (Flow<CodeScannerStatus>) -> Unit,
onScannedResult: CodeScannerCallback,
) {
val cameraPermissionLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.wordpress.android.ui.compose.theme.AppTheme
import org.wordpress.android.util.WPPermissionUtils
import javax.inject.Inject
Expand Down Expand Up @@ -52,12 +48,10 @@ class BarcodeScanningFragment : Fragment() {
shouldShowRequestPermissionRationale(KEY_CAMERA_PERMISSION)
)
},
onScannedResult = { codeScannerStatus ->
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
codeScannerStatus.collect { status ->
setResultAndPopStack(status)
}
onScannedResult = object : CodeScannerCallback {
override fun run(status: CodeScannerStatus?) {
if (status != null) {
setResultAndPopStack(status)
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package org.wordpress.android.ui.barcodescanner

import android.os.Parcelable
import androidx.camera.core.ImageProxy
import kotlinx.coroutines.flow.Flow
import kotlinx.parcelize.Parcelize

interface CodeScanner {
fun startScan(imageProxy: ImageProxy): Flow<CodeScannerStatus>
fun startScan(imageProxy: ImageProxy, callback: CodeScannerCallback)
}

interface CodeScannerCallback {
fun run(status: CodeScannerStatus?)
}

sealed class CodeScannerStatus : Parcelable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ package org.wordpress.android.ui.barcodescanner
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScanner
import com.google.mlkit.vision.barcode.common.Barcode
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import javax.inject.Inject

class GoogleMLKitCodeScanner @Inject constructor(
Expand All @@ -17,53 +13,41 @@ class GoogleMLKitCodeScanner @Inject constructor(
) : CodeScanner {
private var barcodeFound = false
@androidx.camera.core.ExperimentalGetImage
override fun startScan(imageProxy: ImageProxy): Flow<CodeScannerStatus> {
return callbackFlow {
val barcodeTask = barcodeScanner.process(inputImageProvider.provideImage(imageProxy))
barcodeTask.addOnCompleteListener {
// We must call image.close() on received images when finished using them.
// Otherwise, new images may not be received or the camera may stall.
imageProxy.close()
}
barcodeTask.addOnSuccessListener { barcodeList ->
// The check for barcodeFound is done because the startScan method will be called
// continuously by the library as long as we are in the scanning screen.
// There will be a good chance that the same barcode gets identified multiple times and as a result
// success callback will be called multiple times.
if (!barcodeList.isNullOrEmpty() && !barcodeFound) {
barcodeFound = true
handleScanSuccess(barcodeList.firstOrNull())
this@callbackFlow.close()
}
}
barcodeTask.addOnFailureListener { exception ->
this@callbackFlow.trySend(
CodeScannerStatus.Failure(
error = exception.message,
type = errorMapper.mapGoogleMLKitScanningErrors(exception)
)
)
this@callbackFlow.close()
override fun startScan(imageProxy: ImageProxy, callback: CodeScannerCallback) {
val barcodeTask = barcodeScanner.process(inputImageProvider.provideImage(imageProxy))
barcodeTask.addOnCompleteListener {
// We must call image.close() on received images when finished using them.
// Otherwise, new images may not be received or the camera may stall.
imageProxy.close()
}
barcodeTask.addOnSuccessListener { barcodeList ->
// The check for barcodeFound is done because the startScan method will be called
// continuously by the library as long as we are in the scanning screen.
// There will be a good chance that the same barcode gets identified multiple times and as a result
// success callback will be called multiple times.
if (!barcodeList.isNullOrEmpty() && !barcodeFound) {
barcodeFound = true
callback.run(handleScanSuccess(barcodeList.firstOrNull()))
}

awaitClose()
}
barcodeTask.addOnFailureListener { exception ->
callback.run(CodeScannerStatus.Failure(
error = exception.message,
type = errorMapper.mapGoogleMLKitScanningErrors(exception)
))
}
}

private fun ProducerScope<CodeScannerStatus>.handleScanSuccess(code: Barcode?) {
code?.rawValue?.let {
trySend(
CodeScannerStatus.Success(
it,
barcodeFormatMapper.mapBarcodeFormat(code.format)
)
private fun handleScanSuccess(code: Barcode?): CodeScannerStatus {
return code?.rawValue?.let {
CodeScannerStatus.Success(
it,
barcodeFormatMapper.mapBarcodeFormat(code.format)
)
} ?: run {
trySend(
CodeScannerStatus.Failure(
error = "Failed to find a valid raw value!",
type = CodeScanningErrorType.Other(Throwable("Empty raw value"))
)
CodeScannerStatus.Failure(
error = "Failed to find a valid raw value!",
type = CodeScanningErrorType.Other(Throwable("Empty raw value"))
)
}
}
Expand Down
Loading

0 comments on commit e52ef49

Please sign in to comment.