Browse Source

Added disabled button appearance. Fixed login bug (typo). Moved app-level stuff to App.java instead of MainActivity. Implemented some global observable variables. Added loading state to WithdrawFragment. Fixed Resources.getSystem().getString() bug. Fixed AsyncTasks callback bug. Refactored.

Víctor Hernández 3 years ago
parent
commit
785ef8ea88
25 changed files with 550 additions and 283 deletions
  1. 2
    2
      app/src/main/AndroidManifest.xml
  2. 90
    0
      app/src/main/java/uprrp/tania/App.java
  3. 64
    0
      app/src/main/java/uprrp/tania/GlobalValues.java
  4. 0
    36
      app/src/main/java/uprrp/tania/MarleApplication.java
  5. 0
    2
      app/src/main/java/uprrp/tania/MyFirebaseMessagingService.java
  6. 4
    2
      app/src/main/java/uprrp/tania/SendLoginToServer.java
  7. 75
    35
      app/src/main/java/uprrp/tania/activities/ExperienceRegistrationActivity.java
  8. 1
    41
      app/src/main/java/uprrp/tania/activities/MainActivity.java
  9. 168
    90
      app/src/main/java/uprrp/tania/fragments/AssessmentsFragment.java
  10. 71
    26
      app/src/main/java/uprrp/tania/fragments/WithdrawFragment.java
  11. 19
    3
      app/src/main/java/uprrp/tania/models/UserStatusModel.java
  12. 3
    5
      app/src/main/java/uprrp/tania/networking/FetchAssessment.java
  13. 2
    4
      app/src/main/java/uprrp/tania/networking/FetchUserStatus.java
  14. 3
    4
      app/src/main/java/uprrp/tania/networking/SendAnswers.java
  15. 3
    4
      app/src/main/java/uprrp/tania/networking/SendExperienceRegistration.java
  16. 3
    4
      app/src/main/java/uprrp/tania/networking/SendWithdrawal.java
  17. 1
    1
      app/src/main/java/uprrp/tania/unused/AppPrefs.java
  18. 1
    1
      app/src/main/java/uprrp/tania/unused/CognitoSettings.java
  19. 7
    4
      app/src/main/res/drawable/button_background.xml
  20. 12
    0
      app/src/main/res/drawable/button_disabled.xml
  21. 4
    3
      app/src/main/res/layout/activity_experience_registration.xml
  22. 4
    5
      app/src/main/res/layout/fragment_assessments.xml
  23. 3
    2
      app/src/main/res/layout/fragment_withdrawal.xml
  24. 1
    1
      app/src/main/res/values/colors.xml
  25. 9
    8
      app/src/main/res/values/strings.xml

+ 2
- 2
app/src/main/AndroidManifest.xml View File

@@ -7,7 +7,7 @@
7 7
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
8 8
 
9 9
     <application
10
-        android:name=".MarleApplication"
10
+        android:name=".App"
11 11
         android:allowBackup="true"
12 12
         android:icon="@mipmap/ic_launcher"
13 13
         android:label="TANIA"
@@ -45,7 +45,7 @@
45 45
             android:windowSoftInputMode="adjustResize" />
46 46
         <activity
47 47
             android:name="org.researchstack.backbone.ui.ViewWebDocumentActivity"
48
-            android:label="@string/app_name"
48
+            android:label="@string/appName"
49 49
             android:parentActivityName=".activities.MainActivity"
50 50
             android:theme="@style/Theme.MarleApp" />
51 51
         <activity

+ 90
- 0
app/src/main/java/uprrp/tania/App.java View File

@@ -0,0 +1,90 @@
1
+package uprrp.tania;
2
+
3
+import android.app.Application;
4
+import android.content.Intent;
5
+import android.content.SharedPreferences;
6
+import android.util.Log;
7
+import android.widget.Toast;
8
+
9
+import androidx.annotation.NonNull;
10
+
11
+import com.amazonaws.auth.CognitoCachingCredentialsProvider;
12
+import com.amazonaws.regions.Regions;
13
+import com.google.android.gms.tasks.OnFailureListener;
14
+import com.google.android.gms.tasks.OnSuccessListener;
15
+import com.google.firebase.iid.FirebaseInstanceId;
16
+import com.google.firebase.iid.InstanceIdResult;
17
+
18
+import org.researchstack.backbone.StorageAccess;
19
+import org.researchstack.backbone.storage.database.AppDatabase;
20
+import org.researchstack.backbone.storage.database.sqlite.DatabaseHelper;
21
+import org.researchstack.backbone.storage.file.EncryptionProvider;
22
+import org.researchstack.backbone.storage.file.FileAccess;
23
+import org.researchstack.backbone.storage.file.PinCodeConfig;
24
+import org.researchstack.backbone.storage.file.SimpleFileAccess;
25
+import org.researchstack.backbone.storage.file.UnencryptedProvider;
26
+
27
+import uprrp.tania.activities.GettingStartedActivity;
28
+
29
+public class App extends Application {
30
+
31
+    private static final String TAG = "App";
32
+
33
+    @Override
34
+    public void onCreate() {
35
+        super.onCreate();
36
+
37
+        // Customize your pin code preferences
38
+        PinCodeConfig pinCodeConfig = new PinCodeConfig(); // default pin config (4-digit, 1 min lockout)
39
+
40
+        // Customize encryption preferences
41
+        EncryptionProvider encryptionProvider = new UnencryptedProvider(); // No pin, no encryption
42
+
43
+        // If you have special file handling needs, implement FileAccess
44
+        FileAccess fileAccess = new SimpleFileAccess();
45
+
46
+        // If you have your own custom database, implement AppDatabase
47
+        AppDatabase database = new DatabaseHelper(this,
48
+                DatabaseHelper.DEFAULT_NAME,
49
+                null,
50
+                DatabaseHelper.DEFAULT_VERSION);
51
+
52
+        StorageAccess.getInstance().init(pinCodeConfig, encryptionProvider, fileAccess, database);
53
+
54
+        // We need to know if the user has already registered, otherwise they need to do that first
55
+        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
56
+        boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
57
+        if(needsToRegister) {
58
+            Intent needsRegisterIntent = new Intent(this, GettingStartedActivity.class);
59
+            startActivity(needsRegisterIntent);
60
+        }
61
+
62
+        // Enable notifications
63
+        CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
64
+                getApplicationContext(),
65
+                getString(R.string.identityPoolID), // Identity pool ID
66
+                Regions.US_EAST_1 // Region
67
+        );
68
+        SNSRegister snsRegister = new SNSRegister(credentialsProvider);
69
+        snsRegister.execute();
70
+
71
+        // Get device token (store globally
72
+        FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
73
+            @Override
74
+            public void onSuccess(InstanceIdResult instanceIdResult) {
75
+                String token = instanceIdResult.getToken();
76
+                GlobalValues.getInstance().setDeviceToken(token);
77
+                Log.d(TAG, "Got token: " + GlobalValues.getInstance().getDeviceToken());
78
+            }
79
+        }).addOnFailureListener(new OnFailureListener() {
80
+            @Override
81
+            public void onFailure(@NonNull Exception e) {
82
+                GlobalValues.getInstance().setDeviceToken(null);
83
+                Toast.makeText(getApplicationContext(), "Couldn't retrieve token!", Toast.LENGTH_LONG).show();
84
+                Log.e(TAG, "Error occurred while retrieving token...");
85
+                e.printStackTrace();
86
+            }
87
+        });
88
+
89
+    }
90
+}

+ 64
- 0
app/src/main/java/uprrp/tania/GlobalValues.java View File

