Browse Source

ExperienceRegistration got a makeover. Fixes scaled questions bug. Implements 'Retry/Cancel' logic when sending survey answers. Adds multiline open answers (yet limits them to database limit). Heavy refactoring once more.

Víctor Hernández 3 years ago
parent
commit
905ee8db9c
23 changed files with 885 additions and 630 deletions
  1. BIN
      .idea/caches/build_file_checksums.ser
  2. 1
    0
      app/build.gradle
  3. 0
    95
      app/src/main/java/uprrp/tania/SendActivateExperienceToServer.java
  4. 0
    71
      app/src/main/java/uprrp/tania/SendAnswersToServer.java
  5. 0
    118
      app/src/main/java/uprrp/tania/SendWithdrawalToServer.java
  6. 4
    4
      app/src/main/java/uprrp/tania/URLEventListener.java
  7. 64
    81
      app/src/main/java/uprrp/tania/activities/ExperienceRegistrationActivity.java
  8. 43
    66
      app/src/main/java/uprrp/tania/activities/MainActivity.java
  9. 152
    108
      app/src/main/java/uprrp/tania/fragments/AssessmentsFragment.java
  10. 12
    17
      app/src/main/java/uprrp/tania/fragments/ConsentFragment.java
  11. 111
    44
      app/src/main/java/uprrp/tania/fragments/WithdrawFragment.java
  12. 16
    0
      app/src/main/java/uprrp/tania/models/AnsweredAssessmentModel.java
  13. 16
    0
      app/src/main/java/uprrp/tania/models/AnsweredQuestionModel.java
  14. 2
    2
      app/src/main/java/uprrp/tania/models/QuestionModel.java
  15. 7
    0
      app/src/main/java/uprrp/tania/models/UserStatusModel.java
  16. 17
    9
      app/src/main/java/uprrp/tania/networking/FetchAssessment.java
  17. 21
    11
      app/src/main/java/uprrp/tania/networking/FetchUserStatus.java
  18. 163
    0
      app/src/main/java/uprrp/tania/networking/SendAnswers.java
  19. 126
    0
      app/src/main/java/uprrp/tania/networking/SendExperienceRegistration.java
  20. 116
    0
      app/src/main/java/uprrp/tania/networking/SendWithdrawal.java
  21. 1
    1
      app/src/main/res/layout/fragment_assessments.xml
  22. 12
    2
      app/src/main/res/values/strings.xml
  23. 1
    1
      build.gradle

BIN
.idea/caches/build_file_checksums.ser View File


+ 1
- 0
app/build.gradle View File

66
     implementation 'androidx.navigation:navigation-ui:2.2.1'
66
     implementation 'androidx.navigation:navigation-ui:2.2.1'
67
     implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
67
     implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
68
     implementation 'androidx.appcompat:appcompat:1.1.0'
68
     implementation 'androidx.appcompat:appcompat:1.1.0'
69
+    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
69
     testImplementation 'junit:junit:4.12'
70
     testImplementation 'junit:junit:4.12'
70
 
71
 
71
     implementation 'com.android.support:support-v4:28.0.0'
72
     implementation 'com.android.support:support-v4:28.0.0'

+ 0
- 95
app/src/main/java/uprrp/tania/SendActivateExperienceToServer.java View File

1
-package uprrp.tania;
2
-
3
-import android.os.AsyncTask;
4
-import android.util.Log;
5
-
6
-import java.io.BufferedReader;
7
-import java.io.InputStreamReader;
8
-import java.io.OutputStreamWriter;
9
-import java.io.UnsupportedEncodingException;
10
-import java.net.URL;
11
-import java.net.URLEncoder;
12
-
13
-import javax.net.ssl.HttpsURLConnection;
14
-
15
-public class SendActivateExperienceToServer extends AsyncTask<String, String, String> {
16
-
17
-    private final String TAG = "SendActivateExperience";
18
-    private final URLEventListener myCallBack;
19
-    private URLEventListener myCallback;
20
-
21
-    public SendActivateExperienceToServer(URLEventListener callback) {
22
-        this.myCallBack = callback;
23
-    }
24
-
25
-    @Override
26
-    protected String doInBackground(String... strings) {
27
-
28
-        String experienceRegistrationJSON = strings[0]; // array will only ever contain a single element
29
-        String jsonActivateExperience = "";
30
-
31
-        // Encode data
32
-        try {
33
-            jsonActivateExperience = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(experienceRegistrationJSON, "UTF-8");
34
-        } catch (UnsupportedEncodingException e) {
35
-            Log.e(TAG, "Couldn't encode the following JSON: " + experienceRegistrationJSON);
36
-            e.printStackTrace();
37
-            return null;
38
-        }
39
-
40
-        // Send data
41
-        try {
42
-
43
-            // Send POST data request
44
-            URL url = new URL("https://tania.uprrp.edu/inscripcionExperiencia.php"); // TODO: extract URL into @string/activateExperienceURL
45
-            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
46
-            conn.setDoOutput(true);
47
-            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
48
-            wr.write(jsonActivateExperience);
49
-            wr.flush();
50
-
51
-            // Get the server response
52
-            BufferedReader serverReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
53
-            StringBuilder serverResponse = new StringBuilder();
54
-
55
-            String line = "";
56
-            while(line != null) {
57
-                serverResponse.append(line);
58
-                line = serverReader.readLine();
59
-            }
60
-
61
-            String response = serverResponse.toString();
62
-            if(response.startsWith("Success")) {
63
-                return response;
64
-            } else {
65
-                return null;
66
-            }
67
-
68
-
69
-        } catch(Exception e) {
70
-            Log.e("Couldn't communicate with server while activating experience!", e.getMessage());
71
-        }
72
-
73
-        return null;
74
-
75
-    }
76
-
77
-    @Override
78
-    protected void onPostExecute(String response) {
79
-
80
-        if(this.myCallBack == null) {
81
-            this.myCallBack.onFailure(new Exception("Callback wasn't initialized first!"));
82
-            return;
83
-        }
84
-
85
-        if(response == null) {
86
-            this.myCallback.onFailure(new Exception("Error occurred during transaction!"));
87
-            return;
88
-        }
89
-
90
-        Log.d("ACTIVATE EXPERIENCE RESPONSE", "The server's response is: " + response);
91
-        this.myCallBack.onSuccess();
92
-
93
-    }
94
-
95
-}

+ 0
- 71
app/src/main/java/uprrp/tania/SendAnswersToServer.java View File

1
-/*************************************************************
2
- * By: Coralys Cubero Rivera
3
- * Date: 2019
4
- *************************************************************/
5
-
6
-package uprrp.tania;
7
-
8
-import android.os.AsyncTask;
9
-import android.util.Log;
10
-import java.io.BufferedReader;
11
-import java.io.InputStreamReader;
12
-import java.io.OutputStreamWriter;
13
-import java.io.UnsupportedEncodingException;
14
-import java.net.URL;
15
-import java.net.URLConnection;
16
-import java.net.URLEncoder;
17
-
18
-public class SendAnswersToServer extends AsyncTask <String, String, String> {
19
-    @Override
20
-    protected String doInBackground(String... strings) {
21
-        String jsonSurveyAnswers  = " ";
22
-        try {
23
-            jsonSurveyAnswers = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(strings[0], "UTF-8");
24
-        } catch (UnsupportedEncodingException e) {
25
-            e.printStackTrace();
26
-        }
27
-
28
-        String serverReply = "";
29
-        BufferedReader serverReader;
30
-
31
-        //Send data
32
-        try
33
-        {
34
-            //Defined URL  where to send data
35
-            URL url = new URL("https://tania.uprrp.edu/parseAnswers.php");
36
-
37
-            // Send POST data request
38
-            URLConnection conn = url.openConnection();
39
-            conn.setDoOutput(true);
40
-            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
41
-            wr.write(jsonSurveyAnswers);
42
-            wr.flush();
43
-
44
-            // Get the server response
45
-            serverReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
46
-            StringBuilder serverResponse = new StringBuilder();
47
-            String serverResponseLine;
48
-
49
-            // Read Server Response
50
-            while((serverResponseLine = serverReader.readLine()) != null)
51
-            {
52
-                // Append server response in string
53
-                serverResponse.append(serverResponseLine);
54
-            }
55
-
56
-            serverReply = serverResponse.toString();
57
-        }
58
-        catch(Exception ex) {
59
-            Log.e("ERROR SURVEYS ANSWERS", ex.getMessage());
60
-        }
61
-
62
-        return serverReply;
63
-    }
64
-
65
-    @Override
66
-    protected void onPostExecute(String s) {
67
-        Log.d("SURVEYS ANSWERS REPLY", s);
68
-
69
-    }
70
-
71
-}

+ 0
- 118
app/src/main/java/uprrp/tania/SendWithdrawalToServer.java View File

1
-/*************************************************************
2
- * By: Coralys Cubero Rivera
3
- * Date: 2019
4
- *************************************************************/
5
-
6
-package uprrp.tania;
7
-
8
-import android.content.Context;
9
-import android.content.Intent;
10
-import android.content.SharedPreferences;
11
-import android.os.AsyncTask;
12
-import android.util.Log;
13
-
14
-import java.io.BufferedReader;
15
-import java.io.BufferedWriter;
16
-import java.io.InputStream;
17
-import java.io.InputStreamReader;
18
-import java.io.OutputStreamWriter;
19
-import java.io.UnsupportedEncodingException;
20
-import java.io.Writer;
21
-import java.net.URL;
22
-import java.net.URLConnection;
23
-import java.net.URLEncoder;
24
-import java.nio.charset.StandardCharsets;
25
-
26
-import uprrp.tania.activities.GettingStartedActivity;
27
-
28
-public class SendWithdrawalToServer extends AsyncTask<String, String, String> {
29
-
30
-    private Context context;
31
-
32
-    public SendWithdrawalToServer(Context context){
33
-        this.context = context.getApplicationContext();
34
-    }
35
-    @Override
36
-    protected String doInBackground(String... strings) {
37
-        String jsonWithdraw  = "";
38
-
39
-        try {
40
-            jsonWithdraw = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(strings[0], "UTF-8");
41
-
42
-        }
43
-
44
-        catch (UnsupportedEncodingException e) {
45
-            e.printStackTrace();
46
-        }
47
-
48
-        String serverReply = "";
49
-        BufferedReader serverReader;
50
-
51
-        //Send the signature to TANIA's server
52
-        try
53
-        {
54
-            //Defined URL  where to send data
55
-            URL url = new URL("https://tania.uprrp.edu/withdrawal.php");
56
-
57
-            //Send POST data request
58
-            URLConnection conn = url.openConnection();
59
-            conn.setDoOutput(true);
60
-
61
-            Writer writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8));
62
-            writer.write(jsonWithdraw);
63
-            writer.close();
64
-
65
-            InputStream inputStream = conn.getInputStream();
66
-
67
-            if (inputStream == null) {
68
-                return null;
69
-            }
70
-
71
-            //Get the server response
72
-            serverReader = new BufferedReader(new InputStreamReader(inputStream));
73
-            StringBuilder serverResponse = new StringBuilder();
74
-            String serverResponseLine;
75
-
76
-            // Read Server Response
77
-            while((serverResponseLine = serverReader.readLine()) != null)
78
-            {
79
-                //Append server response in string
80
-                serverResponse.append(serverResponseLine);
81
-            }
82
-
83
-            serverReply = serverResponse.toString();
84
-        }
85
-        catch(Exception ex) {
86
-            Log.e("ERROR WITHDRAWAL", ex.getMessage());
87
-        }
88
-
89
-        return serverReply;
90
-    }
91
-
92
-    @Override
93
-    protected void onPostExecute(String s) {
94
-        Log.d("WITHDRAWAL SERVER REPLY", s);
95
-
96
-        String ss = s.substring(0,6);
97
-        String se = s.substring(0,7);
98
-        if (ss.equals("Succes")){
99
-
100
-            SharedPreferences prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE);
101
-            SharedPreferences.Editor editor = prefs.edit();
102
-            editor.putBoolean("needsToRegister", true);
103
-            editor.apply();
104
-
105
-            try {
106
-                Intent intent = new Intent(context, GettingStartedActivity.class);
107
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
108
-                context.startActivity(intent);
109
-            }
110
-            catch (Exception e){
111
-                Log.d("WITHDRAWAL TO GETTING STARTED", e.getMessage());
112
-            }
113
-
114
-
115
-        }
116
-
117
-    }
118
-}

