I want to stop wasting time creating invoices — part 3

Pancho AM
5 min readMar 18, 2024

--

Resuming from previous part, the steps break down:

  1. Take a picture.

With an out of the box app that just takes pictures and uploads them into a GCS bucket

I think I can use this:

https://github.com/googleapis/java-storage

  1. Process OCR

After uploading the picture to GCS, a Cloud Function can be triggered to get the text, this cloud function can have the code to get it done, I think I could get that done after going through the lab below:

https://codelabs.developers.google.com/codelabs/docai-ocr-python#0

  1. Display a clock or whatever to let the user know OCR’s in progress.
  2. Ask user to validate data with a simple ok or edit.
  3. Fill out consignment paper for insurance company
  4. Ask user to validate the issuer’s website and/or specific invoice part of their website
  5. Send the data to the website
  6. Display a clock or whatever to let the user know the invoice is in process
  7. Success/fail

Working on step 1:

https://github.com/googleapis/java-storage/blob/main/samples/snippets/src/main/java/com/example/storage/object/UploadObject.java

Now inside Android Studio I got this showing up:

From the top of my head I’d say google up the latest version and use that, but I don’t know if that’ll work for an APK

Googling…

Too old, limiting to last year…

As per project jdk not defined android studio I think I was right.

Checking latest JDK version.

https://www.java.com/releases/

Going for https://www.oracle.com/java/technologies/javase/21-0-2-relnotes.html

Checking if I have it installed.

https://www.javatpoint.com/how-to-check-jdk-version-in-linux

Already installed.

How do I run this code in an Android emulator?

Add new configuration, Android App I guess?

WTF

Asking Gemini

I have a code in java, set up in maven, now how do I run it in Android Studio with a cellphone emulator?

There’s a key difference between a standard Java application and an Android app:

  • Standard Java Application: Compiled directly into bytecode (.class files) that the Java Virtual Machine (JVM) can understand.
  • Android App: Compiled into bytecode then further processed into Dalvik bytecode ( DEX files) for the Android Runtime (ART) to execute on the device.

F#%$ it…

Navigation Drawer so that I can set up multiple choices in the app.

So for building configuration language gradle it’s a must, gotta say goodbye to maven then…

Not the latest, but I’ll have to go with high percentage

Now where do I code to upload an object into GCS?

Back to: https://cloud.google.com/storage/docs/reference/libraries#client-libraries-install-java

Sh#t… I think it wasn’t necessary to switch from maven after all, googling can you run maven as an apk? Seems it’s doable.

Anywho, so long for my ADHD and switching stuff at first sight impulsively, I already switched to gradle, f#%! it…

And since I installed android studio, I don’t need to install gradle again.

Added those in the build.gradle instead of using ctr+alt+shift+s

Got a plugin notification

Installing it, hope it doesn’t messes it up.

Rebuilding!

Shhh…t

Googling

15 files found with path ‘META-INF/INDEX.LIST’.

https://github.com/auth0/Auth0.Android/issues/598

->

https://stackoverflow.com/questions/44342455/more-than-one-file-was-found-with-os-independent-path-meta-inf-license/47509465#47509465

Inside build.gradle, inside android {}

added:

packagingOptions {
resources.excludes.add("META-INF/*")
}

Rebuilt:

Success!

How do I upload a camera picture to gcs?

https://github.com/pliablematter/simple-cloud-storage <- too old, 11 years old.

I think Android Studio Bot might help, I always have the bad feeling of using AI tools when coding, I feel like if I was helping we all running out of jobs one of these days, hopefully’s just paranoid.

Restarting Android Studio.

In the article reference above mentions the steps below to find the Studio Bot:

Open the Studio Bot tool window by clicking View > Tool Windows > Studio Bot.

Couldn’t freaking find it…

Anyways, I kept Gemini’ing it up and this is what I’ve got so far:

FileUploader:

package com.example.facturasproject.ui.home;
import java.io.IOException;
public class FileUploader {
private final String projectId;
private final String bucketName;
// Constructor with dependency injection
public FileUploader(String projectId, String bucketName) {
this.projectId = projectId;
this.bucketName = bucketName;
}
public void uploadFile(String objectName, String filePath) throws IOException {
// … (Upload logic from UploadObject class)
}
}
HomeFragment:
package com.example.facturasproject.ui.home;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import com.example.facturasproject.databinding.FragmentHomeBinding;
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
Clock clock = Clock.systemDefaultZone();
Instant instant = clock.instant();
long nano = instant.getNano();
private final String objectName = String.valueOf(nano);
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// …
FragmentHomeBinding binding = FragmentHomeBinding.inflate(inflater, container, false);
View root = binding.getRoot();
// …
binding.textHome.setOnClickListener(v -> {
String filePath = "gs://myproject/incoming";
homeViewModel.uploadFile(filePath, objectName);
});
return root;
}
}

HomeViewModel:

package com.example.facturasproject.ui.home;
import androidx.lifecycle.ViewModel;
import java.io.IOException;
public class HomeViewModel extends ViewModel {
// …
public void uploadFile(String filePath, String objectName) {
// Instantiate FileUploader with dependencies
// (you can provide these through constructor or other means)
FileUploader fileUploader = new FileUploader("myProject", "myProjectBucket");
// Handle UI updates for progress, success/failure
// …
// Perform upload in a background thread
new Thread(() -> {
try {
fileUploader.uploadFile(objectName, filePath);
// Notify UI of success
} catch (IOException e) {
// Notify UI of error
}
}).start();
}
}

--

--

Pancho AM

Truth is a journey, not a destination. Love it, pursue it, and never give up on it.