nextcloud / android-library

☎️ Nextcloud Android library
Other
90 stars 91 forks source link

What is the exact version of android-library used in the latest nextcloud Android client? #1092

Closed TermoZour closed 1 year ago

TermoZour commented 1 year ago

I'm having a very hard time trying to follow the documentation examples, then the sample Android client in this repo, and also the Nextcloud client from it's own repo.

I can't find a way to read the data of a specific file after using ReadFolderRemoteOperation. I am getting a RemoteFile object but there is nothing inside it that I can use to get at least a remote path or something. Everything is set to private. This is looking at branch stable-2.14

So I started looking at the example Android client from this repo which seems to magically have all the data from RemoteFile. Yet when I am using the exact library from the example in my app, I can not.

I noticed there are A LOT of differences when comparing android-library with the source code of the Nextcloud client (latest version). For example, if I look at /nextcloud-android/app/src/main/java/com/nextcloud/client/account/User.kt from the Nextcloud client repo, I can see a lot of code compared to /android-library/library/src/main/java/com/nextcloud/common/User.kt.

Which is which? Depending on which version of the android-library I get different locations for this User.kt file, but I can't seem to find the exact version of library that is used in the Nextcloud client code, so I have a working up-to-date app that I can use as an example for the library, as the documentation is very lacking.

This is just an example with User.kt, but if I remember correctly, even after getting the latest version of the android-library, calling some functions would yield "not implemented", which are ofc working on the Nextcloud client.

Can someone enlighten me how all this stuff is organized? I am working on a custom Android client for a university project and I have a very hard time grasping all these differences in code with the 2 different clients and their libraries.

tobiasKaminsky commented 1 year ago

In Files library is specified here: https://github.com/nextcloud/android/blob/master/build.gradle#L11 So in this case it uses latest master branch/snapshot.

For our latest 3.24.1 release it is: https://github.com/nextcloud/android/blob/stable-3.24.1/build.gradle#L11

Regarding your ReadFolderRemoteOperation problem, can you give us an example?

A minimal example you can find here: https://github.com/nextcloud/android-library/blob/master/library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperationIT.kt

It uses credentials that are specified in AbstractIT, which can be set via ~/.gradle/gradle.properties: NC_TEST_SERVER_BASEURL=http://10.0.2.2/nc NC_TEST_SERVER_USERNAME=test NC_TEST_SERVER_PASSWORD=test

You can also join our chat: https://cloud.nextcloud.com/call/ex4id6qh

TermoZour commented 1 year ago

Here is the exact code I'm using, pieced together from different examples and looking at the library implementation itself.

val uri = nextcloudData.url
val username = nextcloudData.username
val password = nextcloudData.password

val mClient = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(uri), context, true)
mClient.credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password)
mClient.userId = username

val operation = ReadFolderRemoteOperation("/Photos")
val response = operation.execute(mClient)
Log.d("NextcloudGallery", "Got result: $response")
Log.d("NextcloudGallery", "Got data: ${response.data}")

First Log.d gives me the entire response object:

2023-03-21 10:02:33.778 22246-22310 NextcloudGallery        com.termozour.nextcloud.gallery      D  Got result: RemoteOperationResult{mSuccess=true, mHttpCode=207, mHttpPhrase='Multi-Status', mException=null, mCode=OK, message='null', getLogMessage='Operation finished with HTTP status code 207 (success)'}

And the second log gives me:

2023-03-21 10:02:33.778 22246-22310 NextcloudGallery        com.termozour.nextcloud.gallery      D  Got data: [com.owncloud.android.lib.resources.files.model.RemoteFile@ae207a, com.owncloud.android.lib.resources.files.model.RemoteFile@65302b, com.owncloud.android.lib.resources.files.model.RemoteFile@c04cc88, com.owncloud.android.lib.resources.files.model.RemoteFile@d8cb621, com.owncloud.android.lib.resources.files.model.RemoteFile@2edca46, com.owncloud.android.lib.resources.files.model.RemoteFile@b04a407, com.owncloud.android.lib.resources.files.model.RemoteFile@f5e2934, com.owncloud.android.lib.resources.files.model.RemoteFile@ddd935d, com.owncloud.android.lib.resources.files.model.RemoteFile@12c44d2, com.owncloud.android.lib.resources.files.model.RemoteFile@93d79a3]

So far so good. Now if I look at the example from android-library (the sample client) I see this example:

