diff --git a/ShowPosts_VM.java b/ShowPosts_VM.java new file mode 100644 index 00000000..13550950 --- /dev/null +++ b/ShowPosts_VM.java @@ -0,0 +1,206 @@ +package unipd.se18.ocrcamera.forum.viewmodels; + +import android.arch.lifecycle.MutableLiveData; +import android.arch.lifecycle.ViewModel; +import android.content.Context; +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.firestore.QueryDocumentSnapshot; +import com.google.firebase.firestore.QuerySnapshot; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Map; + +import unipd.se18.ocrcamera.forum.DatabaseManager; +import unipd.se18.ocrcamera.forum.R; +import unipd.se18.ocrcamera.forum.RequestManager; +import unipd.se18.ocrcamera.forum.models.Post; + + +/** + * According to the MVVM (Model-View-ViewModel) architecture this class contains all fragment ShowPosts' logic. + * This architecture ensures that the code is more testable and organised than the classic approch to put everything + * in the activity or fragment class. + * In particular the methods that are implemented here are used to get posts from forum and to handle users' likes. The + * forum's data are stored into a database handle thanks to FirebaseFirestore API + * @author Leonardo Rossi g2 + */ +public class ShowPosts_VM extends ViewModel implements ShowPostsMethods +{ + + /** + * ******************** + * ** LISTENERS ** + * ******************** + */ + + /** + * This listener is triggered to update the UI with the result of a db interrogation to get posts inside the forum. + * If the result is successfull, that is all the posts are correctly downloaded, the ShowPost fragment recevives the + * posts list, otherwise it receives an error message that can be shown to the user + */ + public interface GetPostListener + { + /** + * Triggered when, after the db interrogation, all the posts are correctly parsed + * @param posts The posts list + */ + void onGetPostsSuccess(ArrayList posts); + + /** + * Triggered when after the db interrogation an error occurs while parsing the posts + * @param message The error message + */ + void onGetPostFailure(String message); + + } + + /** + * This listener is triggered to update the UI when a user put "like" to a specific post. This operation is + * successfull if the like is correctly store to the db, failed otherwise. + */ + public interface AddLikeListener + { + /** + * Triggered when after the db interrogation the like has successfully been added + * @param message A message to show to the user + */ + void onAddLikeSuccess(String message); + + /** + * Triggered when after the db interrogation an error occurred while adding a like + * @param message The error message to show to the user + */ + void onAddLikeFailure(String message); + } + + /** + * *************************** + * ** GLOBAL VARIABLES ** + * *************************** + */ + private GetPostListener getPostListener; + private AddLikeListener addLikeListener; + private final String LOG_TAG = "@@ShowPosts_VM"; + + @Override + public void getPosts(final Context context) + { + //Definition of the listener that will be triggered when the db interrogation is finished + final DatabaseManager.Listeners listeners = new DatabaseManager.Listeners(); + listeners.completeListener = new OnCompleteListener() + { + @Override + public void onComplete(@NonNull Task task) + { + //This array will contain the posts downloaded from the db + ArrayList posts = new ArrayList<>(); + + //Loopping through the db interrogation's result + for (QueryDocumentSnapshot item: task.getResult()) + { + //Each item inside the db interrogation's result is a map + //where the key identifies the db field to which is associated the corresponding value + Map postData = item.getData(); + + //Post attributes reading + String postID = item.getId(); + String postTitle = postData.get(context.getString(R.string.postTitleKey)).toString(); + String postMessage = postData.get(context.getString(R.string.postMessageKey)).toString(); + String postAuthor = postData.get(context.getString(R.string.postAuthorKey)).toString(); + int comments = Integer.valueOf(postData.get(context.getString(R.string.postCommentsKey)).toString()); + int likes = Integer.valueOf(postData.get(context.getString(R.string.postLikesKey)).toString()); + + //The date read from the db is converted into a specific format stored in the static variable + //DATE_FORMAT so that in this way it can be directly present in the UI + SimpleDateFormat format = new SimpleDateFormat(Post.DATE_FORMAT); + String postDate = postData.get(context.getString(R.string.postDateKey)).toString(); + + try + { + //At this point, if no exception are thrown, a post object can be built and stored into the + //specific array + posts.add(new Post(postID, postTitle, postMessage, format.parse(postDate), likes, comments, postAuthor)); + } + catch (ParseException e) + { + //If an error occurs while converting the post's date an error message is logged to console and + //the failure UI listener is triggered with a explanation message for the user + Log.d(LOG_TAG, e.getMessage()); + if (getPostListener != null){ getPostListener.onGetPostFailure(context.getString(R.string.requestFailedMessage)); } + } + } + + //If everithing goes well the success listener can be triggered with the posts list as parameter. + //In this way it can be used in the fragment to populate the UI + if (getPostListener != null){ getPostListener.onGetPostsSuccess(posts); } + } + }; + + //Calling to the method to get posts from the db passing the previously defined listener as parameter + DatabaseManager.getPosts(context, listeners); + } + + /** + * Adds a like to the specified post + * @param context The reference to the activity/fragment that has invoked this method + * @param post The ID of the post to which the like will be added + * @param user The user that has added the like + * @param prevLikes The number of likes before the last addition + */ + public void addLikeToPost(final Context context, String post, String user, int prevLikes) + { + //Definition of the listeners that will be triggered when the db interrogation is finished. + //In particular two listeners are defined: one for a successful db interrogation, the other in case of failure + DatabaseManager.Listeners listeners = new DatabaseManager.Listeners(); + + listeners.successListener = new OnSuccessListener() { + @Override + public void onSuccess(Object o) { + //If the like has correctly been added to the db the success listener is triggerd + //(In this case there's an empty string as parameter because there's no specific message to show to the user) + if (addLikeListener != null) { addLikeListener.onAddLikeSuccess(""); } + } + }; + + listeners.failureListener = new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) + { + //If an error occurrs while storing a like into the db an error message is logged to console and + //and the failure UI listener is trigger with an explanation message for the user + Log.d(LOG_TAG, "Error: " + e.getMessage()); + if (addLikeListener != null) { addLikeListener.onAddLikeFailure(context.getString(R.string.addLikeOnFailureMessage)); } + } + }; + + //Calling to the method to store a like into the db passing as parameter: + //The context which references to the fragment, the post ID, the user that has put "like" to the post, + //the amount of likes before the last one is added and the listeners previously defined + DatabaseManager.addLike(context, post, user, prevLikes, listeners); + } + + /** + * Adds the specified listener to the view model + * @param listener The specified listener that has to be added to the view model + */ + public void setGetPostsListener(GetPostListener listener) { this.getPostListener = listener; } + + /** + * Adds the specified listener to the view model + * @param listener The specified listener that has to be added to the view model + */ + public void setAddLikeListener(AddLikeListener listener) { this.addLikeListener = listener; } +} diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 8f29c0aa..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,50 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 28 - defaultConfig { - applicationId "unipd.se18.ocrcamera" - minSdkVersion 21 - targetSdkVersion 28 - versionCode 1 - versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - //Start - For android testing - testOptions { - unitTests.returnDefaultValues = true - } - //End - For android testing -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:28.0.0' - implementation 'com.android.support.constraint:constraint-layout:1.1.3' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - - //for json testing - testImplementation 'org.json:json:20140107' - - implementation 'com.google.firebase:firebase-core:16.0.4' - implementation 'com.google.firebase:firebase-ml-vision:18.0.1' - implementation 'com.android.support:design:28.0.0' - - implementation group: 'info.debatty', name: 'java-string-similarity', version: '1.1.0' - - //CameraKIt dependencies - implementation 'com.camerakit:camerakit:1.0.0-beta3.9' - implementation 'com.camerakit:jpegkit:0.1.0' - implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.61' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.24.0' -} -apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/app/src/androidTest/java/unipd/se18/ocrcamera/removeMe.md b/app/src/androidTest/java/unipd/se18/ocrcamera/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/androidTest/java/unipd/se18/ocrcamera/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/app/src/main/java/unipd/se18/ocrcamera/removeMe.md b/app/src/main/java/unipd/se18/ocrcamera/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/main/java/unipd/se18/ocrcamera/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/app/src/main/res/layout-land/removeMe.md b/app/src/main/res/layout-land/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/main/res/layout-land/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/app/src/main/res/layout/removeMe.md b/app/src/main/res/layout/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/main/res/layout/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/app/src/main/res/values/removeMe.md b/app/src/main/res/values/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/main/res/values/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/app/src/main/res/xml/removeMe.md b/app/src/main/res/xml/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/main/res/xml/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/app/src/test/java/unipd/se18/ocrcamera/removeMe.md b/app/src/test/java/unipd/se18/ocrcamera/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/test/java/unipd/se18/ocrcamera/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/app/src/test/resources/removeMe.md b/app/src/test/resources/removeMe.md deleted file mode 100644 index 6e2fe634..00000000 --- a/app/src/test/resources/removeMe.md +++ /dev/null @@ -1,2 +0,0 @@ -*Remove me, I'm not useful anymore.* -_- PrandiniUniPD, frankplus_ diff --git a/build.gradle b/build.gradle deleted file mode 100644 index fc759b10..00000000 --- a/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' - // 'com.google.gms:google-services:4.2.0' is available but the TextExtractor implements the 4.0.1 version - classpath 'com.google.gms:google-services:4.0.1' - - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 82618cec..00000000 --- a/gradle.properties +++ /dev/null @@ -1,15 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - - diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index f6b961fd..00000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 9a4163a4..00000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index e7b4def4..00000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app'