+ 4
- 4
app/src/main/java/uprrp/tania/URLEventListener.java View File

4
 import uprrp.tania.models.UserStatusModel;
4
 import uprrp.tania.models.UserStatusModel;
5
 
5
 
6
 public class URLEventListener {
6
 public class URLEventListener {
7
-    public void onSuccess() {};
8
-    public void onSuccess(AssessmentModel assessment) {};
9
-    public void onSuccess(UserStatusModel userStatus) {};
10
-    public void onFailure(Exception e) {};
7
+    public void onSuccess() {}
8
+    public void onSuccess(AssessmentModel assessment) {}
9
+    public void onSuccess(UserStatusModel userStatus) {}
10
+    public void onFailure(Exception e) {}
11
 }
11
 }

+ 64
- 81
app/src/main/java/uprrp/tania/activities/ExperienceRegistrationActivity.java View File

5
 import android.content.Intent;
5
 import android.content.Intent;
6
 import android.net.Uri;
6
 import android.net.Uri;
7
 import android.os.Bundle;
7
 import android.os.Bundle;
8
-import android.os.Handler;
9
 import android.util.Log;
8
 import android.util.Log;
10
 import android.view.View;
9
 import android.view.View;
11
 import android.widget.Button;
10
 import android.widget.Button;
18
 import com.google.firebase.iid.FirebaseInstanceId;
17
 import com.google.firebase.iid.FirebaseInstanceId;
19
 import com.google.firebase.iid.InstanceIdResult;
18
 import com.google.firebase.iid.InstanceIdResult;
20
 
19
 
21
-import org.json.JSONException;
22
-import org.json.JSONObject;
23
-
24
 import uprrp.tania.R;
20
 import uprrp.tania.R;
25
-import uprrp.tania.SendActivateExperienceToServer;
21
+import uprrp.tania.networking.SendExperienceRegistration;
26
 import uprrp.tania.URLEventListener;
22
 import uprrp.tania.URLEventListener;
27
 
23
 
28
 public class ExperienceRegistrationActivity  extends AppCompatActivity {
24
 public class ExperienceRegistrationActivity  extends AppCompatActivity {
29
 
25
 
30
-    private final String TAG = "ExperienceRegistrationActivity";
31
-    private String device_token;
32
-    private String id_experience;
26
+    private static final String TAG = "ExperienceRegistrationActivity";
27
+    private String DEVICE_TOKEN;
28
+    private String EXPERIENCE_ID;
33
 
29
 
34
     @Override
30
     @Override
35
     protected void onCreate(@Nullable Bundle savedInstanceState) {
31
     protected void onCreate(@Nullable Bundle savedInstanceState) {
44
         experienceRegistrationButton.setTransformationMethod(null);
40
         experienceRegistrationButton.setTransformationMethod(null);
45
 
41
 
46
         // Request to Firebase...
42
         // Request to Firebase...
43
+        // TODO: Should we implement retry logic in onFailureListener?
47
         FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
44
         FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
48
             @Override
45
             @Override
49
             public void onSuccess(InstanceIdResult instanceIdResult) {
46
             public void onSuccess(InstanceIdResult instanceIdResult) {
50
 
47
 
51
             // Get device's token
48
             // Get device's token
52
-            device_token = instanceIdResult.getToken();
49
+            // IMPORTANT: must come first before calling
50
+            // another function that uses the token
51
+            DEVICE_TOKEN = instanceIdResult.getToken();
53
 
52
 
54
             // Set onClick listener on button
53
             // Set onClick listener on button
55
             experienceRegistrationButton.setOnClickListener(new View.OnClickListener() {
54
             experienceRegistrationButton.setOnClickListener(new View.OnClickListener() {
56
                 @Override
55
                 @Override
57
                 public void onClick(View v) {
56
                 public void onClick(View v) {
58
-
59
-                    // Initiate progress dialog
60
-                    // TODO: find substitute for this deprecated dialog box
61
-                    final ProgressDialog progressDialog = ProgressDialog.show(ExperienceRegistrationActivity.this,
62
-                            "Registering in Experience",
63
-                            "This shouldn't take long");
64
-
65
-                    if(!id_experience.equals("") && id_experience != null) {
66
-                        try {
67
-
68
-                            // Create JSON with details we'll send
69
-                            JSONObject experienceCodeJSON = new JSONObject();
70
-                            experienceCodeJSON.put("token", device_token);
71
-                            experienceCodeJSON.put("id_experiencia", id_experience);
72
-                            Log.d("EXPERIENCE CODE JSON", experienceCodeJSON.toString());
73
-
74
-                            // Send registration request to server
75
-                            SendActivateExperienceToServer experienceRegistrationTask = new SendActivateExperienceToServer(new URLEventListener() {
76
-                                @Override
77
-                                public void onSuccess() {
78
-                                    progressDialog.dismiss();
79
-                                    Context context = ExperienceRegistrationActivity.this;
80
-                                    Intent intent = new Intent(context, MainActivity.class);
81
-                                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
82
-                                    context.startActivity(intent);
83
-                                    Toast.makeText(getApplicationContext(), "You have been registered!", Toast.LENGTH_LONG).show();
84
-                                }
85
-
86
-                                @Override
87
-                                public void onFailure(Exception e) {
88
-                                    progressDialog.dismiss();
89
-                                    // TODO: restrict double registration (maybe in backend?)
90
-                                    Toast.makeText(ExperienceRegistrationActivity.this, "Oops! Something went wrong...", Toast.LENGTH_LONG).show();
91
-                                    Log.e(TAG, "Error occurred while sending registration request to server...");
92
-                                    e.printStackTrace();
93
-                                }
94
-                            });
95
-
96
-                            experienceRegistrationTask.execute(experienceCodeJSON.toString());
97
-
98
-                            // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
99
-                            /*
100
-                            Handler handler = new Handler();
101
-                            handler.postDelayed(new Runnable() {
102
-                                public void run() {
103
-                                    progressDialog.dismiss();
104
-                                    if(false) { // Imitate success
105
-                                        Context context = ExperienceRegistrationActivity.this;
106
-                                        Intent intent = new Intent(context, MainActivity.class);
107
-                                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
108
-                                        context.startActivity(intent);
109
-                                        Toast.makeText(getApplicationContext(), "You have been registered!", Toast.LENGTH_LONG).show();
110
-                                    } else { // Imitate failure
111
-                                        Toast.makeText(ExperienceRegistrationActivity.this, "Oops! Something went wrong...", Toast.LENGTH_LONG).show();
112
-                                    }
113
-                                }
114
-                            }, 5000);
115
-                            */
116
-                            // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
117
-
118
-                        } catch (JSONException e) {
119
-                            progressDialog.dismiss();
120
-                            Toast.makeText(ExperienceRegistrationActivity.this, "Oops! Something went wrong...", Toast.LENGTH_LONG).show();
121
-                            Log.e(TAG, "Error occurred while preparing JSON for server");
122
-                            e.printStackTrace();
123
-                        }
124
-                    } else {
125
-                        progressDialog.dismiss();
126
-                        Toast.makeText(ExperienceRegistrationActivity.this, "Invalid URL!", Toast.LENGTH_LONG).show();
127
-                        Log.d(TAG, "Invalid query parameter found (" + id_experience + ")");
128
-                    }
57
+                    sendRegistrationRequest();
129
                 }
58
                 }
130
             });
59
             });
60
+
131
             }
61
             }
132
         });
62
         });
133
 
63
 
136
         if(Intent.ACTION_VIEW.equals(intent.getAction())) {
66
         if(Intent.ACTION_VIEW.equals(intent.getAction())) {
137
             Uri uri = intent.getData();
67
             Uri uri = intent.getData();
138
             assert uri != null; // TODO: figure out if this causes crashes...
68
             assert uri != null; // TODO: figure out if this causes crashes...
139
-            id_experience = uri.getQueryParameter("id");
69
+            EXPERIENCE_ID = uri.getQueryParameter("id");
140
         }
70
         }
141
 
71
 
142
     }
72
     }
143
 
73
 
74
+    private void sendRegistrationRequest() {
75
+
76
+        // Initiate progress dialog
77
+        // TODO: find substitute for this deprecated dialog box
78
+        final ProgressDialog progressDialog = ProgressDialog.show(ExperienceRegistrationActivity.this,
79
+                "Registering in Experience",
80
+                "This shouldn't take long");
81
+
82
+        // Send registration request to server
83
+        SendExperienceRegistration experienceRegistrationTask = new SendExperienceRegistration(new URLEventListener() {
84
+            @Override
85
+            public void onSuccess() {
86
+                progressDialog.dismiss();
87
+                Context context = ExperienceRegistrationActivity.this;
88
+                Intent intent = new Intent(context, MainActivity.class);
89
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
90
+                context.startActivity(intent);
91
+                Toast.makeText(getApplicationContext(), "You have been registered!", Toast.LENGTH_LONG).show();
92
+            }
93
+
94
+            @Override
95
+            public void onFailure(Exception e) {
96
+                progressDialog.dismiss();
97
+                Toast.makeText(ExperienceRegistrationActivity.this, "Oops! Something went wrong...\nPlease try again", Toast.LENGTH_LONG).show();
98
+                Log.e(TAG, "Error occurred while sending registration request to server...");
99
+                e.printStackTrace();
100
+            }
101
+        });
102
+
103
+        experienceRegistrationTask.execute(this.DEVICE_TOKEN, this.EXPERIENCE_ID);
104
+
105
+        // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
106
+        /*
107
+        Handler handler = new Handler();
108
+        handler.postDelayed(new Runnable() {
109
+            public void run() {
110
+                progressDialog.dismiss();
111
+                if(false) { // Imitate success
112
+                    Context context = ExperienceRegistrationActivity.this;
113
+                    Intent intent = new Intent(context, MainActivity.class);
114
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
115
+                    context.startActivity(intent);
116
+                    Toast.makeText(getApplicationContext(), "You have been registered!", Toast.LENGTH_LONG).show();
117
+                } else { // Imitate failure
118
+                    Toast.makeText(ExperienceRegistrationActivity.this, "Oops! Something went wrong...", Toast.LENGTH_LONG).show();
119
+                }
120
+            }
121
+        }, 5000);
122
+        */
123
+        // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
124
+
125
+    }
126
+
144
 }
127
 }

+ 43
- 66
app/src/main/java/uprrp/tania/activities/MainActivity.java View File

1
-/*************************************************************
2
- * By: Coralys Cubero Rivera
3
- * Date: 2019
4
- *************************************************************/
5
-
6
 package uprrp.tania.activities;
1
 package uprrp.tania.activities;
7
 
2
 
8
 import android.content.Intent;
3
 import android.content.Intent;
32
 import uprrp.tania.fragments.ConsentFragment;
27
 import uprrp.tania.fragments.ConsentFragment;
33
 import uprrp.tania.fragments.WithdrawFragment;
28
 import uprrp.tania.fragments.WithdrawFragment;
34
 
29
 