mFilesAdapter.clear();
        List<RemoteFile> files = new ArrayList<RemoteFile>();
        for(Object obj: result.getData()) {
            files.add((RemoteFile) obj);
        }
        if (files != null) {
            Iterator<RemoteFile> it = files.iterator();
            while (it.hasNext()) {
                mFilesAdapter.add(it.next());
            }
            mFilesAdapter.remove(mFilesAdapter.getItem(0));
        }
        mFilesAdapter.notifyDataSetChanged();

The adapter that shows me the files literally takes a list of RemoteObject. And in the FilesArrayAdapter.java there is this code which simply gets the path of each file found:

public View getView(int position, View convertView, ViewGroup parent) {
        TextView textView = (TextView)super.getView(position, convertView, parent);
        textView.setText(getItem(position).getRemotePath());
        return textView;
    }       

But that getRemotePath() function I can not find in the source code of the library repo itself, nor in my fork of stable-2.14. Yet somehow, by magic, it works!

tobiasKaminsky commented 1 year ago

But that getRemotePath() function I can not find in the source code of the library repo itself, nor in my fork of stable-2.14. Yet somehow, by magic, it works!

This is via https://github.com/nextcloud/android-library/blob/master/library/src/main/java/com/owncloud/android/lib/resources/files/model/RemoteFile.java#L44

It is an annotation processor, called Lombok, that generates getter and setter via annotation. We will replace this soon with Kotlin data classes.

TermoZour commented 1 year ago

I see. I just noticed the lines in the build.gradle of the library that mention Lombok. But that still begs the question, how is the structure of the library different from the one in the nextcloud client?

For example if we look at this directory from the android-library and this directory from the android client repo, I can see quite a lot of changes. Am I not comparing the right directories? Why am I seeing such huge differences between the android-library repo and the client that is supposed to implement the same exact code as it's found in this repo (and like the build.gradle suggests)

As I'm quite new to Android development as a whole, I am not entirely sure how to import the android-library repo to my project. If I follow the examples here, then I get a lot of "Not implemented" and deprecated warnings.

The approach I took was to get the stable-2.14 branch and copy-paste the repo in my android project while trying to fix all the gradle issues that Android Studio suggested. This meant I had a "technically up-to-date" version of the library which I could then use. But when I found the example code lacking, I turned towards the example android client, which did help in some aspects, but then I got to the issue where I can't actually get information of a RemoteFile object, so I can't populate any list (I'm using Compose). Then I turned to the official Nextcloud Android client hoping that "as that one is often updated, it surely must have working code examples", when I noticed that functions used in there (my getRemotePath() example) simply didn't exist in code, yet worked without issues.

My hunch is that I somehow need to enable Lombok in my project, similar to what is used in the example client, or mimic whatever structure is used in the official Nextcloud client repo...

TermoZour commented 1 year ago

Alright, so in the end I switched back the library being automatically added by gradle following the official documentation here.

I ended up getting the list of files working using this code:

// this is using v1 implementation, as the v2 implementation gives me "not implemented" error
val mClient = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(uri), context, true)
mClient.credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password)
mClient.userId = username

// using the default folder location from a barebones Nextcloud installation. This is what I have.
val operation = ReadFolderRemoteOperation("/Photos")
val response = operation.execute(mClient)

Log.d("NextcloudGallery", "Got data: ${response.getData()}")

// force the array to be of type RemoteFile. If I loop over response.data directly, I get unresolved reference error.
val files = arrayListOf<RemoteFile>()
for (file in response.data) {
    files.add(file as RemoteFile)
//    Log.d("NextcloudGallery","File: ${file.remotePath}") // this gives unresolved reference on remotePath
}

// print all files to logcat
Log.d("NextcloudGallery", "Files: $files")

// print second file (as the first is root and has no useful path info for me)
Log.d("NextcloudGallery", "file entry: ${files[1].remotePath}")

Even though I managed to solve the problem that started this Github issue, I would still like to know what/why is this difference between the library structure in this repo and the structure in the nextcloud android client repo.

tobiasKaminsky commented 1 year ago

First glad to hear that it works and congratulations! :tada:

I would still like to know what/why is this difference between the library structure in this repo and the structure in the nextcloud android client repo.

It is just different :) Think of it like library would not be developed by Nextcloud. We try to follow latest Android architecture on both, but we still have many legacy code, which will be transferred/refactored slowly.

TermoZour commented 1 year ago

Right. I see. Thanks for clarifying!