@@ -0,0 +1,64 @@
1
+package uprrp.tania;
2
+
3
+import androidx.annotation.Nullable;
4
+
5
+import java.util.Observable;
6
+
7
+import uprrp.tania.models.UserStatusModel;
8
+
9
+// TAKEN FROM https://stackoverflow.com/questions/21886768/is-there-any-method-i-can-listen-for-changes-to-global-variable-to-trigger-an-ev
10
+public class GlobalValues extends Observable {
11
+
12
+    private static GlobalValues mInstance = null;
13
+
14
+    public static GlobalValues getInstance() {
15
+        if(mInstance == null) {
16
+            mInstance = new GlobalValues();
17
+        }
18
+        return mInstance;
19
+    }
20
+
21
+    // WHENEVER ADDING ANOTHER GLOBAL VARIABLE...
22
+    // 1. ADD ITS NAME IN ValueName
23
+    // 2. ADD A DECLARATION (AND INITIALIZATION; OPTIONAL)
24
+    // 3. ADD A GETTER AND A SETTER (TAKE A GOOD LOOK AT THE SETTER)
25
+    public enum ValueName {
26
+        DEVICE_TOKEN,
27
+        USER_STATUS,
28
+    }
29
+
30
+    public static class ValueKey {
31
+        private final ValueName mValueName;
32
+        public ValueKey(ValueName valueName) {
33
+            mValueName = valueName;
34
+        }
35
+        public ValueName getKey() {
36
+            return mValueName;
37
+        }
38
+    }
39
+
40
+    // DEVICE TOKEN
41
+    @Nullable
42
+    private String mDeviceToken;
43
+    public String getDeviceToken() {
44
+        return mDeviceToken;
45
+    }
46
+    public void setDeviceToken(@Nullable String value) {
47
+        mDeviceToken = value;
48
+        this.setChanged();
49
+        this.notifyObservers(new ValueKey(ValueName.DEVICE_TOKEN));
50
+    }
51
+
52
+    // USER STATUS
53
+    @Nullable
54
+    private UserStatusModel mUserStatus;
55
+    public UserStatusModel getUserStatus() {
56
+        return mUserStatus;
57
+    }
58
+    public void setUserStatus(UserStatusModel value) {
59
+        mUserStatus = value;
60
+        this.setChanged();
61
+        this.notifyObservers(new ValueKey(ValueName.USER_STATUS));
62
+    }
63
+
64
+}

+ 0
- 36
app/src/main/java/uprrp/tania/MarleApplication.java View File

@@ -1,36 +0,0 @@
1
-package uprrp.tania;
2
-
3
-import android.app.Application;
4
-
5
-import org.researchstack.backbone.StorageAccess;
6
-import org.researchstack.backbone.storage.database.AppDatabase;
7
-import org.researchstack.backbone.storage.database.sqlite.DatabaseHelper;
8
-import org.researchstack.backbone.storage.file.EncryptionProvider;
9
-import org.researchstack.backbone.storage.file.FileAccess;
10
-import org.researchstack.backbone.storage.file.PinCodeConfig;
11
-import org.researchstack.backbone.storage.file.SimpleFileAccess;
12
-import org.researchstack.backbone.storage.file.UnencryptedProvider;
13
-
14
-public class MarleApplication extends Application {
15
-    @Override
16
-    public void onCreate() {
17
-        super.onCreate();
18
-
19
-        // Customize your pin code preferences
20
-        PinCodeConfig pinCodeConfig = new PinCodeConfig(); // default pin config (4-digit, 1 min lockout)
21
-
22
-        // Customize encryption preferences
23
-        EncryptionProvider encryptionProvider = new UnencryptedProvider(); // No pin, no encryption
24
-
25
-        // If you have special file handling needs, implement FileAccess
26
-        FileAccess fileAccess = new SimpleFileAccess();
27
-
28
-        // If you have your own custom database, implement AppDatabase
29
-        AppDatabase database = new DatabaseHelper(this,
30
-                DatabaseHelper.DEFAULT_NAME,
31
-                null,
32
-                DatabaseHelper.DEFAULT_VERSION);
33
-
34
-        StorageAccess.getInstance().init(pinCodeConfig, encryptionProvider, fileAccess, database);
35
-    }
36
-}

+ 0
- 2
app/src/main/java/uprrp/tania/MyFirebaseMessagingService.java View File

@@ -1,7 +1,5 @@
1 1
 package uprrp.tania;
2 2
 
3
-
4
-
5 3
 import com.google.firebase.messaging.FirebaseMessagingService;
6 4
 import com.google.firebase.messaging.RemoteMessage;
7 5
 

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

@@ -8,6 +8,7 @@ package uprrp.tania;
8 8
 import android.content.Context;
9 9
 import android.content.Intent;
10 10
 import android.content.SharedPreferences;
11
+import android.content.res.Resources;
11 12
 import android.os.AsyncTask;
12 13
 import android.os.Environment;
13 14
 import android.util.Base64;
@@ -28,6 +29,7 @@ import uprrp.tania.activities.MainActivity;
28 29
 
