diff --git a/app/build.gradle b/app/build.gradle index 96e5ead2..429d9a07 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,7 @@ android { applicationId "com.mickstarify.zooforzotero" minSdkVersion 23 targetSdkVersion 34 - versionCode 48 + versionCode 49 versionName "3.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField("String", "zotero_api_key", apikeyProperties['zotero_api_key']) @@ -43,10 +43,7 @@ android { namespace 'com.mickstarify.zooforzotero' } -apply plugin: 'com.google.gms.google-services' apply plugin: 'kotlin-kapt' -// Apply the Crashlytics Gradle plugin -apply plugin: 'com.google.firebase.crashlytics' dependencies { def nav_version = "2.3.5" @@ -92,20 +89,14 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' - // facebook flipper - debugImplementation 'com.facebook.flipper:flipper:0.91.1' - debugImplementation 'com.facebook.soloader:soloader:0.10.1' - releaseImplementation 'com.facebook.flipper:flipper-noop:0.91.1' - // Room Dependencies implementation "androidx.room:room-runtime:2.6.1" implementation 'androidx.room:room-rxjava2:2.6.1' kapt "androidx.room:room-compiler:2.6.1" - // crashlytics - implementation platform('com.google.firebase:firebase-bom:32.7.1') - implementation 'com.google.firebase:firebase-analytics' - implementation 'com.google.firebase:firebase-crashlytics' + def acraVersion = "5.11.3" + implementation "ch.acra:acra-mail:$acraVersion" + implementation("ch.acra:acra-dialog:$acraVersion") implementation "com.google.dagger:hilt-android:2.46" kapt "com.google.dagger:hilt-compiler:2.46" @@ -113,9 +104,6 @@ dependencies { // for fab on main screen implementation 'com.getbase:floatingactionbutton:1.10.1' - // barcode stuff - implementation 'com.google.android.gms:play-services-vision:20.1.3' - // for webdav implementation "io.github.rburgst:okhttp-digest:2.5" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8cfe0327..86720af7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ - + diff --git a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/BarcodeScanningScreen.kt b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/BarcodeScanningScreen.kt index 6c40ff1c..fcb742bc 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/BarcodeScanningScreen.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/BarcodeScanningScreen.kt @@ -1,248 +1,245 @@ -package com.mickstarify.zooforzotero.LibraryActivity.Fragments - -import android.Manifest -import android.content.Context -import android.content.pm.PackageManager -import android.graphics.BitmapFactory -import android.graphics.ImageFormat -import android.hardware.camera2.CameraAccessException -import android.hardware.camera2.CameraCaptureSession -import android.hardware.camera2.CameraCharacteristics -import android.hardware.camera2.CameraDevice -import android.hardware.camera2.CameraManager -import android.media.ImageReader -import android.os.Bundle -import android.os.Handler -import android.util.Log -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.SurfaceHolder -import android.view.SurfaceView -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import androidx.navigation.fragment.findNavController -import com.google.android.gms.vision.Frame -import com.google.android.gms.vision.barcode.Barcode -import com.google.android.gms.vision.barcode.BarcodeDetector -import com.mickstarify.zooforzotero.LibraryActivity.ViewModels.LibraryListViewModel -import com.mickstarify.zooforzotero.R - -class BarcodeScanningScreen : Fragment() { - - companion object { - fun newInstance() = BarcodeScanningScreen() - const val REQUEST_CAMERA = 1729 - } - - private lateinit var viewModel: LibraryListViewModel - lateinit var cameraView: SurfaceView - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.barcode_scanning_screen_fragment, container, false) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - menu.clear() - inflater.inflate(R.menu.barcode_scanning_menu, menu) - super.onCreateOptionsMenu(menu, inflater) - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - setHasOptionsMenu(true) - viewModel = ViewModelProvider(requireActivity()).get(LibraryListViewModel::class.java) - - cameraView = requireView().findViewById(R.id.cameraPreview) - cameraView.holder.addCallback(object : SurfaceHolder.Callback { - override fun surfaceCreated(holder: SurfaceHolder) {} - override fun surfaceDestroyed(holder: SurfaceHolder) {} - - override fun surfaceChanged( - holder: SurfaceHolder, - format: Int, - width: Int, - height: Int - ) { - showCameraPreview(width, height) - } - }) - } - - override fun onStart() { - super.onStart() - - if (ContextCompat.checkSelfPermission( - requireContext(), - Manifest.permission.CAMERA - ) != PackageManager.PERMISSION_GRANTED - ) { - requestPermissions(arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA) - } else { - // start camera feed - } - } - - // we will use this to determine the amount of frames in a row that we detect a barcode. - // this is done for accuracy reasons as using one frame was allowing the phone to misdetect - // barcodes. - var detectedInARow: Int = 0 - var lastChange = 0L - var lastReadBarcodeNo: String = "" - - var camera: CameraDevice? = null - - fun showCameraPreview(width: Int, height: Int) { - val cameraView = requireView().findViewById(R.id.cameraPreview) - - try { - val cameraBkgHandler = Handler() - - val cameraManager = - requireActivity().getSystemService(Context.CAMERA_SERVICE) as CameraManager - - cameraManager.cameraIdList.find { - val characteristics = cameraManager.getCameraCharacteristics(it) - val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING) - - return@find cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_BACK - }?.let { - val cameraStateCallback = object : CameraDevice.StateCallback() { - override fun onOpened(camera: CameraDevice) { - this@BarcodeScanningScreen.camera = camera - val barcodeDetector = BarcodeDetector.Builder(requireContext()) - .setBarcodeFormats(Barcode.ALL_FORMATS) - .build() - - if (barcodeDetector.isOperational == false) { - Toast.makeText( - requireContext(), - "Google mobile services (GMS) unable. Barcode scanning unsupported.", - Toast.LENGTH_SHORT - ).show() - stopScanning() - } - - val imgReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1) - imgReader.setOnImageAvailableListener({ reader -> - val cameraImage = reader.acquireNextImage() - val buffer = cameraImage.planes.first().buffer - val bytes = ByteArray(buffer.capacity()) - buffer.get(bytes) - - val bitmap = - BitmapFactory.decodeByteArray(bytes, 0, bytes.count(), null) - val frameToProcess = Frame.Builder().setBitmap(bitmap).build() - val barcodeResults = barcodeDetector.detect(frameToProcess) - if (barcodeResults.size() > 0) { - // Scanned a barcode! - val result = barcodeResults.valueAt(0) - Log.d("zotero", "scanned ${result.rawValue}") - if (result.rawValue == lastReadBarcodeNo) { - detectedInARow++ - } else { - detectedInARow = 0 - lastReadBarcodeNo = result.rawValue - } - - if (detectedInARow == 3) { - val barcodeNo = barcodeResults.valueAt(0).rawValue - viewModel.scannedBarcodeNumber(barcodeNo) - stopScanning() - } - } else { - } - try { - cameraImage.close() - } catch (e: IllegalStateException) { - // camera already closed. - } - - }, cameraBkgHandler) - - val captureStateCallback = object : CameraCaptureSession.StateCallback() { - override fun onConfigured(session: CameraCaptureSession) { - val builder = - camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) - - builder.addTarget(cameraView.holder.surface) - builder.addTarget(imgReader.surface) - session.setRepeatingRequest(builder.build(), null, null) - } - - override fun onConfigureFailed(session: CameraCaptureSession) { - } - } - - camera.createCaptureSession( - listOf(cameraView.holder.surface, imgReader.surface), - captureStateCallback, - cameraBkgHandler - ) - } - - override fun onClosed(camera: CameraDevice) { - } - - override fun onDisconnected(camera: CameraDevice) { - } - - override fun onError(camera: CameraDevice, error: Int) { - } - } - - cameraManager.openCamera(it, cameraStateCallback, cameraBkgHandler) - return - } - - } catch (e: CameraAccessException) { - } catch (e: SecurityException) { - } - } - - private fun stopScanning() { - try { - this.camera?.close() - } catch (e: IllegalStateException) { - // camera already closed. - } - findNavController().navigateUp() - } - - override fun onStop() { - super.onStop() - try { - this.camera?.close() - } catch (e: IllegalStateException) { - // camera already closed. - } - } - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - - if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED - && requestCode == REQUEST_CAMERA - ) { - showCameraPreview(cameraView.measuredWidth, cameraView.measuredHeight) - } else { - Toast.makeText( - requireContext(), - "This functionality requires the camera. Please provide the camera permission.", - Toast.LENGTH_SHORT - ).show() - findNavController().navigateUp() - } - } -} \ No newline at end of file +//package com.mickstarify.zooforzotero.LibraryActivity.Fragments +// +//import android.Manifest +//import android.content.Context +//import android.content.pm.PackageManager +//import android.graphics.BitmapFactory +//import android.graphics.ImageFormat +//import android.hardware.camera2.CameraAccessException +//import android.hardware.camera2.CameraCaptureSession +//import android.hardware.camera2.CameraCharacteristics +//import android.hardware.camera2.CameraDevice +//import android.hardware.camera2.CameraManager +//import android.media.ImageReader +//import android.os.Bundle +//import android.os.Handler +//import android.util.Log +//import android.view.LayoutInflater +//import android.view.Menu +//import android.view.MenuInflater +//import android.view.SurfaceHolder +//import android.view.SurfaceView +//import android.view.View +//import android.view.ViewGroup +//import android.widget.Toast +//import androidx.core.content.ContextCompat +//import androidx.fragment.app.Fragment +//import androidx.lifecycle.ViewModelProvider +//import androidx.navigation.fragment.findNavController +//import com.mickstarify.zooforzotero.LibraryActivity.ViewModels.LibraryListViewModel +//import com.mickstarify.zooforzotero.R +// +//class BarcodeScanningScreen : Fragment() { +// +// companion object { +// fun newInstance() = BarcodeScanningScreen() +// const val REQUEST_CAMERA = 1729 +// } +// +// private lateinit var viewModel: LibraryListViewModel +// lateinit var cameraView: SurfaceView +// +// override fun onCreateView( +// inflater: LayoutInflater, container: ViewGroup?, +// savedInstanceState: Bundle? +// ): View? { +// return inflater.inflate(R.layout.barcode_scanning_screen_fragment, container, false) +// } +// +// override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { +// menu.clear() +// inflater.inflate(R.menu.barcode_scanning_menu, menu) +// super.onCreateOptionsMenu(menu, inflater) +// } +// +// override fun onActivityCreated(savedInstanceState: Bundle?) { +// super.onActivityCreated(savedInstanceState) +// setHasOptionsMenu(true) +// viewModel = ViewModelProvider(requireActivity()).get(LibraryListViewModel::class.java) +// +// cameraView = requireView().findViewById(R.id.cameraPreview) +// cameraView.holder.addCallback(object : SurfaceHolder.Callback { +// override fun surfaceCreated(holder: SurfaceHolder) {} +// override fun surfaceDestroyed(holder: SurfaceHolder) {} +// +// override fun surfaceChanged( +// holder: SurfaceHolder, +// format: Int, +// width: Int, +// height: Int +// ) { +// showCameraPreview(width, height) +// } +// }) +// } +// +// override fun onStart() { +// super.onStart() +// +// if (ContextCompat.checkSelfPermission( +// requireContext(), +// Manifest.permission.CAMERA +// ) != PackageManager.PERMISSION_GRANTED +// ) { +// requestPermissions(arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA) +// } else { +// // start camera feed +// } +// } +// +// // we will use this to determine the amount of frames in a row that we detect a barcode. +// // this is done for accuracy reasons as using one frame was allowing the phone to misdetect +// // barcodes. +// var detectedInARow: Int = 0 +// var lastChange = 0L +// var lastReadBarcodeNo: String = "" +// +// var camera: CameraDevice? = null +// +// fun showCameraPreview(width: Int, height: Int) { +// val cameraView = requireView().findViewById(R.id.cameraPreview) +// +// try { +// val cameraBkgHandler = Handler() +// +// val cameraManager = +// requireActivity().getSystemService(Context.CAMERA_SERVICE) as CameraManager +// +// cameraManager.cameraIdList.find { +// val characteristics = cameraManager.getCameraCharacteristics(it) +// val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING) +// +// return@find cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_BACK +// }?.let { +// val cameraStateCallback = object : CameraDevice.StateCallback() { +// override fun onOpened(camera: CameraDevice) { +// this@BarcodeScanningScreen.camera = camera +// val barcodeDetector = BarcodeDetector.Builder(requireContext()) +// .setBarcodeFormats(Barcode.ALL_FORMATS) +// .build() +// +// if (barcodeDetector.isOperational == false) { +// Toast.makeText( +// requireContext(), +// "Google mobile services (GMS) unable. Barcode scanning unsupported.", +// Toast.LENGTH_SHORT +// ).show() +// stopScanning() +// } +// +// val imgReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1) +// imgReader.setOnImageAvailableListener({ reader -> +// val cameraImage = reader.acquireNextImage() +// val buffer = cameraImage.planes.first().buffer +// val bytes = ByteArray(buffer.capacity()) +// buffer.get(bytes) +// +// val bitmap = +// BitmapFactory.decodeByteArray(bytes, 0, bytes.count(), null) +// val frameToProcess = Frame.Builder().setBitmap(bitmap).build() +// val barcodeResults = barcodeDetector.detect(frameToProcess) +// if (barcodeResults.size() > 0) { +// // Scanned a barcode! +// val result = barcodeResults.valueAt(0) +// Log.d("zotero", "scanned ${result.rawValue}") +// if (result.rawValue == lastReadBarcodeNo) { +// detectedInARow++ +// } else { +// detectedInARow = 0 +// lastReadBarcodeNo = result.rawValue +// } +// +// if (detectedInARow == 3) { +// val barcodeNo = barcodeResults.valueAt(0).rawValue +// viewModel.scannedBarcodeNumber(barcodeNo) +// stopScanning() +// } +// } else { +// } +// try { +// cameraImage.close() +// } catch (e: IllegalStateException) { +// // camera already closed. +// } +// +// }, cameraBkgHandler) +// +// val captureStateCallback = object : CameraCaptureSession.StateCallback() { +// override fun onConfigured(session: CameraCaptureSession) { +// val builder = +// camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) +// +// builder.addTarget(cameraView.holder.surface) +// builder.addTarget(imgReader.surface) +// session.setRepeatingRequest(builder.build(), null, null) +// } +// +// override fun onConfigureFailed(session: CameraCaptureSession) { +// } +// } +// +// camera.createCaptureSession( +// listOf(cameraView.holder.surface, imgReader.surface), +// captureStateCallback, +// cameraBkgHandler +// ) +// } +// +// override fun onClosed(camera: CameraDevice) { +// } +// +// override fun onDisconnected(camera: CameraDevice) { +// } +// +// override fun onError(camera: CameraDevice, error: Int) { +// } +// } +// +// cameraManager.openCamera(it, cameraStateCallback, cameraBkgHandler) +// return +// } +// +// } catch (e: CameraAccessException) { +// } catch (e: SecurityException) { +// } +// } +// +// private fun stopScanning() { +// try { +// this.camera?.close() +// } catch (e: IllegalStateException) { +// // camera already closed. +// } +// findNavController().navigateUp() +// } +// +// override fun onStop() { +// super.onStop() +// try { +// this.camera?.close() +// } catch (e: IllegalStateException) { +// // camera already closed. +// } +// } +// +// override fun onRequestPermissionsResult( +// requestCode: Int, +// permissions: Array, +// grantResults: IntArray +// ) { +// super.onRequestPermissionsResult(requestCode, permissions, grantResults) +// +// if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED +// && requestCode == REQUEST_CAMERA +// ) { +// showCameraPreview(cameraView.measuredWidth, cameraView.measuredHeight) +// } else { +// Toast.makeText( +// requireContext(), +// "This functionality requires the camera. Please provide the camera permission.", +// Toast.LENGTH_SHORT +// ).show() +// findNavController().navigateUp() +// } +// } +//} \ No newline at end of file diff --git a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/LibraryListFragment.kt b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/LibraryListFragment.kt index 480579f2..cec7c739 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/LibraryListFragment.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/Fragments/LibraryListFragment.kt @@ -165,7 +165,7 @@ class LibraryListFragment : Fragment(), LibraryListInteractionListener, val fabISBNScanner = requireView().findViewById(R.id.fab_action_barcode_scanner) fabISBNScanner.setOnClickListener { - findNavController().navigate(R.id.action_libraryListFragment_to_barcodeScanningScreen) + viewModel.onBarcodeScanButtonPressed() } } diff --git a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivity.kt b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivity.kt index 365e9eb6..3c620996 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivity.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivity.kt @@ -1,6 +1,7 @@ package com.mickstarify.zooforzotero.LibraryActivity import android.app.ProgressDialog +import android.content.ActivityNotFoundException import android.content.Intent import android.content.res.Configuration import android.net.Uri @@ -17,6 +18,8 @@ import android.view.MotionEvent import android.view.inputmethod.InputMethodManager import android.widget.EditText import android.graphics.Rect +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels import androidx.core.content.getSystemService import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AlertDialog @@ -25,6 +28,7 @@ import androidx.appcompat.widget.SearchView import androidx.core.view.GravityCompat import androidx.core.view.iterator import androidx.drawerlayout.widget.DrawerLayout +import androidx.lifecycle.ViewModelProvider import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import com.google.android.material.navigation.NavigationView @@ -33,6 +37,7 @@ import com.mickstarify.zooforzotero.LibraryActivity.ItemView.ItemAttachmentEntry import com.mickstarify.zooforzotero.LibraryActivity.ItemView.ItemViewFragment import com.mickstarify.zooforzotero.LibraryActivity.Notes.NoteInteractionListener import com.mickstarify.zooforzotero.LibraryActivity.Notes.NoteView +import com.mickstarify.zooforzotero.LibraryActivity.ViewModels.LibraryListViewModel import com.mickstarify.zooforzotero.R import com.mickstarify.zooforzotero.SettingsActivity import com.mickstarify.zooforzotero.ZoteroAPI.Model.Note @@ -64,10 +69,14 @@ class LibraryActivity : AppCompatActivity(), // used to "uncheck" the last pressed menu item if we change via code. private var currentPressedMenuItem: MenuItem? = null + private lateinit var libraryListViewModel: LibraryListViewModel + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_library) + libraryListViewModel = ViewModelProvider(this).get(LibraryListViewModel::class.java) + navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment_container) as NavHostFragment navController = navHostFragment.navController @@ -86,23 +95,57 @@ class LibraryActivity : AppCompatActivity(), R.id.libraryLoadingScreen -> { libraryLoadingScreenShown() } - R.id.barcodeScanningScreen -> { - barcodeScanningScreenShown() - } else -> { throw(NotImplementedError("Error screen $destination not handled.")) } } + } + libraryListViewModel.getOnBarcodeScanButtonPressed().observe(this) { + if (!it) { + return@observe + } + handleBarcodeScanRequest() } } - private fun barcodeScanningScreenShown() { - supportActionBar?.title = "Barcode Scanner" - mDrawerToggle.isDrawerIndicatorEnabled = false - supportActionBar?.setDisplayHomeAsUpEnabled(true) + private val getBarcode = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val data: Intent? = result.data + val contents = data?.getStringExtra("SCAN_RESULT") + Log.i("zotero", "got barcode scan result $contents") + if(contents != null) { + libraryListViewModel.scannedBarcodeNumber(contents) + } + } + } + + private fun handleBarcodeScanRequest(){ + val intent = Intent("com.google.zxing.client.android.SCAN") + intent.setPackage("com.google.zxing.client.android") + intent.putExtra("SCAN_MODE", "PRODUCT_MODE") + intent.putExtra("SCAN_FORMATS", "EAN_13") + + try { + getBarcode.launch(intent) + } catch (e: ActivityNotFoundException){ + Log.e("zotero", "error launching barcode scanner. ${e.message}") + + val alertDialog = AlertDialog.Builder(this) + .setTitle("Barcode Scanner Not Found") + .setMessage("You need to install the ZXing barcode scanner to use this feature.") + .setPositiveButton("Install", {_, _ -> + val intent2 = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.zxing.client.android")) + startActivity(intent2) + }) + .setIcon(android.R.drawable.ic_dialog_alert) + .setNegativeButton("Cancel", {_, _ -> }) + alertDialog.show() + } } + + private fun libraryLoadingScreenShown() { supportActionBar?.title = "Loading" mDrawerToggle.isDrawerIndicatorEnabled = true @@ -527,14 +570,7 @@ class LibraryActivity : AppCompatActivity(), private var doubleBackToExitPressedOnce = false override fun onBackPressed() { - // our list view has a custom back handler - // if we are on the barcode screen we will just want to return to the previous screen - if (getCurrentScreen() == AvailableScreens.BARCODE_SCANNING_SCREEN) { - navController.navigateUp() - } else { - presenter.backButtonPressed() - } - + presenter.backButtonPressed() Handler().postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000) } @@ -542,6 +578,7 @@ class LibraryActivity : AppCompatActivity(), const val ACTION_FILTER = "com.mickstarify.zooforzotero.intent.action.LIBRARY_FILTER_INTENT" const val EXTRA_QUERY = "com.mickstarify.zooforzotero.intent.EXTRA_QUERY_TEXT" + private const val ACTIVITY_RESULT_REQUEST_BARCODE_SCANNER_CODE = 10 } override fun deleteNote(note: Note) { @@ -572,7 +609,6 @@ class LibraryActivity : AppCompatActivity(), return when (navController.currentDestination?.id) { R.id.libraryListFragment -> AvailableScreens.LIBRARY_LISTVIEW_SCREEN R.id.libraryLoadingScreen -> AvailableScreens.LIBRARY_LOADING_SCREEN - R.id.barcodeScanningScreen -> AvailableScreens.BARCODE_SCANNING_SCREEN else -> throw (Exception("Unknown current screen ${navController.currentDestination}")) } } @@ -602,6 +638,5 @@ class LibraryActivity : AppCompatActivity(), enum class AvailableScreens { LIBRARY_LOADING_SCREEN, - LIBRARY_LISTVIEW_SCREEN, - BARCODE_SCANNING_SCREEN + LIBRARY_LISTVIEW_SCREEN } \ No newline at end of file diff --git a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivityModel.kt b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivityModel.kt index 33acc21e..e1c88057 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivityModel.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryActivityModel.kt @@ -8,7 +8,6 @@ import android.net.Uri import android.os.Bundle import android.os.Handler import android.util.Log -import com.google.firebase.analytics.FirebaseAnalytics import com.google.gson.JsonObject import com.mickstarify.zooforzotero.PreferenceManager import com.mickstarify.zooforzotero.SyncSetup.AuthenticationStorage @@ -51,8 +50,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex var selectedItem: Item? = null var isDisplayingItems = false - private var firebaseAnalytics: FirebaseAnalytics - private lateinit var zoteroAPI: ZoteroAPI private var syncManager: SyncManager @@ -437,7 +434,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex } override fun modifyNote(note: Note) { - firebaseAnalytics.logEvent("modify_note", Bundle()) if (state.isUsingGroup()) { presenter.makeToastAlert("Sorry, this isn't supported in shared collections.") return @@ -457,9 +453,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex } override fun onError(e: Throwable) { - firebaseAnalytics.logEvent( - "modify_note_error", - Bundle().apply { putString("error_message", e.toString()) }) if (e is ItemLockedException) { presenter.createErrorAlert( "Error modifying note", @@ -483,7 +476,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex } override fun deleteNote(note: Note) { - firebaseAnalytics.logEvent("delete_note", Bundle()) if (state.isUsingGroup()) { presenter.makeToastAlert("Sorry, this isn't supported in shared collections.") return @@ -576,9 +568,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex "Error loading group data", "Message: ${e.message}", {}) - val bundle = Bundle() - bundle.putString("error_message", e.message) - firebaseAnalytics.logEvent("error_loading_group_data", bundle) } }) @@ -661,10 +650,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex removeFromRecentlyViewed(item) } catch (e: Exception) { Log.e("zotero", "validateMd5 got error $e") - val bundle = Bundle().apply { - putString("error_message", e.toString()) - } - firebaseAnalytics.logEvent("error_check_attachments", bundle) removeFromRecentlyViewed(item) } } @@ -682,10 +667,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex override fun onError(e: Throwable) { Log.e("zotero", "validateMd5 observer got error $e") - val bundle = Bundle().apply { - putString("error_message", e.message) - } - firebaseAnalytics.logEvent("error_check_attachments", bundle) } override fun onSuccess(itemsToUpload: MutableList>) { @@ -710,8 +691,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex if (fileSizeBytes == 0L) { Log.e("zotero", "avoiding uploading a garbage PDF") - FirebaseAnalytics.getInstance(context) - .logEvent("AVOIDED_UPLOAD_GARBAGE", Bundle()) attachmentStorageManager.deleteAttachment(attachment) removeFromRecentlyViewed(attachment) return @@ -729,7 +708,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex "No", { if (version < attachment.getVersion()) { - firebaseAnalytics.logEvent("upload_attachment_version_mismatch", Bundle()) presenter.createYesNoPrompt("Outdated Version", "This local copy is older than the version on Zotero's server, are you sure you upload (this will irreversibly overwrite the server's copy)", "I am sure", @@ -779,10 +757,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex attachmentStorageManager.getMtime(attachment), AttachmentInfo.WEBDAV ).subscribeOn(Schedulers.io()).subscribe() - firebaseAnalytics.logEvent( - "upload_attachment_successful_webdav", - Bundle() - ) } override fun onSubscribe(d: Disposable) { @@ -795,12 +769,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex e.toString(), {}) Log.e("zotero", "got exception: $e") - val bundle = - Bundle().apply { putString("error_message", e.toString()) } - firebaseAnalytics.logEvent( - "error_uploading_attachments_webdav", - bundle - ) presenter.stopUploadingAttachmentProgress() } }) @@ -854,9 +822,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex e.toString(), {}) Log.e("zotero", "got exception: $e") - val bundle = - Bundle().apply { putString("error_message", e.toString()) } - firebaseAnalytics.logEvent("error_uploading_attachments", bundle) } presenter.stopUploadingAttachmentProgress() } @@ -1067,8 +1032,6 @@ class LibraryActivityModel(private val presenter: Contract.Presenter, val contex attachmentStorageManager = hiltEntryPoint.getAttachmentStorageManager() preferences = hiltEntryPoint.getPreferences() - firebaseAnalytics = FirebaseAnalytics.getInstance(context) - val auth = AuthenticationStorage(context) // add the first library state. states.push(LibraryModelState()) diff --git a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryFilterMenuDialog.kt b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryFilterMenuDialog.kt index 63381b36..2fdaebf9 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryFilterMenuDialog.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/LibraryFilterMenuDialog.kt @@ -10,7 +10,6 @@ import android.view.View import android.widget.Button import android.widget.CheckBox import android.widget.ImageButton -import com.google.firebase.analytics.FirebaseAnalytics import com.mickstarify.zooforzotero.PreferenceManager import com.mickstarify.zooforzotero.R @@ -41,8 +40,6 @@ class LibraryFilterMenuDialog(val context: Context, val onFilterChange: (() -> ( putBoolean("only_notes", onlyNotes) putString("sort_method", selected_sorting_method) } - FirebaseAnalytics.getInstance(context).logEvent("set_filter", params) - onFilterChange() } @@ -51,7 +48,6 @@ class LibraryFilterMenuDialog(val context: Context, val onFilterChange: (() -> ( if (i == -1) { val params = Bundle() params.putString("method", method) - FirebaseAnalytics.getInstance(context).logEvent("error_sort_method_not_found", params) return "Error" } return context.resources.getTextArray(R.array.sort_options_entries)[i].toString() diff --git a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/ViewModels/LibraryListViewModel.kt b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/ViewModels/LibraryListViewModel.kt index 29283d7b..ecc5dc72 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/ViewModels/LibraryListViewModel.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/LibraryActivity/ViewModels/LibraryListViewModel.kt @@ -66,4 +66,12 @@ class LibraryListViewModel : ViewModel() { this.libraryFilterText.value = query } } + + private val _onBarcodeScanButtonPressed = MutableLiveData(false) + fun onBarcodeScanButtonPressed() { + Log.d("zotero", "barcode scan button pressed") + _onBarcodeScanButtonPressed.value = true + _onBarcodeScanButtonPressed.value = false + } + fun getOnBarcodeScanButtonPressed(): LiveData = _onBarcodeScanButtonPressed } \ No newline at end of file diff --git a/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/SyncSetupView.kt b/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/SyncSetupView.kt index e3b5cbd3..f355243d 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/SyncSetupView.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/SyncSetupView.kt @@ -9,7 +9,6 @@ import android.widget.EditText import android.widget.RadioGroup import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity -import com.google.firebase.analytics.FirebaseAnalytics import com.mickstarify.zooforzotero.R import com.mickstarify.zooforzotero.SyncSetup.ZoteroAPISetup.ZoteroAPISetup @@ -40,8 +39,6 @@ class SyncSetupView : AppCompatActivity(), SyncSetupContract.View { textBox.requestFocus() } - private lateinit var firebaseAnalytics: FirebaseAnalytics - override fun showHowToZoteroSyncDialog(onProceed: () -> Unit) { val dialog = AlertDialog.Builder(this) dialog.setTitle("How to access") @@ -104,7 +101,6 @@ class SyncSetupView : AppCompatActivity(), SyncSetupContract.View { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_sync_setup) - firebaseAnalytics = FirebaseAnalytics.getInstance(this) presenter = SyncSetupPresenter(this, this) } diff --git a/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/ZoteroAPISetup/ZoteroAPISetup.kt b/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/ZoteroAPISetup/ZoteroAPISetup.kt index 86fa0f4d..d7aaae19 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/ZoteroAPISetup/ZoteroAPISetup.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/SyncSetup/ZoteroAPISetup/ZoteroAPISetup.kt @@ -15,15 +15,12 @@ import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout -import com.google.firebase.analytics.FirebaseAnalytics import com.mickstarify.zooforzotero.LibraryActivity.LibraryActivity import com.mickstarify.zooforzotero.R import com.mickstarify.zooforzotero.SyncSetup.AuthenticationStorage class ZoteroAPISetup : AppCompatActivity(), Contract.View { - private lateinit var firebaseAnalytics: FirebaseAnalytics - override fun openLibraryView() { val intent = Intent(this, LibraryActivity::class.java) startActivity(intent) @@ -88,7 +85,6 @@ class ZoteroAPISetup : AppCompatActivity(), Contract.View { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_zotero_api_setup) - firebaseAnalytics = FirebaseAnalytics.getInstance(this) supportActionBar?.setDisplayHomeAsUpEnabled(true) presenter = ZoteroAPISetupPresenter(this, AuthenticationStorage(this)) diff --git a/app/src/main/java/com/mickstarify/zooforzotero/ZooForZoteroApplication.kt b/app/src/main/java/com/mickstarify/zooforzotero/ZooForZoteroApplication.kt index f53d929f..800ad072 100644 --- a/app/src/main/java/com/mickstarify/zooforzotero/ZooForZoteroApplication.kt +++ b/app/src/main/java/com/mickstarify/zooforzotero/ZooForZoteroApplication.kt @@ -1,27 +1,46 @@ package com.mickstarify.zooforzotero import android.app.Application -//import com.facebook.flipper.android.AndroidFlipperClient -//import com.facebook.flipper.android.utils.FlipperUtils -//import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin -//import com.facebook.flipper.plugins.inspector.DescriptorMapping -//import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin -//import com.facebook.soloader.SoLoader import dagger.hilt.android.HiltAndroidApp +import org.acra.config.dialog +import org.acra.config.mailSender +import org.acra.data.StringFormat +import org.acra.ktx.initAcra @HiltAndroidApp class ZooForZoteroApplication : Application() { override fun onCreate() { super.onCreate() -// SoLoader.init(this, false) -// -// if (BuildConfig.DEBUG && FlipperUtils.shouldEnableFlipper(this)) { -// val client = AndroidFlipperClient.getInstance(this) -// client.addPlugin(InspectorFlipperPlugin(this, DescriptorMapping.withDefaults())) -// client.addPlugin(DatabasesFlipperPlugin(this)); -// client.start() -// } + initAcra { + //core configuration: + buildConfigClass = BuildConfig::class.java + reportFormat = StringFormat.JSON + //each plugin you chose above can be configured in a block like this: + + dialog { + //required + text = "Zoo for Zotero crashed. Would you like to report it?" + //optional, enables the dialog title + title = "Crash Report" + //defaults to android.R.string.ok + positiveButtonText = "Send" + //defaults to android.R.string.cancel + negativeButtonText = "Cancel" + resTheme = R.style.Theme_ZooForZotero + } + + mailSender { + //required + mailTo = "mickstarify@gmail.com" + //defaults to true + reportAsFile = true + //defaults to ACRA-report.stacktrace + reportFileName = "Crash.txt" + //defaults to " Crash Report" + subject = "Zoo for Zotero crash report" + } + } } } diff --git a/app/src/main/res/layout/barcode_scanning_screen_fragment.xml b/app/src/main/res/layout/barcode_scanning_screen_fragment.xml deleted file mode 100644 index 0e03ecc3..00000000 --- a/app/src/main/res/layout/barcode_scanning_screen_fragment.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index e2efa10b..62718519 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -9,18 +9,7 @@ android:id="@+id/libraryListFragment" android:name="com.mickstarify.zooforzotero.LibraryActivity.Fragments.LibraryListFragment" android:label="library_list_fragment" - tools:layout="@layout/library_list_fragment"> - - - + tools:layout="@layout/library_list_fragment"/>