35
-
36
 public class MainActivity extends PinCodeActivity {
30
 public class MainActivity extends PinCodeActivity {
37
 
31
 
38
-    String device_token;
32
+    private static final String TAG = "MainActivity";
33
+
39
     @Override
34
     @Override
40
-    protected void onCreate(Bundle savedInstanceState) {
35
+    protected void onCreate(final Bundle savedInstanceState) {
36
+
37
+        // Constructor stuff
41
         super.onCreate(savedInstanceState);
38
         super.onCreate(savedInstanceState);
42
         setContentView(R.layout.activity_main);
39
         setContentView(R.layout.activity_main);
43
 
40
 
44
-        // If the application was opened using the URL scheme
45
-        Intent intent = getIntent();
46
-        if (intent != null && intent.getData() != null) {
47
-            Uri uri = intent.getData();
48
-            String expToken = null;
49
-            if (uri != null) {
50
-                expToken = uri.getQueryParameter("expToken");
51
-            }
52
-            Log.d("URL SCHEME", "The experience token is " + expToken);
53
-            //SendActivateExperienceToServer activateExperience = new SendActivateExperienceToServer();
54
-            //activateExperience.execute(expToken);
55
-        }
56
-        /////////////////////////////////////////////////////////////////////////////
57
 
41
 
58
         // We need to know if the user has already registered, otherwise they need to do that first
42
         // We need to know if the user has already registered, otherwise they need to do that first
59
         SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
43
         SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
60
         boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
44
         boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
61
-
62
-        if (needsToRegister){
63
-           Intent needsRegisterIntent = new Intent(this, GettingStartedActivity.class);
45
+        if(needsToRegister) {
46
+            Intent needsRegisterIntent = new Intent(this, GettingStartedActivity.class);
64
             startActivity(needsRegisterIntent);
47
             startActivity(needsRegisterIntent);
65
-         }
66
-        /////////////////////////////////////////////////////////////////////////////
67
-
48
+        }
68
 
49
 
69
-        //////////////////// Let's get NOTIFICATIONS //////////////////////////
70
-        FirebaseInstanceId.getInstance().getInstanceId()
71
-                .addOnSuccessListener(MainActivity.this, new OnSuccessListener<InstanceIdResult>() {
72
-                    @Override
73
-                    public void onSuccess(InstanceIdResult instanceIdResult) {
74
-                        device_token = instanceIdResult.getToken();
75
-                    }
76
-                });
77
 
50
 
51
+        // Enable notifications
78
         CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
52
         CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
79
                 getApplicationContext(),
53
                 getApplicationContext(),
80
-                "us-east-1:574094cd-0784-4e26-bd14-4fa72ae63579", // Identity pool ID
54
+                getString(R.string.identityPoolID), // Identity pool ID
81
                 Regions.US_EAST_1 // Region
55
                 Regions.US_EAST_1 // Region
82
         );
56
         );
83
-
84
         SNSRegister snsRegister = new SNSRegister(credentialsProvider);
57
         SNSRegister snsRegister = new SNSRegister(credentialsProvider);
85
         snsRegister.execute();
58
         snsRegister.execute();
86
-        ////////////////////////////////////////////////////////////////
87
 
59
 
88
 
60
 
61
+        // Create toolbar
89
         Toolbar toolbar = findViewById(R.id.toolbar);
62
         Toolbar toolbar = findViewById(R.id.toolbar);
90
         setSupportActionBar(toolbar);
63
         setSupportActionBar(toolbar);
91
         ActionBar actionBar = getSupportActionBar();
64
         ActionBar actionBar = getSupportActionBar();
92
-        assert actionBar != null;
93
-        actionBar.setTitle("TANIA");
65
+        assert actionBar != null; // TODO: find out if this causes crashes
66
+        actionBar.setTitle(R.string.app_name);
94
         actionBar.setDisplayShowTitleEnabled(true);
67
         actionBar.setDisplayShowTitleEnabled(true);
95
 
68
 
69
+
70
+        // Set navigation buttons listener
96
         BottomNavigationView bottomNavigationMenu = findViewById(R.id.bottom_navigation_menu);
71
         BottomNavigationView bottomNavigationMenu = findViewById(R.id.bottom_navigation_menu);
97
-        bottomNavigationMenu.setOnNavigationItemSelectedListener(navListener);
72
+        bottomNavigationMenu.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
73
+            @Override
74
+            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
75
+
76
+                Fragment selectedFragment;
77
+
78
+                switch (item.getItemId()) {
79
+                    case R.id.nav_assessments:
80
+                        selectedFragment = new AssessmentsFragment();
81
+                        break;
82
+                    case R.id.nav_consent:
83
+                        selectedFragment = new ConsentFragment();
84
+                        break;
85
+                    case R.id.nav_settings:
86
+                        selectedFragment = new WithdrawFragment();
87
+                        break;
88
+                    default:
89
+                        selectedFragment = new Fragment();
90
+                }
98
 
91
 
92
+                getSupportFragmentManager()
93
+                        .beginTransaction()
94
+                        .replace(R.id.mainFragment, selectedFragment)
95
+                        .commit();
99
 
96
 
100
-    }
97
+                return true;
101
 
98
 
102
-    private BottomNavigationView.OnNavigationItemSelectedListener navListener =
103
-            new BottomNavigationView.OnNavigationItemSelectedListener() {
104
-                @Override
105
-                public boolean onNavigationItemSelected(@NonNull MenuItem item) {
106
-                    Fragment selectedFragment = new Fragment();
107
-
108
-                    switch (item.getItemId()) {
109
-                        case R.id.nav_assessments:
110
-                            selectedFragment = new AssessmentsFragment();
111
-                            break;
112
-                        case R.id.nav_consent:
113
-                            selectedFragment = new ConsentFragment();
114
-                            break;
115
-                        case R.id.nav_settings:
116
-                            selectedFragment = new WithdrawFragment();
117
-                            break;
118
-                    }
119
-
120
-                    getSupportFragmentManager().beginTransaction().replace(R.id.mainFragment,
121
-                            selectedFragment).commit();
122
-
123
-                    return true;
124
-                }
125
-            };
99
+            }
100
+        });
101
+
102
+    }
126
 
103
 
127
 }
104
 }
128
 
105
 

+ 152
- 108
app/src/main/java/uprrp/tania/fragments/AssessmentsFragment.java View File

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.app.ProgressDialog;
4
 import android.app.ProgressDialog;
5
+import android.content.DialogInterface;
5
 import android.content.Intent;
6
 import android.content.Intent;
6
 import android.os.Bundle;
7
 import android.os.Bundle;
7
 import android.util.Log;
8
 import android.util.Log;
12
 import android.widget.TextView;
13
 import android.widget.TextView;
13
 import android.widget.Toast;
14
 import android.widget.Toast;
14
 import androidx.annotation.Nullable;
15
 import androidx.annotation.Nullable;
15
-import androidx.appcompat.widget.AppCompatButton;
16
+import androidx.appcompat.app.AlertDialog;
16
 import androidx.fragment.app.Fragment;
17
 import androidx.fragment.app.Fragment;
17
 
18
 
18
 import com.google.android.gms.tasks.OnSuccessListener;
19
 import com.google.android.gms.tasks.OnSuccessListener;
19
 import com.google.firebase.iid.FirebaseInstanceId;
20
 import com.google.firebase.iid.FirebaseInstanceId;
20
 import com.google.firebase.iid.InstanceIdResult;
21
 import com.google.firebase.iid.InstanceIdResult;
21
 
22
 
22
-import org.json.JSONException;
23
-import org.json.JSONObject;
24
 import org.researchstack.backbone.StorageAccess;
23
 import org.researchstack.backbone.StorageAccess;
25
 import org.researchstack.backbone.answerformat.AnswerFormat;
24
 import org.researchstack.backbone.answerformat.AnswerFormat;
26
 import org.researchstack.backbone.answerformat.ChoiceAnswerFormat;
25
 import org.researchstack.backbone.answerformat.ChoiceAnswerFormat;
36
 
35
 
37
 import java.util.ArrayList;
36
 import java.util.ArrayList;
38
 import java.util.List;
37
 import java.util.List;
38
+import java.util.Objects;
39
 
39
 
40
+import uprrp.tania.networking.SendAnswers;
41
+import uprrp.tania.models.AnsweredQuestionModel;
42
+import uprrp.tania.models.AnsweredAssessmentModel;
40
 import uprrp.tania.networking.FetchAssessment;
43
 import uprrp.tania.networking.FetchAssessment;
41
 import uprrp.tania.networking.FetchUserStatus;
44
 import uprrp.tania.networking.FetchUserStatus;
42
 import uprrp.tania.models.AssessmentModel;
45
 import uprrp.tania.models.AssessmentModel;
43
 import uprrp.tania.models.QuestionModel;
46
 import uprrp.tania.models.QuestionModel;
44
 import uprrp.tania.R;
47
 import uprrp.tania.R;
45
-import uprrp.tania.SendAnswersToServer;
46
 import uprrp.tania.URLEventListener;
48
 import uprrp.tania.URLEventListener;
47
 import uprrp.tania.models.UserStatusModel;
49
 import uprrp.tania.models.UserStatusModel;
48
 
50
 
54
     private static final String SAMPLE_SURVEY = "sample_assessment";
56
     private static final String SAMPLE_SURVEY = "sample_assessment";
55
 
57
 
56
     // Our variables
58
     // Our variables
57
-    private final String TAG = "ASSESSMENTS FRAGMENT";
58
-    private String device_token;
59
-    private String id_subquestionnair;
59
+    private static final String TAG = "AssessmentsFragment";
60
+    private String DEVICE_TOKEN;
61
+    private String ASSESSMENT_ID;
62
+    private View thisFragment;
60
 
63
 
61
     @Nullable
64
     @Nullable
62
     @Override
65
     @Override
63
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
66
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
64
 
67
 
65
         // Get reference for this fragment and other components
68
         // Get reference for this fragment and other components
66
-        final View thisFragment = inflater.inflate(R.layout.fragment_assessments, container, false);
67
-        final AppCompatButton surveyButton = thisFragment.findViewById(R.id.surveyButton);
68
-        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton); // TODO: check Button vs. AppCompatButton
69
+        this.thisFragment = inflater.inflate(R.layout.fragment_assessments, container, false);
70
+        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
71
+        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
69
 
72
 
70
         // Change all caps text to normal capitalization
73
         // Change all caps text to normal capitalization
71
         // TODO: this is a workaround I found, any other acceptable solution is welcome
74
         // TODO: this is a workaround I found, any other acceptable solution is welcome
73
         refreshButton.setTransformationMethod(null);
76
         refreshButton.setTransformationMethod(null);
74
 
77
 
75
         // Request to Firebase...
78
         // Request to Firebase...
79
+        // TODO: Should we implement retry logic in onFailureListener?
76
         FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
80
         FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
77
             @Override
81
             @Override
78
             public void onSuccess(InstanceIdResult instanceIdResult) {
82
             public void onSuccess(InstanceIdResult instanceIdResult) {
79
 
83
 
80
-            // Get device's token
81
-            // IMPORTANT: must come first before setting any
82
-            device_token = instanceIdResult.getToken();
84
+                // Get device's token
85
+                // IMPORTANT: must come first before calling
86
+                // another function that uses the token
87
+                DEVICE_TOKEN = instanceIdResult.getToken();
83
 
88
 
84
-            // Add onClick listener to "Answer Survey" button
85
-            surveyButton.setOnClickListener(new View.OnClickListener() {
86
-                @Override
87
-                public void onClick(View v) {
88
-                    fetchAssessment();
89
-                }
90
-            });
89
+                // Add onClick listener to "Answer Survey" button
90
+                surveyButton.setOnClickListener(new View.OnClickListener() {
91
+                    @Override
92
+                    public void onClick(View v) {
93
+                        fetchAssessment();
94
+                    }
95
+                });
91
 
96
 
92
-            // Add onClick listener to "Refresh Status" button
93
-            refreshButton.setOnClickListener(new View.OnClickListener() {
94
-                @Override
95
-                public void onClick(View v) {
96
-                    fetchUserStatus(thisFragment);
97
-                }
98
-            });
97
+                // Add onClick listener to "Refresh Status" button
98
+                refreshButton.setOnClickListener(new View.OnClickListener() {
99
+                    @Override
100
+                    public void onClick(View v) {
101
+                        fetchUserStatus();
102
+                    }
103
+                });
99
 
104
 
100
-            // Fetch user status and assessment, if any
101
-            fetchUserStatus(thisFragment);
105
+                // Fetch user status and assessment, if any
106
+                fetchUserStatus();
102
 //            fetchAssessment();
107
 //            fetchAssessment();
103
 
108
 
104
             }
109
             }
108
 
113
 