29 30
 public class SendLoginToServer extends AsyncTask<String, String, String> {
30 31
 
32
+    private static final String loginBaseURL = "https://tania.uprrp.edu/recoverAccount.php";
31 33
     private Context context;
32 34
 
33 35
     public SendLoginToServer(Context context){
@@ -52,7 +54,7 @@ public class SendLoginToServer extends AsyncTask<String, String, String> {
52 54
         try
53 55
         {
54 56
             // Defined URL  where to send data
55
-            URL url = new URL("https://tania.uprrp.edu7/recoverAccount.php");
57
+            URL url = new URL(loginBaseURL);
56 58
 
57 59
             // Send POST data request
58 60
             URLConnection conn = url.openConnection();
@@ -83,7 +85,7 @@ public class SendLoginToServer extends AsyncTask<String, String, String> {
83 85
         {
84 86
             try
85 87
             {
86
-                assert reader != null;
88
+//                assert reader != null;
87 89
                 reader.close();
88 90
             }
89 91
             catch(Exception ex) {

+ 75
- 35
app/src/main/java/uprrp/tania/activities/ExperienceRegistrationActivity.java View File

@@ -8,58 +8,31 @@ import android.os.Bundle;
8 8
 import android.util.Log;
9 9
 import android.view.View;
10 10
 import android.widget.Button;
11
+import android.widget.TextView;
11 12
 import android.widget.Toast;
12 13
 
13 14
 import androidx.annotation.Nullable;
14 15
 import androidx.appcompat.app.AppCompatActivity;
15 16
 
16
-import com.google.android.gms.tasks.OnSuccessListener;
17
-import com.google.firebase.iid.FirebaseInstanceId;
18
-import com.google.firebase.iid.InstanceIdResult;
17
+import java.util.Observable;
18
+import java.util.Observer;
19 19
 
20
+import uprrp.tania.GlobalValues;
20 21
 import uprrp.tania.R;
21
-import uprrp.tania.networking.SendExperienceRegistration;
22 22
 import uprrp.tania.URLEventListener;
23
+import uprrp.tania.networking.SendExperienceRegistration;
23 24
 
24
-public class ExperienceRegistrationActivity  extends AppCompatActivity {
25
+public class ExperienceRegistrationActivity  extends AppCompatActivity implements Observer {
25 26
 
26 27
     private static final String TAG = "ExperienceRegistrationActivity";
27
-    private String DEVICE_TOKEN;
28 28
     private String EXPERIENCE_ID;
29 29
 
30 30
     @Override
31 31
     protected void onCreate(@Nullable Bundle savedInstanceState) {
32 32
 
33
-        // Start constructor and fetch UI components
33
+        // Start constructor
34 34
         super.onCreate(savedInstanceState);
35 35
         setContentView(R.layout.activity_experience_registration);
36
-        final Button experienceRegistrationButton = findViewById(R.id.buttonEnterExperience);
37
-
38
-        // Change all caps text to normal capitalization
39
-        // TODO: this is a workaround I found, any other acceptable solution is welcome
40
-        experienceRegistrationButton.setTransformationMethod(null);
41
-
42
-        // Request to Firebase...
43
-        // TODO: Should we implement retry logic in onFailureListener?
44
-        FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
45
-            @Override
46
-            public void onSuccess(InstanceIdResult instanceIdResult) {
47
-
48
-            // Get device's token
49
-            // IMPORTANT: must come first before calling
50
-            // another function that uses the token
51
-            DEVICE_TOKEN = instanceIdResult.getToken();
52
-
53
-            // Set onClick listener on button
54
-            experienceRegistrationButton.setOnClickListener(new View.OnClickListener() {
55
-                @Override
56
-                public void onClick(View v) {
57
-                    sendRegistrationRequest();
58
-                }
59
-            });
60
-
61
-            }
62
-        });
63 36
 
64 37
         // Fetch experience ID from URL (only if we launched this Activity from Browser)
65 38
         Intent intent = getIntent();
@@ -67,8 +40,75 @@ public class ExperienceRegistrationActivity  extends AppCompatActivity {
67 40
             Uri uri = intent.getData();
68 41
             assert uri != null; // TODO: figure out if this causes crashes...
69 42
             EXPERIENCE_ID = uri.getQueryParameter("id");
43
+            Log.wtf("EXPERIENCE ID", EXPERIENCE_ID);
44
+        }
45
+
46
+        // Listen for device token changes
47
+        this.startObservingGlobals();
48
+
49
+        // Disable interaction initially while token is being fetched
50
+        if(GlobalValues.getInstance().getDeviceToken() == null) {
51
+            Log.wtf("EXPERIENCE ID", "DISABLING");
52
+            disableInteractionTemporarily();
53
+        } else {
54
+            enableInteraction();
55
+        }
56
+
57
+        // Change all caps text to normal capitalization and add onClick listener
58
+        final Button experienceRegistrationButton = findViewById(R.id.buttonEnterExperience);
59
+        experienceRegistrationButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
60
+        experienceRegistrationButton.setOnClickListener(new View.OnClickListener() {
61
+            @Override
62
+            public void onClick(View v) {
63
+                sendRegistrationRequest();
64
+            }
65
+        });
66
+
67
+    }
68
+
69
+    // TAKEN FROM https://stackoverflow.com/questions/21886768/is-there-any-method-i-can-listen-for-changes-to-global-variable-to-trigger-an-ev
70
+    private void startObservingGlobals() {
71
+        GlobalValues.getInstance().addObserver(this);
72
+    }
73
+
74
+    // TAKEN FROM https://stackoverflow.com/questions/21886768/is-there-any-method-i-can-listen-for-changes-to-global-variable-to-trigger-an-ev
75
+    @Override
76
+    public void update(Observable observable, Object o) {
77
+        if(observable instanceof GlobalValues) {
78
+            if(o instanceof GlobalValues.ValueKey) {
79
+                if(((GlobalValues.ValueKey) o).getKey() == GlobalValues.ValueName.DEVICE_TOKEN) {
80
+                    if(GlobalValues.getInstance().getDeviceToken() == null) {
81
+                        disableInteraction();
82
+                    } else {
83
+                        enableInteraction();
84
+                    }
85
+                }
86
+            }
70 87
         }
88
+    }
89
+
90
+    private void enableInteraction() {
91
+        final Button experienceRegistrationButton = findViewById(R.id.buttonEnterExperience);
92
+        final TextView experienceRegistrationTextView = findViewById(R.id.experienceRegistrationText);
93
+
94
+        experienceRegistrationButton.setEnabled(true);
95
+        experienceRegistrationTextView.setText(R.string.experienceRegistrationDescriptionText);
96
+    }
97
+
98
+    private void disableInteraction() {
99
+        final Button experienceRegistrationButton = findViewById(R.id.buttonEnterExperience);
100
+        final TextView experienceRegistrationTextView = findViewById(R.id.experienceRegistrationText);
101
+
102
+        experienceRegistrationButton.setEnabled(false);
103
+        experienceRegistrationTextView.setText(R.string.tokenErrorText);
104
+    }
105
+
106
+    private void disableInteractionTemporarily() {
107
+        final Button experienceRegistrationButton = findViewById(R.id.buttonEnterExperience);
108
+        final TextView experienceRegistrationTextView = findViewById(R.id.experienceRegistrationText);
71 109
 
110
+        experienceRegistrationButton.setEnabled(false);
111
+        experienceRegistrationTextView.setText(R.string.loadingText);
72 112
     }
73 113
 
74 114
     private void sendRegistrationRequest() {
@@ -100,7 +140,7 @@ public class ExperienceRegistrationActivity  extends AppCompatActivity {
100 140
             }
101 141
         });
102 142
 
103
-        experienceRegistrationTask.execute(this.DEVICE_TOKEN, this.EXPERIENCE_ID);
143
+        experienceRegistrationTask.execute(GlobalValues.getInstance().getDeviceToken(), this.EXPERIENCE_ID);
104 144
 
105 145
         // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
106 146
         /*

+ 1
- 41
app/src/main/java/uprrp/tania/activities/MainActivity.java View File

@@ -1,10 +1,6 @@
1 1
 package uprrp.tania.activities;
2 2
 
3
-import android.content.Intent;
4
-import android.content.SharedPreferences;
5
-import android.net.Uri;
6 3
 import android.os.Bundle;
7
-import android.util.Log;
8 4
 import android.view.MenuItem;
9 5
 
10 6
 import androidx.annotation.NonNull;
@@ -12,17 +8,11 @@ import androidx.appcompat.app.ActionBar;
12 8
 import androidx.appcompat.widget.Toolbar;
13 9
 import androidx.fragment.app.Fragment;
14 10
 
15
-import com.amazonaws.auth.CognitoCachingCredentialsProvider;
16
-import com.amazonaws.regions.Regions;
17
-import com.google.android.gms.tasks.OnSuccessListener;
18 11
 import com.google.android.material.bottomnavigation.BottomNavigationView;
19
-import com.google.firebase.iid.FirebaseInstanceId;
20
-import com.google.firebase.iid.InstanceIdResult;
21 12
 
22 13
 import org.researchstack.backbone.ui.PinCodeActivity;
23 14
 
24 15
 import uprrp.tania.R;
25
-import uprrp.tania.SNSRegister;
26 16
 import uprrp.tania.fragments.AssessmentsFragment;
27 17
 import uprrp.tania.fragments.ConsentFragment;
28 18
 import uprrp.tania.fragments.WithdrawFragment;
@@ -39,31 +29,12 @@ public class MainActivity extends PinCodeActivity {
39 29
         setContentView(R.layout.activity_main);
40 30
 
41 31
 
42
-        // We need to know if the user has already registered, otherwise they need to do that first
43
-        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
44
-        boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
45
-        if(needsToRegister) {
46
-            Intent needsRegisterIntent = new Intent(this, GettingStartedActivity.class);
47
-            startActivity(needsRegisterIntent);
48
-        }
49
-
50
-
51
-        // Enable notifications
52
-        CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
53
-                getApplicationContext(),
54
-                getString(R.string.identityPoolID), // Identity pool ID
55
-                Regions.US_EAST_1 // Region
56
-        );
57
-        SNSRegister snsRegister = new SNSRegister(credentialsProvider);
58
-        snsRegister.execute();
59
-
60
-
61 32
         // Create toolbar
62 33
         Toolbar toolbar = findViewById(R.id.toolbar);
63 34
         setSupportActionBar(toolbar);
64 35
         ActionBar actionBar = getSupportActionBar();
65 36
         assert actionBar != null; // TODO: find out if this causes crashes
66
-        actionBar.setTitle(R.string.app_name);
37
+        actionBar.setTitle(R.string.appName);
67 38
         actionBar.setDisplayShowTitleEnabled(true);
68 39
 
69 40
 
@@ -102,14 +73,3 @@ public class MainActivity extends PinCodeActivity {
102 73
     }
103 74
 
104 75
 }
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-

+ 168
- 90
app/src/main/java/uprrp/tania/fragments/AssessmentsFragment.java View File

@@ -12,14 +12,11 @@ import android.view.ViewGroup;
12 12
 import android.widget.Button;
13 13
 import android.widget.TextView;
14 14
 import android.widget.Toast;
15
+
15 16
 import androidx.annotation.Nullable;
16 17
 import androidx.appcompat.app.AlertDialog;
17 18
 import androidx.fragment.app.Fragment;
18 19
 
19
-import com.google.android.gms.tasks.OnSuccessListener;
20
-import com.google.firebase.iid.FirebaseInstanceId;
21
-import com.google.firebase.iid.InstanceIdResult;
22
-
23 20
 import org.researchstack.backbone.StorageAccess;
24 21
 import org.researchstack.backbone.answerformat.AnswerFormat;
25 22
 import org.researchstack.backbone.answerformat.ChoiceAnswerFormat;
@@ -36,19 +33,22 @@ import org.researchstack.backbone.ui.ViewTaskActivity;
36 33
 import java.util.ArrayList;
37 34
 import java.util.List;
38 35
 import java.util.Objects;
36
+import java.util.Observable;
37
+import java.util.Observer;
39 38
 
40
-import uprrp.tania.networking.SendAnswers;
41
-import uprrp.tania.models.AnsweredQuestionModel;
39
+import uprrp.tania.GlobalValues;
40
+import uprrp.tania.R;
41
+import uprrp.tania.URLEventListener;
42 42
 import uprrp.tania.models.AnsweredAssessmentModel;
43
-import uprrp.tania.networking.FetchAssessment;
44
-import uprrp.tania.networking.FetchUserStatus;
43
+import uprrp.tania.models.AnsweredQuestionModel;
45 44
 import uprrp.tania.models.AssessmentModel;
46 45
 import uprrp.tania.models.QuestionModel;
47
-import uprrp.tania.R;
48
-import uprrp.tania.URLEventListener;
49 46
 import uprrp.tania.models.UserStatusModel;
47
+import uprrp.tania.networking.FetchAssessment;
48
+import uprrp.tania.networking.FetchUserStatus;
49
+import uprrp.tania.networking.SendAnswers;
50 50
 
51
-public class AssessmentsFragment extends Fragment {
51
+public class AssessmentsFragment extends Fragment implements Observer {
52 52
 
53 53
     // These variables came from the sample app provided to explain the use of Research Stack
54 54
     private static final int REQUEST_SURVEY = 1;
@@ -57,7 +57,6 @@ public class AssessmentsFragment extends Fragment {
57 57
 
58 58
     // Our variables
59 59
     private static final String TAG = "AssessmentsFragment";
60
-    private String DEVICE_TOKEN;
61 60
     private String ASSESSMENT_ID;
62 61
     private View thisFragment;
63 62
 
@@ -65,47 +64,40 @@ public class AssessmentsFragment extends Fragment {
65 64
     @Override
66 65
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
67 66
 
68
-        // Get reference for this fragment and other components
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);
67
+        // Constructor
68
+        thisFragment = inflater.inflate(R.layout.fragment_assessments, container, false);
72 69
 
73
-        // Change all caps text to normal capitalization
74
-        // TODO: this is a workaround I found, any other acceptable solution is welcome
75
-        surveyButton.setTransformationMethod(null);
76
-        refreshButton.setTransformationMethod(null);
70
+        // Listen for device token changes
71
+        this.startObservingGlobals();
77 72
 
78
-        // Request to Firebase...
79
-        // TODO: Should we implement retry logic in onFailureListener?
80
-        FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
81
-            @Override
82
-            public void onSuccess(InstanceIdResult instanceIdResult) {
83
-
84
-                // Get device's token
85
-                // IMPORTANT: must come first before calling
86
-                // another function that uses the token
87
-                DEVICE_TOKEN = instanceIdResult.getToken();
88
-
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
-                });
73
+        // Disable interaction initially while token is being fetched
74
+        if(GlobalValues.getInstance().getDeviceToken() == null) {
75
+            disableInteractionTemporarily();
76
+        } else {
77
+            enableInteraction();
78
+        }
96 79
 
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
-                });
80
+        // Display user status if available
81
+        UserStatusModel userStatus = GlobalValues.getInstance().getUserStatus();
82
+        if(userStatus != null) {
83
+            positiveUserStatus(userStatus);
84
+        }
104 85
 
105
-                // Fetch user status and assessment, if any
86
+        // Change all caps text to normal capitalization and add onClick listener
87
+        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
88
+        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
89
+        surveyButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
90
+        refreshButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
91
+        surveyButton.setOnClickListener(new View.OnClickListener() {
92
+            @Override
93
+            public void onClick(View v) {
94
+                fetchAssessment();
95
+            }
96
+        });
97
+        refreshButton.setOnClickListener(new View.OnClickListener() {
98
+            @Override
99
+            public void onClick(View v) {
106 100
                 fetchUserStatus();
107
-//            fetchAssessment();
108
-
109 101
             }
110 102
         });
111 103
 
@@ -113,61 +105,147 @@ public class AssessmentsFragment extends Fragment {
113 105
 
114 106
     }
115 107
 
116
-    private void fetchUserStatus() {
117
-
118
-        // Get text fields and initialize other stuff
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);
108
+    private void disableInteractionTemporarily() {
109
+        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
110
+        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
111
+        final TextView statusTextView = thisFragment.findViewById(R.id.statusTextView);
112
+        final TextView nextSurveyTextView = thisFragment.findViewById(R.id.nextSurveyTextView);
123 113
 
124
-        // Change UI to indicate loading is happening
114
+        surveyButton.setEnabled(false);
115
+        refreshButton.setEnabled(false);
125 116
         statusTextView.setText(R.string.loadingText);
126
-        nextSurveyTextView.setVisibility(View.GONE);
117
+        nextSurveyTextView.setVisibility(View.INVISIBLE);
118
+    }
127 119
 
128
-        // Define task
129
-        FetchUserStatus userStatusTask = new FetchUserStatus(new URLEventListener() {
120
+    private void disableInteraction() {
121
+        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
122
+        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
123
+        final TextView statusTextView = thisFragment.findViewById(R.id.statusTextView);
124
+        final TextView nextSurveyTextView = thisFragment.findViewById(R.id.nextSurveyTextView);
130 125
 
131
-            @Override
132
-            public void onSuccess(UserStatusModel userStatus) {
133
-                if(userStatus.isEnrolled()) {
126
+        surveyButton.setEnabled(false);
127
+        refreshButton.setEnabled(false);
128
+        statusTextView.setText(R.string.tokenErrorText);
129
+        nextSurveyTextView.setVisibility(View.INVISIBLE);
130
+    }
134 131
 
135
-                    // Change next survey date text (as well as status text)
136
-                    statusTextView.setText(userStatus.toString());
137
-                    nextSurveyTextView.setText(userStatus.getTimeToNext());
138
-                    nextSurveyTextView.setVisibility(View.VISIBLE);
132
+    private void enableInteraction() {
133
+        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
134
+        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
139 135
 
140
-                    // Hide refresh button (it only refreshes user status, anyways so...)
141
-                    refreshButton.setVisibility(View.GONE);
136
+        surveyButton.setEnabled(true);
137
+        refreshButton.setEnabled(true);
138
+        if(GlobalValues.getInstance().getUserStatus() == null) {
139
+            fetchUserStatus(); // refresh user status
140
+        }
141
+    }
142 142
 
143
-                    // Toggle "Answer" button visibility depending on survey availability
144
-                    if(userStatus.surveyAvailable()) {
145
-                        surveyButton.setVisibility(View.VISIBLE);
146
-                    } else {
147
-                        surveyButton.setVisibility(View.GONE);
148
-                    }
143
+    // TAKEN FROM https://stackoverflow.com/questions/21886768/is-there-any-method-i-can-listen-for-changes-to-global-variable-to-trigger-an-ev
144
+    private void startObservingGlobals() {
145
+        GlobalValues.getInstance().addObserver(this);
146
+    }
149 147
 
150
-                } else {
151
-                    // Prompt user to refresh status if user doesn't have an experience
152
-//                    statusTextView.setText("You are not enrolled in any experience.\nIf you think this is a mistake, contact your supervisors."); // for debugging/testing
153
-                    statusTextView.setText(userStatus.toString());
154
-                    nextSurveyTextView.setVisibility(View.GONE);
155
-                    surveyButton.setVisibility(View.GONE);
156
-                    refreshButton.setVisibility(View.VISIBLE);
148
+    // TAKEN FROM https://stackoverflow.com/questions/21886768/is-there-any-method-i-can-listen-for-changes-to-global-variable-to-trigger-an-ev
149
+    @Override
150
+    public void update(Observable observable, Object o) {
151
+        if(observable instanceof GlobalValues) {
152
+            if(o instanceof GlobalValues.ValueKey) {
153
+                switch(((GlobalValues.ValueKey) o).getKey()) {
154
+                    case DEVICE_TOKEN:
155
+                        if(GlobalValues.getInstance().getDeviceToken() == null) {
156
+                            disableInteraction();
157
+                        } else {
158
+                            enableInteraction();
159
+                        }
160
+                        break;
161
+                    case USER_STATUS:
162
+                        UserStatusModel userStatus = GlobalValues.getInstance().getUserStatus();
163
+                        if(userStatus == null) {
164
+                            negativeUserStatus();
165
+                        } else {
166
+                            positiveUserStatus(userStatus);
167
+                        }
168
+                        break;
157 169
                 }
158 170
             }
171
+        }
172
+    }
173
+
174
+    private void negativeUserStatus() {
175
+        Toast.makeText(getContext(), "Can't verify identity!", Toast.LENGTH_LONG).show();
176
+
177
+        final TextView statusTextView = thisFragment.findViewById(R.id.statusTextView);
178
+        final TextView nextSurveyTextView = thisFragment.findViewById(R.id.nextSurveyTextView);
179
+        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
180
+        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
181
+
182
+        statusTextView.setText(R.string.userStatusErrorText);
183
+        nextSurveyTextView.setVisibility(View.INVISIBLE);
184
+        surveyButton.setVisibility(View.INVISIBLE);
185
+        surveyButton.setEnabled(false);
186
+        refreshButton.setVisibility(View.VISIBLE);
187
+    }
188
+
189
+    private void positiveUserStatus(UserStatusModel userStatus) {
190
+
191
+        final TextView statusTextView = thisFragment.findViewById(R.id.statusTextView);
192
+        final TextView nextSurveyTextView = thisFragment.findViewById(R.id.nextSurveyTextView);
193
+        final Button surveyButton = thisFragment.findViewById(R.id.surveyButton);
194
+        final Button refreshButton = thisFragment.findViewById(R.id.refreshButton);
195
+
196
+        statusTextView.setText(userStatus.toString());
197
+
198
+        if(userStatus.isEnrolled()) {
159 199
 
200
+            nextSurveyTextView.setText(userStatus.getTimeToNext());
201
+            nextSurveyTextView.setVisibility(View.VISIBLE);
202
+
203
+            if(userStatus.surveyAvailable()) {
204
+                refreshButton.setVisibility(View.INVISIBLE);
205
+                refreshButton.setEnabled(false);
206
+                surveyButton.setVisibility(View.VISIBLE);
207
+                surveyButton.setEnabled(true);
208
+            } else {
209
+                surveyButton.setVisibility(View.INVISIBLE);
210
+                surveyButton.setEnabled(false);
211
+                refreshButton.setVisibility(View.VISIBLE);
212
+                refreshButton.setEnabled(true);
213
+            }
214
+
215
+        } else {
216
+
217
+            nextSurveyTextView.setText("");
218
+            nextSurveyTextView.setVisibility(View.INVISIBLE);
219
+
220
+            surveyButton.setVisibility(View.INVISIBLE);
221
+            surveyButton.setEnabled(false);
222
+            refreshButton.setVisibility(View.VISIBLE);
223
+            refreshButton.setEnabled(true);
224
+
225
+        }
226
+
227
+    }
228
+
229
+    private void fetchUserStatus() {
230
+
231
+        disableInteractionTemporarily();
232
+
233
+        // Define task
234
+        FetchUserStatus userStatusTask = new FetchUserStatus(new URLEventListener() {
235
+            @Override
236
+            public void onSuccess(UserStatusModel userStatus) {
237
+                GlobalValues.getInstance().setUserStatus(userStatus);
238
+                enableInteraction();
239
+            }
160 240
             @Override
161 241
             public void onFailure(Exception e) {
162
-                statusTextView.setText(R.string.userStatusErrorText);
163
-                Toast.makeText(getContext(), "Can't verify identity!", Toast.LENGTH_LONG).show();
164
-                Log.e("ERROR WHILE FETCHING USER STATUS", e.toString());
242
+                GlobalValues.getInstance().setUserStatus(null);
243
+                Log.e(TAG, "Error while fetching user status: " + e.toString());
165 244
             }
166
-
167 245
         });
168 246
 
169 247
         // Start task
170
-        userStatusTask.execute(this.DEVICE_TOKEN);
248
+        userStatusTask.execute(GlobalValues.getInstance().getDeviceToken());
171 249
 
172 250
     }
173 251
 
@@ -204,7 +282,7 @@ public class AssessmentsFragment extends Fragment {
204 282
         });
205 283
 
206 284
         // Start task
207
-        assessmentTask.execute(this.DEVICE_TOKEN);
285
+        assessmentTask.execute(GlobalValues.getInstance().getDeviceToken());
208 286
 
209 287
     }
210 288
 
@@ -259,7 +337,7 @@ public class AssessmentsFragment extends Fragment {
259 337
 
260 338
            @Override
261 339
            public void onFailure(Exception e) {
262
-               Log.e("ERROR WHILE SENDING ANSWERS", e.toString());
340
+               Log.e(TAG, "Error whilte sending answers: " + e.toString());
263 341
                e.printStackTrace();
264 342
                progressDialog.dismiss();
265 343
                promptRetrySend(answeredAssessment);
@@ -311,7 +389,7 @@ public class AssessmentsFragment extends Fragment {
311 389
         }
312 390
 
313 391
         // Return answered assessment
314
-        return new AnsweredAssessmentModel(this.ASSESSMENT_ID, this.DEVICE_TOKEN, answeredQuestions);
392
+        return new AnsweredAssessmentModel(this.ASSESSMENT_ID, GlobalValues.getInstance().getDeviceToken(), answeredQuestions);
315 393
 
316 394
     }
317 395
 
@@ -322,7 +400,7 @@ public class AssessmentsFragment extends Fragment {
322 400
 
323 401
         // Create instruction screen (add it to total steps)
324 402
         InstructionStep instructionStep = new InstructionStep(INSTRUCTION,
325
-                getString(R.string.app_name),
403
+                getString(R.string.appName),
326 404
                 assessment.getDescription());
327 405
         instructionStep.setStepTitle(R.string.surveyToolbarText);
328 406
         steps.add(0, instructionStep);

+ 71
- 26
app/src/main/java/uprrp/tania/fragments/WithdrawFragment.java View File

@@ -11,6 +11,7 @@ import android.view.LayoutInflater;
11 11
 import android.view.View;
12 12
 import android.view.ViewGroup;
13 13
 import android.widget.Button;
14
+import android.widget.TextView;
14 15
 import android.widget.Toast;
15 16
 
16 17
 import androidx.annotation.NonNull;
@@ -18,51 +19,95 @@ import androidx.annotation.Nullable;
18 19
 import androidx.appcompat.app.AlertDialog;
19 20
 import androidx.fragment.app.Fragment;
20 21
 
21
-import com.google.android.gms.tasks.OnSuccessListener;
22
-import com.google.firebase.iid.FirebaseInstanceId;
23
-import com.google.firebase.iid.InstanceIdResult;
24
-
25 22
 import java.util.Objects;
23
+import java.util.Observable;
24
+import java.util.Observer;
26 25
 
26
+import uprrp.tania.GlobalValues;
27 27
 import uprrp.tania.R;
28 28
 import uprrp.tania.URLEventListener;
29 29
 import uprrp.tania.activities.GettingStartedActivity;
30 30
 import uprrp.tania.networking.SendWithdrawal;
31 31
 
32
-public class WithdrawFragment extends Fragment {
32
+public class WithdrawFragment extends Fragment implements Observer {
33 33
 
34 34
     private static final String TAG = "WithdrawFragment";
35
-    private String DEVICE_TOKEN;
35
+    private View thisFragment;
36 36
 
37 37
     @Nullable
38 38
     @Override
39 39
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
40 40
 
41
-        // Get reference for this fragment and other components
42
-        View view = inflater.inflate(R.layout.fragment_withdrawal, container, false);
43
-        final Button withdrawButton = view.findViewById(R.id.withdrawButton);
41
+        // Constructor
42
+        thisFragment = inflater.inflate(R.layout.fragment_withdrawal, container, false);
43
+
44
+        // Listen for device token changes
45
+        this.startObservingGlobals();
44 46
 
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);
47
+        // Disable interaction initially while token is being fetched
48
+        if(GlobalValues.getInstance().getDeviceToken() == null) {
49
+            disableInteractionTemporarily();
50
+        } else {
51
+            enableInteraction();
52
+        }
49 53
 
50
-        // Get device's token and attach click listener once we have it
51
-        FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
54
+        // Change all caps text to normal capitalization and add onClick listener
55
+        final Button withdrawButton = thisFragment.findViewById(R.id.withdrawButton);
56
+        withdrawButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
57
+        withdrawButton.setOnClickListener(new View.OnClickListener() {
52 58
             @Override
53
-            public void onSuccess(InstanceIdResult instanceIdResult) {
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);
59
+            public void onClick(View v) {
60
+                promptConfirmation();
62 61
             }
63 62
         });
64 63
 
65
-        return view;
64
+        return thisFragment;
65
+
66
+    }
67
+
68
+    private void disableInteractionTemporarily() {
69
+        final Button withdrawButton = thisFragment.findViewById(R.id.withdrawButton);
70
+        final TextView withdrawTextView = thisFragment.findViewById(R.id.withdrawText);
71
+
72
+        withdrawButton.setEnabled(false);
73
+        withdrawTextView.setText(R.string.loadingText);
74
+    }
75
+
76
+    private void disableInteraction() {
77
+        final Button withdrawButton = thisFragment.findViewById(R.id.withdrawButton);
78
+        final TextView withdrawTextView = thisFragment.findViewById(R.id.withdrawText);
79
+
80
+        withdrawButton.setEnabled(false);
81
+        withdrawTextView.setText(R.string.tokenErrorText);
82
+    }
83
+
84
+    private void enableInteraction() {
85
+        final Button withdrawButton = thisFragment.findViewById(R.id.withdrawButton);
86
+        final TextView withdrawTextView = thisFragment.findViewById(R.id.withdrawText);
87
+
88
+        withdrawButton.setEnabled(true);
89
+        withdrawTextView.setText(R.string.withdrawDescriptionText);
90
+    }
91
+
92
+    // TAKEN FROM https://stackoverflow.com/questions/21886768/is-there-any-method-i-can-listen-for-changes-to-global-variable-to-trigger-an-ev
93
+    private void startObservingGlobals() {
94
+        GlobalValues.getInstance().addObserver(this);
95
+    }
96
+
97
+    // TAKEN FROM https://stackoverflow.com/questions/21886768/is-there-any-method-i-can-listen-for-changes-to-global-variable-to-trigger-an-ev
98
+    @Override
99
+    public void update(Observable observable, Object o) {
100
+        if(observable instanceof GlobalValues) {
101
+            if(o instanceof GlobalValues.ValueKey) {
102
+                if(((GlobalValues.ValueKey) o).getKey() == GlobalValues.ValueName.DEVICE_TOKEN) {
103
+                    if(GlobalValues.getInstance().getDeviceToken() == null) {
104
+                        disableInteraction();
105
+                    } else {
106
+                        enableInteraction();
107
+                    }
108
+                }
109
+            }
110
+        }
66 111
     }
67 112
 
68 113
     private void promptConfirmation() {
@@ -127,7 +172,7 @@ public class WithdrawFragment extends Fragment {
127 172
         });
128 173
 
129 174
         // Start task
130
-        sendWithdrawalTask.execute(DEVICE_TOKEN);
175
+        sendWithdrawalTask.execute(GlobalValues.getInstance().getDeviceToken());
131 176
 
132 177
         // UNCOMMENT THIS FOR TESTING (REMEMBER TO COMMENT .execute() LINE)
133 178
         /*

+ 19
- 3
app/src/main/java/uprrp/tania/models/UserStatusModel.java View File

@@ -37,17 +37,33 @@ public class UserStatusModel {
37 37
         }
38 38
     }
39 39
 
40
-    private String formatTimeToNext() {
40
+    private boolean isInteger(String s) {
41
+        return s.matches("-?\\d+");
42
+    }
41 43
 
44
+    private boolean validTimeToNext() {
42 45
         // Format is DD:HH:MM (can be negative if survey can be answered)
43 46
         String[] parts = this.time_to_next.split(":");
44 47
 
45
-        // Input validation
46
-        if(parts[0].equals("") || parts[1].equals("") || parts[2].equals("")) {
48
+        if(parts.length != 3) {
49
+            return false;
50
+        } else if(!isInteger(parts[0]) || !isInteger(parts[1]) || !isInteger(parts[2])) {
51
+            return false;
52
+        } else {
53
+            return true;
54
+        }
55
+    }
56
+
57
+    private String formatTimeToNext() {
58
+
59
+        // Validation
60
+        if(!this.validTimeToNext()) {
47 61
             Log.wtf(TAG, "Backend gave an invalid time_to_next: " + this.time_to_next);
48 62
             return ".."; // forms ellipsis
49 63
         }
50 64
 
65
+        // Format is DD:HH:MM (can be negative if survey can be answered)
66
+        String[] parts = this.time_to_next.split(":");
51 67
         int days = Integer.parseInt(parts[0]);
52 68
         int hours = Integer.parseInt(parts[1]);
53 69
         int minutes = Integer.parseInt(parts[2]);

+ 3
- 5
app/src/main/java/uprrp/tania/networking/FetchAssessment.java View File

@@ -1,6 +1,5 @@
1 1
 package uprrp.tania.networking;
2 2
 
3
-import android.content.res.Resources;
4 3
 import android.os.AsyncTask;
5 4
 import android.util.Log;
6 5
 
@@ -19,7 +18,6 @@ import java.net.URL;
19 18
 
20 19
 import javax.net.ssl.HttpsURLConnection;
21 20
 
22
-import uprrp.tania.R;
23 21
 import uprrp.tania.URLEventListener;
24 22
 import uprrp.tania.models.AssessmentModel;
25 23
 import uprrp.tania.models.EmptyAssessmentModel;
@@ -27,6 +25,7 @@ import uprrp.tania.models.EmptyAssessmentModel;
27 25
 public class FetchAssessment extends AsyncTask<String, Void, JSONObject> {
28 26
 
29 27
     private static final String TAG = "FetchAssessment";
28
+    private static final String assessmentBaseURL = "https://tania.uprrp.edu/getSubQ2.php?tk=";
30 29
     private final URLEventListener myCallBack;
31 30
 
32 31
     public FetchAssessment(URLEventListener callback) {
@@ -39,8 +38,7 @@ public class FetchAssessment extends AsyncTask<String, Void, JSONObject> {
39 38
 
40 39
         try {
41 40
 
42
-            String getMomentsBaseURL = Resources.getSystem().getString(R.string.assessmentsBaseURL);
43
-            URL url = new URL(getMomentsBaseURL + deviceToken);
41
+            URL url = new URL(assessmentBaseURL + deviceToken);
44 42
             Log.d(TAG, "token:" + deviceToken); // log
45 43
             Log.d(TAG, "url:" + url.toString()); // log
46 44
             HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
@@ -82,7 +80,7 @@ public class FetchAssessment extends AsyncTask<String, Void, JSONObject> {
82 80
     protected void onPostExecute(JSONObject obj) {
83 81
 
84 82
         if(this.myCallBack == null) {
85
-            this.myCallBack.onFailure(new Exception("Callback wasn't initialized first!"));
83
+            Log.e(TAG, "Callback wasn't initialized first!");
86 84
             return;
87 85
         }
88 86
 

+ 2
- 4
app/src/main/java/uprrp/tania/networking/FetchUserStatus.java View File

@@ -1,6 +1,5 @@
1 1
 package uprrp.tania.networking;
2 2
 
3
-import android.content.res.Resources;
4 3
 import android.os.AsyncTask;
5 4
 import android.util.Log;
6 5
 
@@ -20,7 +19,6 @@ import java.net.URL;
20 19
 
21 20
 import javax.net.ssl.HttpsURLConnection;
22 21
 
23
-import uprrp.tania.R;
24 22
 import uprrp.tania.URLEventListener;
25 23
 import uprrp.tania.models.EmptyUserStatusModel;
26 24
 import uprrp.tania.models.UserStatusModel;
@@ -28,6 +26,7 @@ import uprrp.tania.models.UserStatusModel;
28 26
 public class FetchUserStatus extends AsyncTask<String, Void, JSONArray> {
29 27
 
30 28
     private static final String TAG = "FetchUserStatus";
29
+    private static final String userStatusBaseURL = "https://tania.uprrp.edu/status.php?tk=";
31 30
     private final URLEventListener myCallBack;
32 31
 
33 32
     public FetchUserStatus(URLEventListener callback) {
@@ -40,7 +39,6 @@ public class FetchUserStatus extends AsyncTask<String, Void, JSONArray> {
40 39
 
41 40
         try {
42 41
 
43
-            String userStatusBaseURL = Resources.getSystem().getString(R.string.userStatusBaseURL);
44 42
             URL url = new URL(userStatusBaseURL + deviceToken);
45 43
             Log.d(TAG, "token:" + deviceToken); // log
46 44
             Log.d(TAG, "url:" + url.toString()); // log
@@ -84,7 +82,7 @@ public class FetchUserStatus extends AsyncTask<String, Void, JSONArray> {
84 82
         super.onPostExecute(arr);
85 83
 
86 84
         if(this.myCallBack == null) {
87
-            this.myCallBack.onFailure(new Exception("Callback wasn't initialized first!"));
85
+            Log.e(TAG, "Callback wasn't initialized first!");
88 86
             return;
89 87
         }
90 88
 

+ 3
- 4
app/src/main/java/uprrp/tania/networking/SendAnswers.java View File

@@ -1,6 +1,5 @@
1 1
 package uprrp.tania.networking;
2 2
 
3
-import android.content.res.Resources;
4 3
 import android.os.AsyncTask;
5 4
 import android.util.Log;
6 5
 
@@ -19,13 +18,13 @@ import java.net.URLEncoder;
19 18
 
20 19
 import javax.net.ssl.HttpsURLConnection;
21 20
 
22
-import uprrp.tania.R;
23 21
 import uprrp.tania.URLEventListener;
24 22
 import uprrp.tania.models.AnsweredAssessmentModel;
25 23
 
26 24
 public class SendAnswers extends AsyncTask<AnsweredAssessmentModel, Void, String> {
27 25
 
28 26
     private static final String TAG = "SendAnswers";
27
+    private static final String sendAnswersURL = "https://tania.uprrp.edu/parseAnswers.php";
29 28
     private final URLEventListener myCallback;
30 29
 
31 30
     public SendAnswers(URLEventListener callback) {
@@ -97,7 +96,7 @@ public class SendAnswers extends AsyncTask<AnsweredAssessmentModel, Void, String
97 96
             String encodedRequestBody = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(surveyResults.toString(), "UTF-8");
98 97
 
99 98
             // Send POST data request
100
-            URL url = new URL(Resources.getSystem().getString(R.string.sendAnswersURL));
99
+            URL url = new URL(sendAnswersURL);
101 100
             HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
102 101
             conn.setDoOutput(true);
103 102
             OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
@@ -147,7 +146,7 @@ public class SendAnswers extends AsyncTask<AnsweredAssessmentModel, Void, String
147 146
     protected void onPostExecute(String response) {
148 147
 
149 148
         if(this.myCallback == null) {
150
-            this.myCallback.onFailure(new Exception("Callback wasn't initialized first!"));
149
+            Log.e(TAG, "Callback wasn't initialized first!");
151 150
             return;
152 151
         }
153 152
 

+ 3
- 4
app/src/main/java/uprrp/tania/networking/SendExperienceRegistration.java View File

@@ -1,6 +1,5 @@
1 1
 package uprrp.tania.networking;
2 2
 
3
-import android.content.res.Resources;
4 3
 import android.os.AsyncTask;
5 4
 import android.util.Log;
6 5
 
@@ -16,12 +15,12 @@ import java.net.URLEncoder;
16 15
 
17 16
 import javax.net.ssl.HttpsURLConnection;
18 17
 
19
-import uprrp.tania.R;
20 18
 import uprrp.tania.URLEventListener;
21 19
 
22 20
 public class SendExperienceRegistration extends AsyncTask<String, String, String> {
23 21
 
24 22
     private static final String TAG = "SendActivateExperience";
23
+    private static final String activateExperienceURL = "https://tania.uprrp.edu/inscripcionExperiencia.php";
25 24
     private final URLEventListener myCallback;
26 25
 
27 26
     public SendExperienceRegistration(URLEventListener callback) {
@@ -64,7 +63,7 @@ public class SendExperienceRegistration extends AsyncTask<String, String, String
64 63
             String encodedRequestBody = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(experienceRegistrationJSON.toString(), "UTF-8");
65 64
 
66 65
             // Send POST data request
67
-            URL url = new URL(Resources.getSystem().getString(R.string.activateExperienceURL));
66
+            URL url = new URL(activateExperienceURL);
68 67
             HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
69 68
             conn.setDoOutput(true);
70 69
             OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
@@ -110,7 +109,7 @@ public class SendExperienceRegistration extends AsyncTask<String, String, String
110 109
     protected void onPostExecute(String response) {
111 110
 
112 111
         if(this.myCallback == null) {
113
-            this.myCallback.onFailure(new Exception("Callback wasn't initialized first!"));
112
+            Log.e(TAG, "Callback wasn't initialized first!");
114 113
             return;
115 114
         }
116 115
 

+ 3
- 4
app/src/main/java/uprrp/tania/networking/SendWithdrawal.java View File

@@ -1,6 +1,5 @@
1 1
 package uprrp.tania.networking;
2 2
 
3
-import android.content.res.Resources;
4 3
 import android.os.AsyncTask;
5 4
 import android.util.Log;
6 5
 
@@ -19,12 +18,12 @@ import java.nio.charset.StandardCharsets;
19 18
 
20 19
 import javax.net.ssl.HttpsURLConnection;
21 20
 
22
-import uprrp.tania.R;
23 21
 import uprrp.tania.URLEventListener;
24 22
 
25 23
 public class SendWithdrawal extends AsyncTask<String, String, String> {
26 24
 
27 25
     private static final String TAG = "SendWithdrawal";
26
+    private static final String withdrawalURL = "https://tania.uprrp.edu/withdrawal.php";
28 27
     private final URLEventListener myCallback;
29 28
 
30 29
     public SendWithdrawal(URLEventListener callback) {
@@ -56,7 +55,7 @@ public class SendWithdrawal extends AsyncTask<String, String, String> {
56 55
             String encodedRequestBody = URLEncoder.encode("data", "UTF-8") + "=" + URLEncoder.encode(withdrawJSON.toString(), "UTF-8");
57 56
 
58 57
             // Send POST data request
59
-            URL url = new URL(Resources.getSystem().getString(R.string.withdrawalURL));
58
+            URL url = new URL(withdrawalURL);
60 59
             HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
61 60
             conn.setDoOutput(true);
62 61
             Writer writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8));
@@ -101,7 +100,7 @@ public class SendWithdrawal extends AsyncTask<String, String, String> {
101 100
     protected void onPostExecute(String response) {
102 101
 
103 102
         if(this.myCallback == null) {
104
-            this.myCallback.onFailure(new Exception("Callback wasn't initialized first!"));
103
+            Log.e(TAG, "Callback wasn't initialized first!");
105 104
             return;
106 105
         }
107 106
 

app/src/main/java/uprrp/tania/AppPrefs.java → app/src/main/java/uprrp/tania/unused/AppPrefs.java View File

@@ -1,4 +1,4 @@
1
-package uprrp.tania;
1
+package uprrp.tania.unused;
2 2
 
3 3
 import android.content.Context;
4 4
 import android.content.SharedPreferences;

app/src/main/java/uprrp/tania/CognitoSettings.java → app/src/main/java/uprrp/tania/unused/CognitoSettings.java View File

@@ -1,4 +1,4 @@
1
-package uprrp.tania;
1
+package uprrp.tania.unused;
2 2
 
3 3
 import android.content.Context;
4 4
 

+ 7
- 4
app/src/main/res/drawable/button_background.xml View File

@@ -1,9 +1,12 @@
1 1
 <?xml version="1.0" encoding="utf-8" ?>
2 2
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
3
-    <!--  Non focused states  -->
4
-    <item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/button_unfocused" />
5
-    <item android:state_focused="false" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/button_unfocused" />
6
-    <!--  Focused states  -->
3
+    <!--  Disabled  -->
4
+    <item android:state_enabled="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/button_disabled" />
5
+    <item android:state_enabled="false" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/button_disabled" />
6
+    <!--  Enabled  -->
7
+    <item android:state_enabled="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/button_unfocused" />
8
+    <item android:state_enabled="true" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/button_unfocused" />
9
+    <!--  Focused  -->
7 10
 <!--    <item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/button_focus" />-->
8 11
 <!--    <item android:state_focused="true" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/button_focus" />-->
9 12
     <!--  Pressed  -->

+ 12
- 0
app/src/main/res/drawable/button_disabled.xml View File

@@ -0,0 +1,12 @@
1
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
2
+<!--  Border  -->
3
+<!--    <stroke android:width="1dp" android:color="@color/colorPrimary" />-->
4
+<!--  Radius  -->
5
+<corners android:radius="@dimen/cornerRadius" />
6
+<!--  Gradient  -->
7
+<!--    FF6800 -> FF8000 -> FF9700    -->
8
+<gradient android:startColor="@color/colorPrimaryDisabled"
9
+    android:centerColor="@color/colorPrimaryDisabled"
10
+    android:endColor="@color/colorPrimaryDisabled"
11
+    android:angle="90" />
12
+</shape>

+ 4
- 3
app/src/main/res/layout/activity_experience_registration.xml View File

@@ -25,7 +25,7 @@
25 25
         app:layout_constraintTop_toTopOf="parent" />
26 26
 
27 27
     <TextView
28
-        android:id="@+id/textViewConfirmMessage"
28
+        android:id="@+id/experienceRegistrationText"
29 29
         android:layout_width="0dp"
30 30
         android:layout_height="wrap_content"
31 31
         android:layout_marginStart="@dimen/horizontalMargin"
@@ -33,12 +33,13 @@
33 33
         android:layout_marginEnd="@dimen/horizontalMargin"
34 34
         android:fontFamily="sans-serif"
35 35
         android:gravity="center"
36
-        android:text="@string/experienceRegistrationDescriptionText"
36
+        android:text="@string/loadingText"
37 37
         android:textAlignment="center"
38 38
         android:textSize="18sp"
39 39
         app:layout_constraintEnd_toEndOf="parent"
40 40
         app:layout_constraintStart_toStartOf="parent"
41
-        app:layout_constraintTop_toBottomOf="@+id/textViewActivateExperience" />
41
+        app:layout_constraintTop_toBottomOf="@+id/textViewActivateExperience"
42
+        tools:text="@string/experienceRegistrationDescriptionText" />
42 43
 
43 44
     <Button
44 45
         android:id="@+id/buttonEnterExperience"

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

@@ -21,12 +21,13 @@
21 21
         android:textColor="@android:color/white"
22 22
         android:textSize="@dimen/buttonTextSize"
23 23
         android:textStyle="bold"
24
+        android:visibility="visible"
24 25
         app:layout_constraintBottom_toBottomOf="parent"
25 26
         app:layout_constraintEnd_toEndOf="parent"
26 27
         app:layout_constraintHeight_max="@dimen/buttonMaxHeight"
27 28
         app:layout_constraintStart_toStartOf="parent"
28 29
         app:layout_constraintTop_toBottomOf="@id/statusTextView"
29
-        tools:visibility="gone" />
30
+        tools:visibility="invisible" />
30 31
 
31 32
     <androidx.appcompat.widget.AppCompatButton
32 33
         android:id="@+id/surveyButton"
@@ -44,7 +45,7 @@
44 45
         android:textColor="@android:color/white"
45 46
         android:textSize="@dimen/buttonTextSize"
46 47
         android:textStyle="bold"
47
-        android:visibility="gone"
48
+        android:visibility="invisible"
48 49
         app:layout_constraintBottom_toBottomOf="parent"
49 50
         app:layout_constraintEnd_toEndOf="parent"
50 51
         app:layout_constraintHeight_max="@dimen/buttonMaxHeight"
@@ -76,13 +77,11 @@
76 77
         android:textAlignment="center"
77 78
         android:textSize="18sp"
78 79
         android:textStyle="bold"
79
-        android:visibility="gone"
80 80
         app:layout_constraintBottom_toTopOf="@+id/surveyButton"
81 81
         app:layout_constraintEnd_toEndOf="parent"
82 82
         app:layout_constraintHorizontal_bias="0.5"
83 83
         app:layout_constraintStart_toStartOf="parent"
84
-        tools:text="Next survey in 2 days, 6 hours."
85
-        tools:visibility="visible" />
84
+        tools:text="Next survey in 2 days, 6 hours." />
86 85
 
87 86
     <TextView
88 87
         android:id="@+id/assessmentTitle"

+ 3
- 2
app/src/main/res/layout/fragment_withdrawal.xml View File

@@ -30,12 +30,13 @@
30 30
         android:layout_marginStart="@dimen/horizontalMargin"
31 31
         android:layout_marginTop="16dp"
32 32
         android:layout_marginEnd="@dimen/horizontalMargin"
33
-        android:text="@string/withdrawing_text"
33
+        android:text="@string/loadingText"
34 34
         android:textAlignment="textStart"
35 35
         android:textSize="@dimen/sectionDescriptionTextSize"
36 36
         app:layout_constraintEnd_toEndOf="parent"
37 37
         app:layout_constraintStart_toStartOf="parent"
38
-        app:layout_constraintTop_toBottomOf="@+id/withdrawTitle" />
38
+        app:layout_constraintTop_toBottomOf="@+id/withdrawTitle"
39
+        tools:text="@string/withdrawDescriptionText" />
39 40
 
40 41
     <Button
41 42
         android:id="@+id/withdrawButton"

+ 1
- 1
app/src/main/res/values/colors.xml View File

@@ -2,11 +2,11 @@
2 2
 <resources>
3 3
     <color name="colorPrimary">#397af3</color>
4 4
     <color name="colorPrimaryDark">#174396</color>
5
+    <color name="colorPrimaryDisabled">#7ea5ed</color>
5 6
     <color name="colorAccent">#174396</color>
6 7
     <color name="dark_gray">#cccccc</color>
7 8
     <color name="textColor1">#FFFCEFD3</color>
8 9
     <color name="textColor2">#423E3E</color>
9
-
10 10
 </resources>
11 11
 
12 12
 

+ 9
- 8
app/src/main/res/values/strings.xml View File

@@ -1,5 +1,4 @@
1 1
 <resources>
2
-    <string name="app_name">TANIA</string>
3 2
     <string name="menu_data_cleared">La información ha sido borrada</string>
4 3
     <string name="user_name">Nombre de usuario:</string>
5 4
     <string name="date_consented">Fecha de consentimiento:</string>
@@ -22,17 +21,19 @@
22 21
     <string name="title_activity_consent_pdf_viewer">Consent TANIA</string>
23 22
 
24 23
     <!-- !!!!! POST-Víctor !!!!! -->
25
-
26 24
     <!--  AmazonCognito Details  -->
27 25
     <string name="identityPoolID">us-east-1:574094cd-0784-4e26-bd14-4fa72ae63579</string>
28 26
     <!--  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>
27
+<!--    <string name="sendAnswersURL">https://tania.uprrp.edu/parseAnswers.php</string>-->
28
+<!--    <string name="activateExperienceURL">https://tania.uprrp.edu/inscripcionExperiencia.php</string>-->
29
+<!--    <string name="withdrawalURL">https://tania.uprrp.edu/withdrawal.php</string>-->
30
+<!--    <string name="userStatusBaseURL">https://tania.uprrp.edu/status.php?tk=</string>-->
31
+<!--    <string name="assessmentsBaseURL">https://tania.uprrp.edu/getSubQ2.php?tk=</string>-->
32
+<!--    <string name="loginBaseURL">https://tania.uprrp.edu/recoverAccount.php</string>-->
34 33
     <!--  General App Configurations  -->
34
+    <string name="appName">TANIA</string>
35 35
     <string name="surveyToolbarText">Assessment</string>
36
+    <string name="tokenErrorText">There was an error…\nPlease come back later!</string>
36 37
     <!--  Assessment Fragment  -->
37 38
     <string name="mainGreetingText">Hello! 👋</string>
38 39
     <string name="loadingText">Please wait a moment…</string>
@@ -42,7 +43,7 @@
42 43
     <!-- Withdraw Fragment -->
43 44
     <string name="withdrawTitleText">Withdraw from Study</string>
44 45
     <string name="withdrawButtonText">Withdraw</string>
45
-    <string name="withdrawing_text">If you no longer want to participate in this research study, you can choose to withdraw. By withdrawing, you understand that your decision is final and your account on TANIA will be removed without any chance of recovery.</string>
46
+    <string name="withdrawDescriptionText">If you no longer want to participate in this research study, you can choose to withdraw. By withdrawing, you understand that your decision is final and your account on TANIA will be removed without any chance of recovery.</string>
46 47
     <!--  Experience Registration Activity  -->
47 48
     <string name="experienceRegistrationTitleText">Activate Experience</string>
48 49
     <string name="experienceRegistrationDescriptionText">Click the button below to enter the research experience you are participating in.</string>