Commit 7014c9fb authored by jayamin's avatar jayamin

Final Demo Version 0.01

parent 31131fa4
# Zenn
# ZENN
Zenn is a digitalized friend for your brain powered by AI.
## Installation
Open or import into Android Studio. Do a grade clean, build, and sync if necessary.
```
gradle --refresh-dependencies
gradle --clean
gradle --build
```
## Usage
```c
Run in your emulator of choice.
For best performance, run on a trusted device
(with USB Debugging enabled)
```
## Contributing
Please contribute and pull and let me know what you come up with!
For big ideas, open an issue or contact me.
Please follow formatting and javadoc in similar fashion.
Thanks :)
## Authors and Acknowledgement
Huge thanks to Dr. Mat and his TAs in CPRE 388 at ISU (Fall 2019).
Additional credits in app menu.
Designed by Jay Amin [ jayamin@iastate.edu ].
## License
[MIT](https://choosealicense.com/licenses/mit/)
......@@ -21,13 +21,16 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.0.0'
implementation 'androidx.navigation:navigation-ui:2.0.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'com.google.android.material:material:1.2.0-alpha02'
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.1.0"
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="edu.iastate.zenn">
<application
......@@ -10,17 +9,49 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".controller.FeelingsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_feelings"
android:parentActivityName=".controller.MainActivity"
android:theme="@style/FullscreenTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="edu.iastate.zenn.controller.MainActivity" />
</activity>
<activity
android:name=".controller.SettingsActivity"
android:label="@string/title_activity_settings"
android:parentActivityName=".controller.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="edu.iastate.zenn.controller.MainActivity" />
</activity>
<activity
android:name=".MainActivity"
android:label="@string/app_name">
android:name=".controller.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="edu.iastate.zenn.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
</application>
<dist:module dist:instant="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>
\ No newline at end of file
package edu.iastate.zenn;
import android.os.Bundle;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
}
package edu.iastate.zenn.controller;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceFragmentCompat;
import edu.iastate.zenn.R;
/**
* Settings activity that houses the settings fragment
*
* This activity is the CONTROLLER that interfaces with the data in root_preferences.xml
* and updates the VIEW in settings_activity.xml accordingly. It is where the user can choose their
* settings and see credits.
*
* @author Jay Amin
* @version 0.01
*/
public class SettingsActivity extends AppCompatActivity {
/**
* Method that runs every time SettingsActivity is created
*
* @param savedInstanceState is the input bundle for the saved instance
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
/**
* This method forces the user to use the upper back button that has more consistent behavior
*
*/
@Override
public void onBackPressed()
{
/*
Was seeing some bugs with standard back behavior versus app bar back.
Didn't have enough time to step into core methods and behavior.
This is a temporary solution until I can properly override and manage the
lifecycles according to spec.
*/
Toast.makeText(this, "Please use back button above.", Toast.LENGTH_LONG).show();
}
/**
* Settings fragment
*
* This is the fragment that populates SettingsActivity
*
*/
public static class SettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
}
}
}
\ No newline at end of file
package edu.iastate.zenn.model;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
/**
* FeelingsActivityViewModel that has data for FeelingsActivity
*
* This activity is the model for the controller FeelingsActivity.
*
* @author Jay Amin
* @version 0.01
*/
public class FeelingsActivityViewModel extends ViewModel {
/**
* Tag for custom logging
*/
private String TAG = "CustomLog_FeelingsActivityViewModel";
/**
* MutableLiveData for timer
*/
private MutableLiveData<Long> elapsedTime = new MutableLiveData<>();
/**
* Current feeling
*/
public String currentFeeling = "";
/**
* Initial time
*/
private long initialTime = 0;
/**
* Hash map for feeling descriptions
*/
private HashMap<String, String> feelingDescriptions = new HashMap<String,String>();
/**
* FeelingsActivityViewModel
*/
public FeelingsActivityViewModel(){
populateFeelingsHashMap();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
final long newValue = (SystemClock.elapsedRealtime() - initialTime) / 1000;
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
elapsedTime.setValue(newValue);
}
});
}
}, 1000, 1000);
}
/**
* Getter for elapsed time
*
* @return returns the livedata for elapsed time
*/
public LiveData<Long> getElapsedTime() {
return elapsedTime;
}
/**
* Setter for elapsed time
*
* @param initialTime is the initial time to set
*/
public void setInitialTime(long initialTime){
this.initialTime = initialTime;
}
/**
* Starts timer
*/
public void startTimer() {
Log.d(TAG,"Timer Started");
setInitialTime(SystemClock.elapsedRealtime());
}
/**
* Stops timer
*/
public void stopTimer() {
Log.d(TAG,"Timer Stopped");
}
/**
* Getter for current feeling
*
* @return returns the current feeling
*/
public String getCurrentFeeling() {
return currentFeeling;
}
/**
* Setter for current feeling
*
* @param currentFeeling is the feeling that needs the be set
*/
public void setCurrentFeeling(String currentFeeling) {
this.currentFeeling = currentFeeling;
}
/**
* Getter for feeling description
*
* @param feeling is the feeling the description is requested for
* @return returns the feeling description
*/
public String getFeelingDescription(String feeling){
return feelingDescriptions.get(feeling);
}
/**
* Setter for feeling description
*
* @param description is description for feeling
* @param feeling is the feeling name
*/
public void setFeelingDescription(String feeling, String description){
feelingDescriptions.put(feeling, description);
}
/**
* Populates feelings hash map
*/
public void populateFeelingsHashMap(){
feelingDescriptions.put("Neutral",
"Breathe as you think 'it's good to be here.' Smile at the little things " +
"and enjoy the moment.");
feelingDescriptions.put("Anger",
"Breathe as you think 'what made me angry?' Ask yourself if it's a small or " +
"big deal, and then explore more neutral compromises without anger.");
feelingDescriptions.put("Stress",
"Breathe as you focus on your stress. If it is unjustified, try to change your " +
"position or drink a glass of water. If it is justified, turn the " +
"stress over on itself and use it to jump-start a task that needs to get " +
"done.");
feelingDescriptions.put("Fear",
"Breathe as you think about what is causing your fear. The purpose of fear isn't " +
"'to make you more stressed, but rather to help you navigate potential " +
"danger' - no matter the context. Use it to your advantage.");
feelingDescriptions.put("Anxiety",
"Breathe as you think about what is around you. Research has shown anxiety " +
"heightens your senses. Use that to your advantage to take in the " +
"beautiful world around you one deep breath at a time.");
feelingDescriptions.put("Sadness",
"Breathe as you reflect on what made you sad. Often, it will be dissatisfaction " +
"with yourself or an event out of your control. It can also be a good " +
"thing, because it means you are passionate about something. It helps " +
"to step back and get some perspective.");
feelingDescriptions.put("Guilt",
"Breathe as you think about the source of your guilt. If it is unjustified, take a " +
"few deep breaths and don't internalize it. If it is justified, use it " +
"as a 'catalyst to make changes in your life.'");
}
}
package edu.iastate.zenn.model;
import android.net.Uri;
import androidx.lifecycle.ViewModel;
/**
* MainActivityViewModel that has data for MainActivity.
*
* This activity is the model for the controller MainActivity.
*
* @author Jay Amin
* @version 0.01
*/
public class MainActivityViewModel extends ViewModel {
/**
* Tag for custom logging
*/
private String TAG = "CustomLog_MainActivityViewModel";
/**
* Current feeling in MainActivityViewModel
*/
private String currentFeeling = "";
/**
* Feelings array for numberpicker
*/
private String[] feelingsArray = new String[] {"Neutral","Anger", "Stress", "Fear", "Anxiety",
"Sadness", "Guilt", "Custom"};
/**
* Array for custom image picker dialog
*/
private String[] customImgDialogChoicesArray = new String[] {"Choose from gallery"};
/**
* Image Uri for custom image
*/
private Uri imageUri = null;
/**
* ints for ai stats
*/
private int morningStat=0,afternoonStat=0,nightStat=0;
/**
* Block string for ai
*/
private String proceduralBlockOne = "[...]";
/**
* Block string for ai
*/
private String proceduralBlockTwo = "[...]";
/**
* Block string for ai
*/
private String proceduralBlockThree = "[...]";
/**
* Block string for ai
*/
private String proceduralBlockFour = "[...]";
/**
* Getter for current feeling
*
* @return returns current feeling
*/
public String getCurrentFeeling() {
return currentFeeling;
}
/**
* Setter for current feeling
*
* @param currentFeeling is the current feeling to be set
*/
public void setCurrentFeeling(String currentFeeling) {
this.currentFeeling = currentFeeling;
}
/**
* Getter for custom image uri
*
* @return returns image uri
*/
public Uri getImageUri() { return imageUri; }
/**
* Setter for custom image uri
*
* @param imageUri is the image uri to be set
*/
public void setImageUri(Uri imageUri) {
this.imageUri = imageUri;
}
/**
* Getter for feelings array
*
* @return returns the feelings array
*/
public String[] getFeelingsArray() {
return feelingsArray;
}
/**
* Setter for feelings array
*
* @param feelingsArray is the input feelings array to be set
*/
public void setFeelingsArray(String[] feelingsArray) {
this.feelingsArray = feelingsArray;
}
/**
* Getter for dialog choices array
*
* @return returns the custom image picker choices array
*/
public String[] getCustomImgDialogChoicesArray() {
return customImgDialogChoicesArray;
}
/**
* Getter for morning stat
*
* @return returns the morning stat
*/
public int getMorningStat() {
return morningStat;
}
/**
* Setter for morning stat
*
* @param morningStat is the input morningStat to be set
*/
public void setMorningStat(int morningStat) {
this.morningStat = morningStat;
}
/**
* Getter for afternoon stat
*
* @return returns the afternoon stat
*/
public int getAfternoonStat() {
return afternoonStat;
}
/**
* Sets the afternoon stat
*
* @param afternoonStat is the input afternoonStat to be set
*/
public void setAfternoonStat(int afternoonStat) {
this.afternoonStat = afternoonStat;
}
/**
* Getter for night stat
*
* @return returns the night stat
*/
public int getNightStat() {
return nightStat;
}
/**
* Setter for night stat
*
* @param nightStat is the input nightStat to be set
*/
public void setNightStat(int nightStat) {
this.nightStat = nightStat;
}
/**
* Procedural block getter
*
* @return returns the procedural string block
*/
public String getProceduralBlockOne() {
return proceduralBlockOne;
}
/**
* Procedural block setter
*
* @param proceduralBlockOne is the procedural string block to be set
*/
public void setProceduralBlockOne(String proceduralBlockOne) {
this.proceduralBlockOne = proceduralBlockOne;
}
/**
* Procedural block getter
*
* @return returns the procedural string block
*/
public String getProceduralBlockTwo() {
return proceduralBlockTwo;
}
/**
* Procedural block setter
*
* @param proceduralBlockTwo is the procedural string block to be set
*/
public void setProceduralBlockTwo(String proceduralBlockTwo) {
this.proceduralBlockTwo = proceduralBlockTwo;
}
/**
* Procedural block getter
*
* @return returns the procedural string block
*/
public String getProceduralBlockThree() {
return proceduralBlockThree;
}
/**
* Procedural block setter
*
* @param proceduralBlockThree is the procedural string block to be set
*/
public void setProceduralBlockThree(String proceduralBlockThree) {
this.proceduralBlockThree = proceduralBlockThree;
}
/**
* Procedural block getter
*
* @return returns the procedural string block
*/
public String getProceduralBlockFour() {
return proceduralBlockFour;
}
/**
* Procedural block setter