109
     }
114
     }
110
 
115
 
111
-    private void fetchUserStatus(View thisFragment) {
116
+    private void fetchUserStatus() {
112
 
117
 
113
         // Get text fields and initialize other stuff
118
         // Get text fields and initialize other stuff
114
-        final TextView statusTextView = thisFragment.findViewById(R.id.statusTextView);
115
-        final TextView nextSurveyTextView = thisFragment.findViewById(R.id.nextSurveyTextView);
116
-        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
117
-        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
119
+        final TextView statusTextView = this.thisFragment.findViewById(R.id.statusTextView);
120
+        final TextView nextSurveyTextView = this.thisFragment.findViewById(R.id.nextSurveyTextView);
121
+        final Button surveyButton = this.thisFragment.findViewById(R.id.surveyButton);
122
+        final Button refreshButton = this.thisFragment.findViewById(R.id.refreshButton);
118
 
123
 
119
         // Change UI to indicate loading is happening
124
         // Change UI to indicate loading is happening
120
-        statusTextView.setText(R.string.userStatusLoadingText);
125
+        statusTextView.setText(R.string.loadingText);
121
         nextSurveyTextView.setVisibility(View.GONE);
126
         nextSurveyTextView.setVisibility(View.GONE);
122
 
127
 
123
         // Define task
128
         // Define task
124
-        FetchUserStatus userStatusTask = (FetchUserStatus) new FetchUserStatus(new URLEventListener() {
129
+        FetchUserStatus userStatusTask = new FetchUserStatus(new URLEventListener() {
125
 
130
 
126
             @Override
131
             @Override
127
             public void onSuccess(UserStatusModel userStatus) {
132
             public void onSuccess(UserStatusModel userStatus) {
136
                     refreshButton.setVisibility(View.GONE);
141
                     refreshButton.setVisibility(View.GONE);
137
 
142
 
138
                     // Toggle "Answer" button visibility depending on survey availability
143
                     // Toggle "Answer" button visibility depending on survey availability
139
-                    // TODO: Decide whether to show the button regardless of anything,
140
-                    //  since this may be optional functionally, but important for UX
141
                     if(userStatus.surveyAvailable()) {
144
                     if(userStatus.surveyAvailable()) {
142
                         surveyButton.setVisibility(View.VISIBLE);
145
                         surveyButton.setVisibility(View.VISIBLE);
143
                     } else {
146
                     } else {
164
         });
167
         });
165
 
168
 
166
         // Start task
169
         // Start task
167
-        userStatusTask.execute(this.device_token);
170
+        userStatusTask.execute(this.DEVICE_TOKEN);
168
 
171
 
169
     }
172
     }
170
 
173
 
178
 
181
 
179
         // Fetch the assessment to be taken (if there is at least one available),
182
         // Fetch the assessment to be taken (if there is at least one available),
180
         // and launch the assessment (if the button is pressed)
183
         // and launch the assessment (if the button is pressed)
181
-        FetchAssessment assessmentTask = (FetchAssessment) new FetchAssessment(new URLEventListener() {
184
+        FetchAssessment assessmentTask = new FetchAssessment(new URLEventListener() {
182
 
185
 
183
             @Override
186
             @Override
184
             public void onSuccess(AssessmentModel assessment) {
187
             public void onSuccess(AssessmentModel assessment) {
185
-
186
-                // Stop progress dialog
187
                 progressDialog.dismiss();
188
                 progressDialog.dismiss();
188
-
189
-                // Launch survey or notify there are none available, accordingly
190
                 if(assessment.isEmpty()) {
189
                 if(assessment.isEmpty()) {
190
+                    fetchUserStatus(); // update status to let user know if it already had expired by the time he clicked
191
                     Toast.makeText(getContext(), "There are no surveys at the moment!", Toast.LENGTH_LONG).show();
191
                     Toast.makeText(getContext(), "There are no surveys at the moment!", Toast.LENGTH_LONG).show();
192
                 } else {
192
                 } else {
193
                     launchSurvey(assessment);
193
                     launchSurvey(assessment);
194
                 }
194
                 }
195
-
196
             }
195
             }
197
 
196
 
198
             @Override
197
             @Override
205
         });
204
         });
206
 
205
 
207
         // Start task
206
         // Start task
208
-        assessmentTask.execute(this.device_token);
207
+        assessmentTask.execute(this.DEVICE_TOKEN);
209
 
208
 
210
     }
209
     }
211
 
210
 
218
     }
217
     }
219
 
218
 
220
     private void launchSurvey(AssessmentModel assessment) {
219
     private void launchSurvey(AssessmentModel assessment) {
221
-        this.id_subquestionnair = assessment.getID();
222
-        List<Step> allSteps = this.prepareSurveySteps(assessment);
223
-        OrderedTask task = new OrderedTask(SAMPLE_SURVEY, allSteps);
220
+        this.ASSESSMENT_ID = assessment.getID();
221
+        List<Step> steps = this.prepareSurveySteps(assessment);
222
+        OrderedTask task = new OrderedTask(SAMPLE_SURVEY, steps);
224
         Intent intent = ViewTaskActivity.newIntent(getContext(), task);
223
         Intent intent = ViewTaskActivity.newIntent(getContext(), task);
225
         startActivityForResult(intent, REQUEST_SURVEY);
224
         startActivityForResult(intent, REQUEST_SURVEY);
226
     }
225
     }
227
 
226
 
228
     private void processSurveyResult(TaskResult result) {
227
     private void processSurveyResult(TaskResult result) {
228
+
229
+        // Save results to local database
229
         StorageAccess.getInstance().getAppDatabase().saveTaskResult(result);
230
         StorageAccess.getInstance().getAppDatabase().saveTaskResult(result);
230
 
231
 
232
+        // Load results
233
+        TaskResult taskResult = StorageAccess.getInstance()
234
+                .getAppDatabase()
235
+                .loadLatestTaskResult(SAMPLE_SURVEY);
236
+
237
+        // Prepare and send results
238
+        AnsweredAssessmentModel answeredAssessment = this.prepareAnsweredAssessment(taskResult);
239
+        this.sendSurveyInfo(answeredAssessment);
240
+
241
+    }
242
+
243
+    private void sendSurveyInfo(final AnsweredAssessmentModel answeredAssessment) {
244
+
231
         // Initiate progress dialog
245
         // Initiate progress dialog
232
         // TODO: find substitute for this deprecated dialog box
246
         // TODO: find substitute for this deprecated dialog box
233
         final ProgressDialog progressDialog = ProgressDialog.show(getContext(),
247
         final ProgressDialog progressDialog = ProgressDialog.show(getContext(),
234
                 "Sending Answers",
248
                 "Sending Answers",
235
                 "This shouldn't take long");
249
                 "This shouldn't take long");
236
 
250
 
237
-        try {
238
-            sendSurveyInfo();
239
-            progressDialog.dismiss();
240
-        } catch(Exception e) {
241
-            // TODO: prompt user to retry sending results
242
-            progressDialog.dismiss();
243
-            Toast.makeText(getContext(), "Couldn't send answers!", Toast.LENGTH_LONG).show();
244
-            Log.e("ERROR WHILE SENDING ANSWERS", e.toString());
245
-            e.printStackTrace();
246
-        }
247
-    }
248
-
249
-    private void sendSurveyInfo() {
250
-
251
-        // Load survey results
252
-        TaskResult taskResult = StorageAccess.getInstance()
253
-                .getAppDatabase()
254
-                .loadLatestTaskResult(SAMPLE_SURVEY);
251
+        // Send answers and prompt user if he wants to retry sending them if an error occurs
252
+        SendAnswers sendAnswersTask = new SendAnswers(new URLEventListener() {
255
 
253
 
256
-        // Serialize results into JSON
257
-        String resultsJSON = this.serializeSurveyResults(taskResult);
254
+           @Override public void onSuccess() {
255
+               progressDialog.dismiss();
256
+               Toast.makeText(getContext(), "Answers sent!", Toast.LENGTH_LONG).show();
257
+               fetchUserStatus();
258
+           }
258
 
259
 
259
-        // Send JSON
260
-        Log.d(TAG, "preparedJSON:" + resultsJSON);
261
-        new SendAnswersToServer().execute(resultsJSON);
260
+           @Override
261
+           public void onFailure(Exception e) {
262
+               Log.e("ERROR WHILE SENDING ANSWERS", e.toString());
263
+               e.printStackTrace();
264
+               progressDialog.dismiss();
265
+               promptRetrySend(answeredAssessment);
266
+           }
262
 
267
 
263
-    }
264
-
265
-    private String serializeSurveyResults(TaskResult taskResult) {
268
+        });
266
 
269
 
267
-        JSONObject surveyResults = new JSONObject();
268
 
270
 
269
-        try {
271
+        // Prepare results and start task
272
+       sendAnswersTask.execute(answeredAssessment);
273
+
274
+        // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
275
+//        Handler handler = new Handler();
276
+//        handler.postDelayed(new Runnable() {
277
+//            public void run() {
278
+//                progressDialog.dismiss();
279
+//                if(true) { // Imitate success
280
+//                    Toast.makeText(getContext(), "Answers sent!", Toast.LENGTH_LONG).show();
281
+//                    fetchUserStatus();
282
+//                } else { // Imitate failure
283
+//                    promptRetrySend2(answeredAssessment);
284
+//                }
285
+//            }
286
+//        }, 5000);
287
+        // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
270
 
288
 
271
-            surveyResults.put("os", "Android");
289
+    }
272
 
290
 
273
-            JSONObject data = new JSONObject();
274
-            data.put("id_subquestionnair", this.id_subquestionnair);
275
-            data.put("token", this.device_token);
291
+    private AnsweredAssessmentModel prepareAnsweredAssessment(TaskResult taskResult) {
276
 
292
 
277
-            // TODO: Try Gson.toJSON() to simplify this process
278
-            for (String id : taskResult.getResults().keySet()) {
279
-                JSONObject questions = new JSONObject();
280
-                StepResult stepResult = taskResult.getStepResult(id);
293
+        // Gather answered questions
294
+        ArrayList<AnsweredQuestionModel> answeredQuestions = new ArrayList<>();
295
+        for (String questionID : taskResult.getResults().keySet()) {
281
 
296
 
282
-                questions.accumulate("id_question", id);
283
-                questions.accumulate("start_datetime", taskResult.getStartDate().toString());
284
-                questions.accumulate("question_answer", stepResult.getResult().toString());
285
-                questions.accumulate("end_datetime", taskResult.getEndDate().toString());
286
-                data.accumulate("preguntas", questions.toString());
287
-            }
297
+            // Extract question info
298
+            // TODO: check if instead of getting the taskResult start/end times,
299
+            //  we should be getting the stepResult start/end times...
300
+            //  IF NOT: we should think about restructuring the JSON
301
+            //  because we're being highly redundant and inefficient
302
+            StepResult stepResult = taskResult.getStepResult(questionID);
303
+            String answer = stepResult.getResult().toString();
304
+            String startDatetime = taskResult.getStartDate().toString();
305
+            String endDatetime = taskResult.getEndDate().toString();
288
 
306
 
289
-            surveyResults.put("data", data.toString());
307
+            // Append question
308
+            AnsweredQuestionModel answeredQuestion = new AnsweredQuestionModel(questionID, answer, startDatetime, endDatetime);
309
+            answeredQuestions.add(answeredQuestion);
290
 
310
 
291
-        } catch (JSONException e) {
292
-            e.printStackTrace();
293
         }
311
         }
294
 
312
 
295
-        return surveyResults.toString();
313
+        // Return answered assessment
314
+        return new AnsweredAssessmentModel(this.ASSESSMENT_ID, this.DEVICE_TOKEN, answeredQuestions);
296
 
315
 
297
     }
316
     }
298
 
317
 
299
     private List<Step> prepareSurveySteps(AssessmentModel assessment) {
318
     private List<Step> prepareSurveySteps(AssessmentModel assessment) {
300
 
319
 
301
         // Initialize survey steps
320
         // Initialize survey steps
302
-//        List<QuestionStep> taniaQuestions = new ArrayList<>();
303
-        List<Step> allSteps = new ArrayList<>();
321
+        List<Step> steps = new ArrayList<>();
304
 
322
 
305
         // Create instruction screen (add it to total steps)
323
         // Create instruction screen (add it to total steps)
306
         InstructionStep instructionStep = new InstructionStep(INSTRUCTION,
324
         InstructionStep instructionStep = new InstructionStep(INSTRUCTION,
307
                 getString(R.string.app_name),
325
                 getString(R.string.app_name),
308
                 assessment.getDescription());
326
                 assessment.getDescription());
309
-        instructionStep.setStepTitle(R.string.survey);
310
-        allSteps.add(0, instructionStep);
327
+        instructionStep.setStepTitle(R.string.surveyToolbarText);
328
+        steps.add(0, instructionStep);
311
 
329
 
312
         // Prepare survey question by question
330
         // Prepare survey question by question
313
         List<QuestionModel> questions = assessment.getQuestions();
331
         List<QuestionModel> questions = assessment.getQuestions();
315
         for(int i = 0; i < assessment.getQuestionCount(); i++) {
333
         for(int i = 0; i < assessment.getQuestionCount(); i++) {
316
 
334
 
317
             QuestionModel question = questions.get(i);
335
             QuestionModel question = questions.get(i);
318
-            Log.d("id_type", question.getType());
336
+            Log.d(TAG, "QuestionType:" + question.getType());
319
 
337
 
320
             if(question.getType().equals("SCALED")) {
338
             if(question.getType().equals("SCALED")) {
321
 
339
 
336
                 AnswerFormat multiFormat = new ChoiceAnswerFormat(AnswerFormat.ChoiceAnswerStyle.SingleChoice, choices);
354
                 AnswerFormat multiFormat = new ChoiceAnswerFormat(AnswerFormat.ChoiceAnswerStyle.SingleChoice, choices);
337
 
355
 
338
                 // Set question step details
356
                 // Set question step details
339
-                newQuestionStep.setStepTitle(R.string.survey);
357
+                newQuestionStep.setStepTitle(R.string.surveyToolbarText);
340
                 newQuestionStep.setTitle(question.getPremise());
358
                 newQuestionStep.setTitle(question.getPremise());
341
                 newQuestionStep.setAnswerFormat(multiFormat);
359
                 newQuestionStep.setAnswerFormat(multiFormat);
342
                 newQuestionStep.setOptional(false);
360
                 newQuestionStep.setOptional(false);
343
 
361
 
344
                 // Add step to arrays
362
                 // Add step to arrays
345
-//                taniaQuestions.add(i, newQuestionStep);
346
-                allSteps.add(newQuestionStep);
363
+                steps.add(newQuestionStep);
347
 
364
 
348
             } else if(question.getType().equals("OPEN")) {
365
             } else if(question.getType().equals("OPEN")) {
349
 
366
 
350
                 // Create question step along with its choices
367
                 // Create question step along with its choices
351
                 QuestionStep newQuestionStep = new QuestionStep(question.getID());
368
                 QuestionStep newQuestionStep = new QuestionStep(question.getID());
352
-                TextAnswerFormat format = new TextAnswerFormat();
369
+                TextAnswerFormat format = new TextAnswerFormat(100);
370
+                format.setIsMultipleLines(true);
353
 
371
 
354
                 // Set question step details
372
                 // Set question step details
355
-                newQuestionStep.setStepTitle(R.string.survey);
373
+                newQuestionStep.setStepTitle(R.string.surveyToolbarText);
356
                 newQuestionStep.setTitle(question.getPremise());
374
                 newQuestionStep.setTitle(question.getPremise());
357
                 newQuestionStep.setAnswerFormat(format);
375
                 newQuestionStep.setAnswerFormat(format);
358
                 newQuestionStep.setOptional(false);
376
                 newQuestionStep.setOptional(false);
359
 
377
 
360
                 // Add step to arrays
378
                 // Add step to arrays
361
-//                taniaQuestions.add(i, newQuestionStep);
362
-                allSteps.add(newQuestionStep);
379
+                steps.add(newQuestionStep);
363
 
380
 
381
+            } else {
382
+                Log.wtf(TAG, "Neither OPEN nor SCALED if-statement has been reached");
364
             }
383
             }
384
+
365
         }
385
         }
366
 
386
 
367
-        return allSteps;
387
+        return steps;
388
+    }
389
+
390
+    private void promptRetrySend(final AnsweredAssessmentModel answeredAssessment) {
391
+        AlertDialog.Builder builder = new AlertDialog.Builder(Objects.requireNonNull(getContext()));
392
+        builder.setCancelable(true);
393
+        builder.setTitle("ERROR");
394
+        builder.setMessage("Couldn't send answer!");
395
+        builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
396
+            @Override
397
+            public void onClick(DialogInterface dialog, int which) {
398
+                Log.d(TAG, "Retrying answer send!");
399
+                sendSurveyInfo(answeredAssessment);
400
+            }
401
+        });
402
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
403
+            @Override
404
+            public void onClick(DialogInterface dialog, int which) {
405
+                Toast.makeText(getContext(), "Didn't send answers!", Toast.LENGTH_LONG).show();
406
+                fetchUserStatus();
407
+            }
408
+        });
409
+
410
+        AlertDialog dialog = builder.create();
411
+        dialog.show();
368
     }
412
     }
369
 
413
 
370
 }
414
 }

+ 12
- 17
app/src/main/java/uprrp/tania/fragments/ConsentFragment.java View File

1
-/*************************************************************
2
- * By: Coralys Cubero Rivera
3
- * Date: 2019
4
- *************************************************************/
5
-
6
 package uprrp.tania.fragments;
1
 package uprrp.tania.fragments;
7
 
2
 
8
 import android.graphics.Canvas;
3
 import android.graphics.Canvas;
30
 
25
 
31
 import uprrp.tania.R;
26
 import uprrp.tania.R;
32
 
27
 
33
-
34
 public class ConsentFragment extends Fragment {
28
 public class ConsentFragment extends Fragment {
35
 
29
 
36
-    PDFView pdfView;
30
+    private static final String TAG = "ConsentFragment";
31
+    private PDFView pdfView;
37
 
32
 
38
     @Nullable
33
     @Nullable
39
     @Override
34
     @Override
40
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
35
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
41
         View view = inflater.inflate(R.layout.fragment_consent, container, false);
36
         View view = inflater.inflate(R.layout.fragment_consent, container, false);
42
 
37
 
43
-        pdfView = view.findViewById(R.id.pdf_viewer);
44
-        File consentFile = new File(Environment.getExternalStorageDirectory().getPath() + "/consent-tania-app.pdf");
45
-        pdfView.fromFile(consentFile)
38
+        this.pdfView = view.findViewById(R.id.pdf_viewer);
39
+        File consentFile = new File(Environment.getExternalStorageDirectory().getPath() + getString(R.string.consentFileName));
40
+        this.pdfView.fromFile(consentFile)
46
                 .password(null)
41
                 .password(null)
47
                 .defaultPage(0)
42
                 .defaultPage(0)
48
                 .enableSwipe(true)
43
                 .enableSwipe(true)
77
                     public boolean onTap(MotionEvent e) {
72
                     public boolean onTap(MotionEvent e) {
78
                         return true;
73
                         return true;
79
                     }
74
                     }
80
-                }).onRender(new OnRenderListener() {
81
-            @Override
82
-            public void onInitiallyRendered(int nbPages, float pageWidth, float pageHeight) {
83
-                pdfView.fitToWidth();
84
-            }
85
-        })
75
+                })
76
+                .onRender(new OnRenderListener() {
77
+                    @Override
78
+                    public void onInitiallyRendered(int nbPages, float pageWidth, float pageHeight) {
79
+                        pdfView.fitToWidth();
80
+                    }
81
+                })
86
                 .enableAnnotationRendering(true)
82
                 .enableAnnotationRendering(true)
87
                 .invalidPageColor(Color.WHITE)
83
                 .invalidPageColor(Color.WHITE)
88
                 .load();
84
                 .load();
90
         return view;
86
         return view;
91
     }
87
     }
92
 
88
 
93
-
94
 }
89
 }

+ 111
- 44
app/src/main/java/uprrp/tania/fragments/WithdrawFragment.java View File

1
-/*************************************************************
2
- * By: Coralys Cubero Rivera
3
- * Date: 2019
4
- *************************************************************/
5
-
6
 package uprrp.tania.fragments;
1
 package uprrp.tania.fragments;
7
 
2
 
3
+import android.app.ProgressDialog;
4
+import android.content.Context;
8
 import android.content.DialogInterface;
5
 import android.content.DialogInterface;
6
+import android.content.Intent;
7
+import android.content.SharedPreferences;
9
 import android.os.Bundle;
8
 import android.os.Bundle;
9
+import android.util.Log;
10
 import android.view.LayoutInflater;
10
 import android.view.LayoutInflater;
11
 import android.view.View;
11
 import android.view.View;
12
 import android.view.ViewGroup;
12
 import android.view.ViewGroup;
13
 import android.widget.Button;
13
 import android.widget.Button;
14
+import android.widget.Toast;
14
 
15
 
15
 import androidx.annotation.NonNull;
16
 import androidx.annotation.NonNull;
16
 import androidx.annotation.Nullable;
17
 import androidx.annotation.Nullable;
21
 import com.google.firebase.iid.FirebaseInstanceId;
22
 import com.google.firebase.iid.FirebaseInstanceId;
22
 import com.google.firebase.iid.InstanceIdResult;
23
 import com.google.firebase.iid.InstanceIdResult;
23
 
24
 
24
-import org.json.JSONException;
25
-import org.json.JSONObject;
26
-
27
 import java.util.Objects;
25
 import java.util.Objects;
28
 
26
 
29
 import uprrp.tania.R;
27
 import uprrp.tania.R;
30
-import uprrp.tania.SendWithdrawalToServer;
28
+import uprrp.tania.URLEventListener;
29
+import uprrp.tania.activities.GettingStartedActivity;
30
+import uprrp.tania.networking.SendWithdrawal;
31
 
31
 
32
 public class WithdrawFragment extends Fragment {
32
 public class WithdrawFragment extends Fragment {
33
 
33
 
34
-    private String device_token;
34
+    private static final String TAG = "WithdrawFragment";
35
+    private String DEVICE_TOKEN;
35
 
36
 
36
     @Nullable
37
     @Nullable
37
     @Override
38
     @Override
38
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
39
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
40
+
41
+        // Get reference for this fragment and other components
39
         View view = inflater.inflate(R.layout.fragment_withdrawal, container, false);
42
         View view = inflater.inflate(R.layout.fragment_withdrawal, container, false);
43
+        final Button withdrawButton = view.findViewById(R.id.withdrawButton);
40
 
44
 
41
-        //Let's get the device's token
45
+        // Change all caps text to normal capitalization
46
+        // TODO: this is a workaround I found, any other acceptable solution is welcome
47
+        withdrawButton.setTransformationMethod(null);
48
+        withdrawButton.setText(R.string.loadingText);
49
+
50
+        // Get device's token and attach click listener once we have it
42
         FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
51
         FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
43
             @Override
52
             @Override
44
             public void onSuccess(InstanceIdResult instanceIdResult) {
53
             public void onSuccess(InstanceIdResult instanceIdResult) {
45
-                device_token = instanceIdResult.getToken();
54
+                DEVICE_TOKEN = instanceIdResult.getToken();
55
+                withdrawButton.setOnClickListener(new View.OnClickListener() {
56
+                    @Override
57
+                    public void onClick(View v) {
58
+                        promptConfirmation();
59
+                    }
60
+                });
61
+                withdrawButton.setText(R.string.withdrawButtonText);
46
             }
62
             }
47
         });
63
         });
48
 
64
 
49
-        Button withdrawButton = view.findViewById(R.id.withdrawButton);
50
-        withdrawButton.setTransformationMethod(null); // change all caps to normal
51
-        withdrawButton.setOnClickListener(new View.OnClickListener() {
65
+        return view;
66
+    }
67
+
68
+    private void promptConfirmation() {
69
+        AlertDialog.Builder builder = new AlertDialog.Builder(Objects.requireNonNull(getContext()));
70
+        builder.setCancelable(true);
71
+        builder.setTitle("WITHDRAWING");
72
+        builder.setMessage("Are you absolutely sure you want to withdraw from the project?");
73
+        builder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
52
             @Override
74
             @Override
53
-            public void onClick(View v) {
54
-                AlertDialog.Builder builder = new AlertDialog.Builder(Objects.requireNonNull(getContext()));
55
-                builder.setCancelable(true);
56
-                builder.setTitle("WITHDRAWING");
57
-                builder.setMessage("Are you absolutely sure you want to withdraw from the project?");
58
-                builder.setPositiveButton("Confirm",
59
-                        new DialogInterface.OnClickListener() {
60
-                            @Override
61
-                            public void onClick(DialogInterface dialog, int which) {
62
-                                try {
63
-                                    JSONObject withdrawToken = new JSONObject();
64
-                                    withdrawToken.put("token", device_token);
65
-                                    SendWithdrawalToServer sendWithdrawalToServer = new SendWithdrawalToServer(getContext());
66
-                                    sendWithdrawalToServer.execute(withdrawToken.toString());
67
-                                }
68
-                                catch (JSONException e){
69
-                                    e.getMessage();
70
-                                }
71
-
72
-                            }
73
-                        });
74
-                builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
75
-                    @Override
76
-                    public void onClick(DialogInterface dialog, int which) {
77
-                    }
78
-                });
75
+            public void onClick(DialogInterface dialog, int which) {
76
+                sendWithdrawalRequest();
77
+            }
78
+        });
79
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
80
+            @Override
81
+            public void onClick(DialogInterface dialog, int which) {
82
+                Log.d(TAG, "Cancelled withdrawal!");
83
+            }
84
+        });
85
+
86
+        AlertDialog dialog = builder.create();
87
+        dialog.show();
88
+    }
89
+
90
+    private void sendWithdrawalRequest() {
91
+
92
+        // Initiate progress dialog
93
+        // TODO: find substitute for this deprecated dialog box
94
+        final ProgressDialog progressDialog = ProgressDialog.show(getContext(),
95
+                "Withdrawing",
96
+                "This shouldn't take long");
97
+
98
+        // Send withdrawal request to server
99
+        SendWithdrawal sendWithdrawalTask = new SendWithdrawal(new URLEventListener() {
100
+            @Override
101
+            public void onSuccess() {
102
+
103
+                progressDialog.dismiss();
104
+                Context context = getContext();
105
+
106
+                // Change system preferences to begin in GettingStartedActivity by default
107
+                SharedPreferences prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE);
108
+                SharedPreferences.Editor editor = prefs.edit();
109
+                editor.putBoolean("needsToRegister", true);
110
+                editor.apply();
111
+
112
+                // Start GettingStartedActivity with a success message
113
+                Intent intent = new Intent(context, GettingStartedActivity.class);
114
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
115
+                context.startActivity(intent);
116
+                Toast.makeText(context.getApplicationContext(), "Successfully withdrawn!", Toast.LENGTH_LONG).show();
79
 
117
 
80
-                AlertDialog dialog = builder.create();
81
-                dialog.show();
118
+            }
119
+
120
+            @Override
121
+            public void onFailure(Exception e) {
122
+                progressDialog.dismiss();
123
+                Toast.makeText(getContext(), "Oops! Something went wrong...", Toast.LENGTH_LONG).show();
124
+                Log.e(TAG, "Error occurred while sending withdrawal request to server...");
125
+                e.printStackTrace();
82
             }
126
             }
83
         });
127
         });
84
 
128
 
85
-        return view;
129
+        // Start task
130
+        sendWithdrawalTask.execute(DEVICE_TOKEN);
131
+
132
+        // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
133
+        /*
134
+        Handler handler = new Handler();
135
+        handler.postDelayed(new Runnable() {
136
+            public void run() {
137
+                progressDialog.dismiss();
138
+                if(true) { // Imitate success
139
+                    Context context = getContext();
140
+                    Intent intent = new Intent(context, GettingStartedActivity.class);
141
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
142
+                    context.startActivity(intent);
143
+                    Toast.makeText(context.getApplicationContext(), "Successfully withdrawn!", Toast.LENGTH_LONG).show();
144
+                } else { // Imitate failure
145
+                    Toast.makeText(getContext(), "Oops! Something went wrong...", Toast.LENGTH_LONG).show();
146
+                }
147
+            }
148
+        }, 5000);
149
+        */
150
+        // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
151
+
86
     }
152
     }
153
+
87
 }
154
 }

+ 16
- 0
app/src/main/java/uprrp/tania/models/AnsweredAssessmentModel.java View File

1
+package uprrp.tania.models;
2
+
3
+import java.util.ArrayList;
4
+
5
+public class AnsweredAssessmentModel {
6
+    // NOTE these attribute must have the same names as the JSON fields we'll be sending to the server
7
+    private final String id_subquestionnair;
8
+    private final String token;
9
+    private final ArrayList<AnsweredQuestionModel> preguntas;
10
+
11
+    public AnsweredAssessmentModel(String id, String token, ArrayList<AnsweredQuestionModel> answeredQuestions) {
12
+        this.id_subquestionnair = id;
13
+        this.token = token;
14
+        this.preguntas = answeredQuestions;
15
+    }
16
+}

+ 16
- 0
app/src/main/java/uprrp/tania/models/AnsweredQuestionModel.java View File

1
+package uprrp.tania.models;
2
+
3
+public class AnsweredQuestionModel {
4
+    // NOTE these attribute must have the same names as the JSON fields we'll be sending to the server
5
+    private final String id_question;
6
+    private final String question_answer;
7
+    private final String start_datetime;
8
+    private final String end_datetime;
9
+
10
+    public AnsweredQuestionModel(String id, String answer, String startDatetime, String endDatetime) {
11
+        this.id_question = id;
12
+        this.question_answer = answer;
13
+        this.start_datetime = startDatetime;
14
+        this.end_datetime = endDatetime;
15
+    }
16
+}

+ 2
- 2
app/src/main/java/uprrp/tania/models/QuestionModel.java View File

10
     private String premise;
10
     private String premise;
11
     private String max_text;
11
     private String max_text;
12
     private String min_text;
12
     private String min_text;
13
-    private int max_value;
13
+    private int max_val;
14
 
14
 
15
     public String getID() {
15
     public String getID() {
16
         return this.id_question;
16
         return this.id_question;
40
     }
40
     }
41
 
41
 
42
     public int getMaxValue() {
42
     public int getMaxValue() {
43
-        return this.max_value;
43
+        return this.max_val;
44
     }
44
     }
45
 
45
 
46
     public int getMinValue() {
46
     public int getMinValue() {

+ 7
- 0
app/src/main/java/uprrp/tania/models/UserStatusModel.java View File

41
 
41
 
42
         // Format is DD:HH:MM (can be negative if survey can be answered)
42
         // Format is DD:HH:MM (can be negative if survey can be answered)
43
         String[] parts = this.time_to_next.split(":");
43
         String[] parts = this.time_to_next.split(":");
44
+
45
+        // Input validation
46
+        if(parts[0].equals("") || parts[1].equals("") || parts[2].equals("")) {
47
+            Log.wtf(TAG, "Backend gave an invalid time_to_next: " + this.time_to_next);
48
+            return ".."; // forms ellipsis
49
+        }
50
+
44
         int days = Integer.parseInt(parts[0]);
51
         int days = Integer.parseInt(parts[0]);
45
         int hours = Integer.parseInt(parts[1]);
52
         int hours = Integer.parseInt(parts[1]);
46
         int minutes = Integer.parseInt(parts[2]);
53
         int minutes = Integer.parseInt(parts[2]);

+ 17
- 9
app/src/main/java/uprrp/tania/networking/FetchAssessment.java View File

1
 package uprrp.tania.networking;
1
 package uprrp.tania.networking;
2
 
2
 
3
+import android.content.res.Resources;
3
 import android.os.AsyncTask;
4
 import android.os.AsyncTask;
4
 import android.util.Log;
5
 import android.util.Log;
5
 
6
 
18
 
19
 
19
 import javax.net.ssl.HttpsURLConnection;
20
 import javax.net.ssl.HttpsURLConnection;
20
 
21
 
22
+import uprrp.tania.R;
21
 import uprrp.tania.URLEventListener;
23
 import uprrp.tania.URLEventListener;
22
 import uprrp.tania.models.AssessmentModel;
24
 import uprrp.tania.models.AssessmentModel;
23
 import uprrp.tania.models.EmptyAssessmentModel;
25
 import uprrp.tania.models.EmptyAssessmentModel;
24
 
26
 
25
 public class FetchAssessment extends AsyncTask<String, Void, JSONObject> {
27
 public class FetchAssessment extends AsyncTask<String, Void, JSONObject> {
26
 
28
 
27
-    private final String TAG = "FETCH ASSESSMENT";
28
-    private final StringBuilder data =  new StringBuilder();
29
+    private static final String TAG = "FetchAssessment";
29
     private final URLEventListener myCallBack;
30
     private final URLEventListener myCallBack;
30
 
31
 
31
     public FetchAssessment(URLEventListener callback) {
32
     public FetchAssessment(URLEventListener callback) {
38
 
39
 
39
         try {
40
         try {
40
 
41
 
41
-            String getMomentsBaseURL = "https://tania.uprrp.edu/getSubQ2.php?tk="; // TODO: extract URL into @string/getMomentsBaseURL
42
+            String getMomentsBaseURL = Resources.getSystem().getString(R.string.assessmentsBaseURL);
42
             URL url = new URL(getMomentsBaseURL + deviceToken);
43
             URL url = new URL(getMomentsBaseURL + deviceToken);
43
             Log.d(TAG, "token:" + deviceToken); // log
44
             Log.d(TAG, "token:" + deviceToken); // log
44
             Log.d(TAG, "url:" + url.toString()); // log
45
             Log.d(TAG, "url:" + url.toString()); // log
45
             HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
46
             HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
46
             InputStream inputStream = httpsURLConnection.getInputStream();
47
             InputStream inputStream = httpsURLConnection.getInputStream();
47
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
48
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
49
+            StringBuilder serverResponse =  new StringBuilder();
48
 
50
 
49
             String line = "";
51
             String line = "";
50
             while (line != null) {
52
             while (line != null) {
51
-                data.append(line);
53
+                serverResponse.append(line);
52
                 line = bufferedReader.readLine();
54
                 line = bufferedReader.readLine();
53
             }
55
             }
54
 
56
 
55
-            Log.d(TAG, data.toString().substring(0, 10)); // log
56
-            if(data.toString().startsWith("Error:NoHa")) {
57
+            String response = serverResponse.toString();
58
+            Log.d(TAG, response.substring(0, 10)); // log
59
+            if(response.startsWith("Error:NoHa")) {
57
                 return new JSONObject("{}");
60
                 return new JSONObject("{}");
58
             } else {
61
             } else {
59
-                return new JSONObject(data.toString());
62
+                return new JSONObject(response);
60
             }
63
             }
61
 
64
 
62
         } catch (MalformedURLException e) {
65
         } catch (MalformedURLException e) {
66
+            Log.e(TAG, "Wrong URL used!");
63
             e.printStackTrace();
67
             e.printStackTrace();
68
+            return null;
64
         } catch (IOException e) {
69
         } catch (IOException e) {
70
+            Log.e(TAG, "IOStream error occurred!");
65
             e.printStackTrace();
71
             e.printStackTrace();
72
+            return null;
66
         } catch (JSONException e) {
73
         } catch (JSONException e) {
74
+            Log.e(TAG, "Couldn't construct return JSON!");
67
             e.printStackTrace();
75
             e.printStackTrace();
76
+            return null;
68
         }
77
         }
69
 
78
 
70
-        return null;
71
     }
79
     }
72
 
80
 
73
     @Override
81
     @Override
79
         }
87
         }
80
 
88
 
81
         if(obj == null) {
89
         if(obj == null) {
82
-            this.myCallBack.onFailure(new Exception("An error occurred during FetchAssesment!"));
90
+            this.myCallBack.onFailure(new Exception("An error occurred during FetchAssessment!"));
83
             return;
91
             return;
84
         }
92
         }
85
 
93
 

+ 21
- 11
app/src/main/java/uprrp/tania/networking/FetchUserStatus.java View File

1
 package uprrp.tania.networking;
1
 package uprrp.tania.networking;
2
 
2
 
3
+import android.content.res.Resources;
3
 import android.os.AsyncTask;
4
 import android.os.AsyncTask;
4
 import android.util.Log;
5
 import android.util.Log;
5
 
6
 
6
 import com.google.gson.GsonBuilder;
7
 import com.google.gson.GsonBuilder;
7
 import com.google.gson.JsonSyntaxException;
8
 import com.google.gson.JsonSyntaxException;
8
 
9
 
9
-import org.json.JSONException;
10
 import org.json.JSONArray;
10
 import org.json.JSONArray;
11
+import org.json.JSONException;
11
 import org.json.JSONObject;
12
 import org.json.JSONObject;
12
 
13
 
13
 import java.io.BufferedReader;
14
 import java.io.BufferedReader;
14
 import java.io.IOException;
15
 import java.io.IOException;
15
 import java.io.InputStream;
16
 import java.io.InputStream;
16
 import java.io.InputStreamReader;
17
 import java.io.InputStreamReader;
17
-import java.net.HttpURLConnection;
18
 import java.net.MalformedURLException;
18
 import java.net.MalformedURLException;
19
 import java.net.URL;
19
 import java.net.URL;
20
 
20
 
21
+import javax.net.ssl.HttpsURLConnection;
22
+
23
+import uprrp.tania.R;
21
 import uprrp.tania.URLEventListener;
24
 import uprrp.tania.URLEventListener;
22
 import uprrp.tania.models.EmptyUserStatusModel;
25
 import uprrp.tania.models.EmptyUserStatusModel;
23
 import uprrp.tania.models.UserStatusModel;
26
 import uprrp.tania.models.UserStatusModel;
24
 
27
 
25
 public class FetchUserStatus extends AsyncTask<String, Void, JSONArray> {
28
 public class FetchUserStatus extends AsyncTask<String, Void, JSONArray> {
26
 
29
 
27
-    private final String TAG = "FETCH USER STATUS";
28
-    private final StringBuilder data =  new StringBuilder();
30
+    private static final String TAG = "FetchUserStatus";
29
     private final URLEventListener myCallBack;
31
     private final URLEventListener myCallBack;
30
 
32
 
31
     public FetchUserStatus(URLEventListener callback) {
33
     public FetchUserStatus(URLEventListener callback) {
37
         String deviceToken = deviceTokenArray[0]; // array will only ever contain a single element
39
         String deviceToken = deviceTokenArray[0]; // array will only ever contain a single element
38
 
40
 
39
         try {
41
         try {
40
-            String userStatusBaseURL = "https://tania.uprrp.edu/status.php?tk=";  // TODO: extract URL into @string/userStatusBaseURL
42
+
43
+            String userStatusBaseURL = Resources.getSystem().getString(R.string.userStatusBaseURL);
41
             URL url = new URL(userStatusBaseURL + deviceToken);
44
             URL url = new URL(userStatusBaseURL + deviceToken);
42
             Log.d(TAG, "token:" + deviceToken); // log
45
             Log.d(TAG, "token:" + deviceToken); // log
43
             Log.d(TAG, "url:" + url.toString()); // log
46
             Log.d(TAG, "url:" + url.toString()); // log
44
-            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
47
+            HttpsURLConnection httpURLConnection = (HttpsURLConnection) url.openConnection();
45
             InputStream inputStream = httpURLConnection.getInputStream();
48
             InputStream inputStream = httpURLConnection.getInputStream();
46
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
49
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
50
+            StringBuilder serverResponse =  new StringBuilder();
47
 
51
 
48
             String line = "";
52
             String line = "";
49
             while(line != null) {
53
             while(line != null) {
50
-                data.append(line);
54
+                serverResponse.append(line);
51
                 line = bufferedReader.readLine();
55
                 line = bufferedReader.readLine();
52
             }
56
             }
53
 
57
 
54
-            Log.d(TAG, "rawString:" + data.toString()); // log
55
-            if(data.toString().equals("no esta inscrito")) {
58
+            String response = serverResponse.toString();
59
+            Log.d(TAG, "rawString:" + response); // log
60
+            if(response.equals("no esta inscrito")) {
56
                 return new JSONArray("[]");
61
                 return new JSONArray("[]");
57
             } else {
62
             } else {
58
-                return new JSONArray(data.toString());
63
+                return new JSONArray(response);
59
             }
64
             }
60
 
65
 
61
         } catch (MalformedURLException e) {
66
         } catch (MalformedURLException e) {
67
+            Log.e(TAG, "Wrong URL used!");
62
             e.printStackTrace();
68
             e.printStackTrace();
69
+            return null;
63
         } catch (IOException e) {
70
         } catch (IOException e) {
71
+            Log.e(TAG, "IOStream error occurred!");
64
             e.printStackTrace();
72
             e.printStackTrace();
73
+            return null;
65
         } catch (JSONException e) {
74
         } catch (JSONException e) {
75
+            Log.e(TAG, "Couldn't construct return JSON!");
66
             e.printStackTrace();
76
             e.printStackTrace();
77
+            return null;
67
         }
78
         }
68
 
79
 
69
-        return null;
70
     }
80
     }
71
 
81
 
72
     @Override
82
     @Override

+ 163
- 0
app/src/main/java/uprrp/tania/networking/SendAnswers.java View File

1
+package uprrp.tania.networking;
2
+
3
+import android.content.res.Resources;
4
+import android.os.AsyncTask;
5
+import android.util.Log;
6
+
7
+import com.google.gson.GsonBuilder;
8
+import com.google.gson.JsonSyntaxException;
9
+
10
+import org.json.JSONException;
11
+import org.json.JSONObject;
12
+
13
+import java.io.BufferedReader;
14
+import java.io.InputStreamReader;
15
+import java.io.OutputStreamWriter;
16
+import java.io.UnsupportedEncodingException;
17
+import java.net.URL;
18
+import java.net.URLEncoder;
19
+
20
+import javax.net.ssl.HttpsURLConnection;
21
+
22
+import uprrp.tania.R;
23
+import uprrp.tania.URLEventListener;
24
+import uprrp.tania.models.AnsweredAssessmentModel;
25
+
26
+public class SendAnswers extends AsyncTask<AnsweredAssessmentModel, Void, String> {
27
+
28
+    private static final String TAG = "SendAnswers";
29
+    private final URLEventListener myCallback;
30
+
31
+    public SendAnswers(URLEventListener callback) {
32
+        this.myCallback = callback;
33
+    }
34
+
35
+    // TODO: instead of making a normal POST request with
36
+    //  the body data=<uglyJSON>, we should just send the JSON itself
37
+    //  This is adding unnecessary layers of complexity when decoding AND encoding
38
+    /*
39
+        uglyJSON Format:
40
+        {
41
+            "os": "Android",
42
+            "data": String (containing escaped serializedAssessmentJSON)
43
+        }
44
+
45
+        serializedAssessmentJSON Format:
46
+        {
47
+            "id_subquestionnair": String,
48
+            "token": String,
49
+            "preguntas": [
50
+                {
51
+                    "id_question": String,
52
+                    "start_datetime": String,
53
+                    "question_answer": String,
54
+                    "end_datetime": String
55
+                },
56
+                ...
57
+            ]
58
+        }
59
+
60
+        WE SHOULD BE INSTEAD SENDING SOMETHING LIKE:
61
+        {
62
+            "os": "Android",
63
+            "token" String,
64
+            "data": {
65
+                "id_subquestionnair": String,
66
+                "preguntas": [
67
+                    {
68
+                        "id_question": String,
69
+                        "start_datetime": String,
70
+                        "question_answer": String,
71
+                        "end_datetime": String
72
+                    },
73
+                    ...
74
+                ]
75
+            }
76
+        }
77
+     */
78
+    @Override
79
+    protected String doInBackground(AnsweredAssessmentModel... answeredAssessments) {
80
+
81
+        AnsweredAssessmentModel answeredAssessment = answeredAssessments[0]; // array will only ever contain a single element
82
+
83
+        try {
84
+
85
+            // Serialize answered assessment
86
+            GsonBuilder builder = new GsonBuilder();
87
+//            builder.setPrettyPrinting(); // the server doesn't like pretty printing...
88
+            String serializedAssessment = builder.create().toJson(answeredAssessment);
89
+            Log.d(TAG,"reconstructedJSON:\n" + serializedAssessment); // log
90
+
91
+            // Create wrapper json (a.k.a. uglyJSON)
92
+            JSONObject surveyResults = new JSONObject();
93
+            surveyResults.put("os", "Android");
94
+            surveyResults.put("data", serializedAssessment);
95
+
96
+            // Encode data
97
+            String encodedRequestBody = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(surveyResults.toString(), "UTF-8");
98
+
99
+            // Send POST data request
100
+            URL url = new URL(Resources.getSystem().getString(R.string.sendAnswersURL));
101
+            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
102
+            conn.setDoOutput(true);
103
+            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
104
+            wr.write(encodedRequestBody);
105
+            wr.flush();
106
+
107
+            // Get the server response
108
+            BufferedReader serverReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
109
+            StringBuilder serverResponse = new StringBuilder();
110
+
111
+            String line = "";
112
+            while(line != null) {
113
+                serverResponse.append(line);
114
+                line = serverReader.readLine();
115
+            }
116
+
117
+            String response = serverResponse.toString();
118
+            Log.d(TAG, "The server's response is: " + response);
119
+            if(response.startsWith("Success")) {
120
+                return response;
121
+            } else {
122
+                return null;
123
+            }
124
+
125
+
126
+        } catch (JsonSyntaxException e) {
127
+            Log.e(TAG, "Failed to JSONify AnsweredAssessment!");
128
+            e.printStackTrace();
129
+            return null;
130
+        } catch (JSONException e) {
131
+            Log.e(TAG, "Failed to put AnsweredAssessment to surveyResults!");
132
+            e.printStackTrace();
133
+            return null;
134
+        } catch (UnsupportedEncodingException e) {
135
+            Log.e(TAG, "Couldn't encode surveyResultsJSON!");
136
+            e.printStackTrace();
137
+            return null;
138
+        } catch(Exception e) {
139
+            Log.e(TAG,"Couldn't communicate with server while sending answers!" + e.getMessage());
140
+            e.printStackTrace();
141
+            return null;
142
+        }
143
+
144
+    }
145
+
146
+    @Override
147
+    protected void onPostExecute(String response) {
148
+
149
+        if(this.myCallback == null) {
150
+            this.myCallback.onFailure(new Exception("Callback wasn't initialized first!"));
151
+            return;
152
+        }
153
+
154
+        if(response == null) {
155
+            this.myCallback.onFailure(new Exception("Error occurred during transaction!"));
156
+            return;
157
+        }
158
+
159
+        this.myCallback.onSuccess();
160
+
161
+    }
162
+
163
+}

+ 126
- 0
app/src/main/java/uprrp/tania/networking/SendExperienceRegistration.java View File

1
+package uprrp.tania.networking;
2
+
3
+import android.content.res.Resources;
4
+import android.os.AsyncTask;
5
+import android.util.Log;
6
+
7
+import org.json.JSONException;
8
+import org.json.JSONObject;
9
+
10
+import java.io.BufferedReader;
11
+import java.io.InputStreamReader;
12
+import java.io.OutputStreamWriter;
13
+import java.io.UnsupportedEncodingException;
14
+import java.net.URL;
15
+import java.net.URLEncoder;
16
+
17
+import javax.net.ssl.HttpsURLConnection;
18
+
19
+import uprrp.tania.R;
20
+import uprrp.tania.URLEventListener;
21
+
22
+public class SendExperienceRegistration extends AsyncTask<String, String, String> {
23
+
24
+    private static final String TAG = "SendActivateExperience";
25
+    private final URLEventListener myCallback;
26
+
27
+    public SendExperienceRegistration(URLEventListener callback) {
28
+        this.myCallback = callback;
29
+    }
30
+
31
+    // TODO: instead of making a normal POST request with
32
+    //  the body data=<JSON>, we should just send the JSON itself
33
+    //  This is adding unnecessary layers of complexity when decoding AND encoding
34
+    /*
35
+        JSON format:
36
+        {
37
+            "token": String,
38
+            "id_experiencia": String
39
+        }
40
+    */
41
+    @Override
42
+    protected String doInBackground(String... strings) {
43
+
44
+        String deviceToken = strings[0];
45
+        String experienceID = strings[1];
46
+
47
+        if(experienceID == null) {
48
+            Log.e(TAG, "Encountered null experience ID!");
49
+            return null;
50
+        } else if (deviceToken == null) {
51
+            Log.e(TAG, "Encountered null device token!");
52
+            return null;
53
+        }
54
+
55
+        try {
56
+
57
+            // Create JSON
58
+            JSONObject experienceRegistrationJSON = new JSONObject();
59
+            experienceRegistrationJSON.put("token", deviceToken);
60
+            experienceRegistrationJSON.put("id_experiencia", experienceID);
61
+            Log.d(TAG, "Prepared JSON: " + experienceRegistrationJSON.toString());
62
+
63
+            // Encode data
64
+            String encodedRequestBody = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(experienceRegistrationJSON.toString(), "UTF-8");
65
+
66
+            // Send POST data request
67
+            URL url = new URL(Resources.getSystem().getString(R.string.activateExperienceURL));
68
+            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
69
+            conn.setDoOutput(true);
70
+            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
71
+            wr.write(encodedRequestBody);
72
+            wr.flush();
73
+
74
+            // Get the server response
75
+            BufferedReader serverReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
76
+            StringBuilder serverResponse = new StringBuilder();
77
+
78
+            String line = "";
79
+            while(line != null) {
80
+                serverResponse.append(line);
81
+                line = serverReader.readLine();
82
+            }
83
+
84
+            // TODO: restrict double registration (maybe in backend?)
85
+            String response = serverResponse.toString();
86
+            Log.d(TAG, "The server's response is: " + response);
87
+            if(response.startsWith("Success")) {
88
+                return response;
89
+            } else {
90
+                return null;
91
+            }
92
+
93
+        } catch (JSONException e) {
94
+            Log.e(TAG, "Couldn't prepare experienceRegistrationJSON!");
95
+            e.printStackTrace();
96
+            return null;
97
+        } catch (UnsupportedEncodingException e) {
98
+            Log.e(TAG, "Couldn't encode experienceRegistrationJSON!");
99
+            e.printStackTrace();
100
+            return null;
101
+        } catch(Exception e) {
102
+            Log.e(TAG, "Couldn't communicate with server while activating experience!");
103
+            e.printStackTrace();
104
+            return null;
105
+        }
106
+
107
+    }
108
+
109
+    @Override
110
+    protected void onPostExecute(String response) {
111
+
112
+        if(this.myCallback == null) {
113
+            this.myCallback.onFailure(new Exception("Callback wasn't initialized first!"));
114
+            return;
115
+        }
116
+
117
+        if(response == null) {
118
+            this.myCallback.onFailure(new Exception("Error occurred during transaction!"));
119
+            return;
120
+        }
121
+
122
+        this.myCallback.onSuccess();
123
+
124
+    }
125
+
126
+}

+ 116
- 0
app/src/main/java/uprrp/tania/networking/SendWithdrawal.java View File

1
+package uprrp.tania.networking;
2
+
3
+import android.content.res.Resources;
4
+import android.os.AsyncTask;
5
+import android.util.Log;
6
+
7
+import org.json.JSONException;
8
+import org.json.JSONObject;
9
+
10
+import java.io.BufferedReader;
11
+import java.io.BufferedWriter;
12
+import java.io.InputStreamReader;
13
+import java.io.OutputStreamWriter;
14
+import java.io.UnsupportedEncodingException;
15
+import java.io.Writer;
16
+import java.net.URL;
17
+import java.net.URLEncoder;
18
+import java.nio.charset.StandardCharsets;
19
+
20
+import javax.net.ssl.HttpsURLConnection;
21
+
22
+import uprrp.tania.R;
23
+import uprrp.tania.URLEventListener;
24
+
25
+public class SendWithdrawal extends AsyncTask<String, String, String> {
26
+
27
+    private static final String TAG = "SendWithdrawal";
28
+    private final URLEventListener myCallback;
29
+
30
+    public SendWithdrawal(URLEventListener callback) {
31
+        this.myCallback = callback;
32
+    }
33
+
34
+    // TODO: instead of making a normal POST request with
35
+    //  the body data=<JSON>, we should just send the JSON itself
36
+    //  This is adding unnecessary layers of complexity when decoding AND encoding
37
+    /*
38
+        JSON format:
39
+        {
40
+            "token": String
41
+        }
42
+    */
43
+    @Override
44
+    protected String doInBackground(String... deviceTokenArray) {
45
+
46
+        String deviceToken = deviceTokenArray[0]; // array will only ever contain one element
47
+
48
+        try {
49
+
50
+            // Create JSON
51
+            JSONObject withdrawJSON = new JSONObject();
52
+            withdrawJSON.put("token", deviceToken);
53
+            Log.d(TAG, "Prepared JSON: " + withdrawJSON.toString());
54
+
55
+            // Encode data
56
+            String encodedRequestBody = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(withdrawJSON.toString(), "UTF-8");
57
+
58
+            // Send POST data request
59
+            URL url = new URL(Resources.getSystem().getString(R.string.withdrawalURL));
60
+            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
61
+            conn.setDoOutput(true);
62
+            Writer writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8));
63
+            writer.write(encodedRequestBody);
64
+            writer.close();
65
+
66
+            // Get the server response
67
+            BufferedReader serverReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
68
+            StringBuilder serverResponse = new StringBuilder();
69
+
70
+            String line = "";
71
+            while(line != null) {
72
+                serverResponse.append(line);
73
+                line = serverReader.readLine();
74
+            }
75
+
76
+            String response = serverResponse.toString();
77
+            Log.d(TAG, "The server's response is: " + response);
78
+            if(response.startsWith("Success")) {
79
+                return response;
80
+            } else {
81
+                return null;
82
+            }
83
+
84
+        } catch (JSONException e){
85
+            Log.e(TAG, "Couldn't construct withdrawJSON!");
86
+            e.printStackTrace();
87
+            return null;
88
+        } catch (UnsupportedEncodingException e) {
89
+            Log.e(TAG, "Couldn't encode withdrawJSON!");
90
+            e.printStackTrace();
91
+            return null;
92
+        } catch (Exception e) {
93
+            Log.e(TAG, "Couldn't communicate with server during withdrawal!");
94
+            e.printStackTrace();
95
+            return null;
96
+        }
97
+
98
+    }
99
+
100
+    @Override
101
+    protected void onPostExecute(String response) {
102
+
103
+        if(this.myCallback == null) {
104
+            this.myCallback.onFailure(new Exception("Callback wasn't initialized first!"));
105
+            return;
106
+        }
107
+
108
+        if(response == null) {
109
+            this.myCallback.onFailure(new Exception("Error occurred during transaction!"));
110
+            return;
111
+        }
112
+
113
+        this.myCallback.onSuccess();
114
+
115
+    }
116
+}

+ 1
- 1
app/src/main/res/layout/fragment_assessments.xml View File

59
         android:layout_marginStart="@dimen/horizontalMargin"
59
         android:layout_marginStart="@dimen/horizontalMargin"
60
         android:layout_marginTop="16dp"
60
         android:layout_marginTop="16dp"
61
         android:layout_marginEnd="@dimen/horizontalMargin"
61
         android:layout_marginEnd="@dimen/horizontalMargin"
62
-        android:text="@string/userStatusLoadingText"
62
+        android:text="@string/loadingText"
63
         android:textSize="@dimen/sectionDescriptionTextSize"
63
         android:textSize="@dimen/sectionDescriptionTextSize"
64
         app:layout_constraintEnd_toEndOf="parent"
64
         app:layout_constraintEnd_toEndOf="parent"
65
         app:layout_constraintStart_toStartOf="parent"
65
         app:layout_constraintStart_toStartOf="parent"

+ 12
- 2
app/src/main/res/values/strings.xml View File

1
 <resources>
1
 <resources>
2
     <string name="app_name">TANIA</string>
2
     <string name="app_name">TANIA</string>
3
-    <string name="survey">TANIA ASSESSMENT</string>
4
     <string name="menu_data_cleared">La información ha sido borrada</string>
3
     <string name="menu_data_cleared">La información ha sido borrada</string>
5
     <string name="user_name">Nombre de usuario:</string>
4
     <string name="user_name">Nombre de usuario:</string>
6
     <string name="date_consented">Fecha de consentimiento:</string>
5
     <string name="date_consented">Fecha de consentimiento:</string>
24
 
23
 
25
     <!-- !!!!! POST-Víctor !!!!! -->
24
     <!-- !!!!! POST-Víctor !!!!! -->
26
 
25
 
26
+    <!--  AmazonCognito Details  -->
27
+    <string name="identityPoolID">us-east-1:574094cd-0784-4e26-bd14-4fa72ae63579</string>
28
+    <!--  API Endpoints  -->
29
+    <string name="sendAnswersURL">https://tania.uprrp.edu/parseAnswers.php</string>
30
+    <string name="activateExperienceURL">https://tania.uprrp.edu/inscripcionExperiencia.php</string>
31
+    <string name="withdrawalURL">https://tania.uprrp.edu/withdrawal.php</string>
32
+    <string name="userStatusBaseURL">https://tania.uprrp.edu/status.php?tk=</string>
33
+    <string name="assessmentsBaseURL">https://tania.uprrp.edu/getSubQ2.php?tk=</string>
34
+    <!--  General App Configurations  -->
35
+    <string name="surveyToolbarText">Assessment</string>
27
     <!--  Assessment Fragment  -->
36
     <!--  Assessment Fragment  -->
28
     <string name="mainGreetingText">Hello! 👋</string>
37
     <string name="mainGreetingText">Hello! 👋</string>
29
-    <string name="userStatusLoadingText">Please wait a moment…</string>
38
+    <string name="loadingText">Please wait a moment…</string>
30
     <string name="userStatusErrorText">It seems we can\'t identify you… Please try again later.</string>
39
     <string name="userStatusErrorText">It seems we can\'t identify you… Please try again later.</string>
31
     <string name="refreshButtonText">Refresh Status</string>
40
     <string name="refreshButtonText">Refresh Status</string>
32
     <string name="surveyButtonText">Answer Survey</string>
41
     <string name="surveyButtonText">Answer Survey</string>
38
     <string name="experienceRegistrationTitleText">Activate Experience</string>
47
     <string name="experienceRegistrationTitleText">Activate Experience</string>
39
     <string name="experienceRegistrationDescriptionText">Click the button below to enter the research experience you are participating in.</string>
48
     <string name="experienceRegistrationDescriptionText">Click the button below to enter the research experience you are participating in.</string>
40
     <string name="experienceRegistrationButtonText">Enter</string>
49
     <string name="experienceRegistrationButtonText">Enter</string>
50
+    <string name="consentFileName">/consent-tania-app.pdf</string>
41
 </resources>
51
 </resources>

+ 1
- 1
build.gradle View File

7
         jcenter()
7
         jcenter()
8
     }
8
     }
9
     dependencies {
9
     dependencies {
10
-        classpath 'com.android.tools.build:gradle:4.1.0'
10
+        classpath 'com.android.tools.build:gradle:4.1.1'
11
         classpath 'com.google.gms:google-services:4.3.3'
11
         classpath 'com.google.gms:google-services:4.3.3'
12
         
12
         
13
 
13