Commit 8e97c163 by Joosep L

Initial

First commit of Android to TUT git
parents
Showing with 4852 additions and 0 deletions
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>
\ No newline at end of file
<component name="CopyrightManager">
<settings default="" />
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/thesis.iml" filepath="$PROJECT_DIR$/thesis.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
\ No newline at end of file
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "ee.ttu.thesis"
minSdkVersion 21
targetSdkVersion 22
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
android {
compileOptions.incremental = false
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
// android
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
//UI
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
compile 'com.google.android.gms:play-services:10.2.0'
compile 'jp.wasabeef:recyclerview-animators:2.2.6'
//rx java
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.0.9'
compile 'com.jakewharton.rxrelay2:rxrelay:2.0.0'
compile 'uk.co.chrisjenx:calligraphy:2.2.0'
// dependency injection
compile "com.google.dagger:dagger:2.8"
annotationProcessor "com.google.dagger:dagger-compiler:2.8"
provided 'javax.annotation:jsr250-api:1.0'
compile 'javax.inject:javax.inject:1'
compile 'com.jakewharton:butterknife:8.5.1'
// network
compile "com.amitshekhar.android:rx2-android-networking:1.0.0"
//helper
compile 'com.orhanobut:logger:1.15'
compile 'com.github.deano2390:MaterialShowcaseView:1.1.0'
compile ('com.github.worker8:tourguide:1.0.17-SNAPSHOT@aar'){
transitive=true
}
}
apply plugin: 'com.google.gms.google-services'
{
"project_info": {
"project_number": "61076858488",
"project_id": "firebase-thesis"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:61076858488:android:fabc7ea6905e8dc5",
"android_client_info": {
"package_name": "ee.ttu.thesis"
}
},
"oauth_client": [
{
"client_id": "61076858488-u2cg2n8lv0c8280hk7i8krkhu7s4v361.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "61076858488-ksjb18fbta0j2a7e1ac3cg26b93j2mko.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "ee.ttu.thesis",
"certificate_hash": "05de74f702a795d2258f058e26b0ba0c63a49c12"
}
}
],
"api_key": [
{
"current_key": "AIzaSyCCRw2qGiq3JMmE9TL8DtXsmTA9tLRwcZI"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 1
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/hajola/Android/Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
package ee.ttu.thesis;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("ee.ttu.thesis", appContext.getPackageName());
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ee.ttu.thesis">
<!-- To auto-complete the email text field in the login form with the user's emails -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<application
android:name=".ThesisApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:hardwareAccelerated="true"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".ui.login.LoginActivity"
android:screenOrientation="portrait"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.list.ListActivity"
android:screenOrientation="portrait">
</activity>
<activity
android:name=".ui.start.StartActivity"
android:screenOrientation="portrait">
</activity>
<activity
android:name=".ui.game.GameActivity"
android:screenOrientation="portrait">
</activity>
<activity
android:name=".ui.future.FutureGameActivity"
android:screenOrientation="portrait">
</activity>
<activity
android:name=".ui.past.HistoryActivity"
android:screenOrientation="portrait">
</activity>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyCVOu0A8kPjB3jfA09CzqoEwrZ-VAbJuyQ"/>
</application>
</manifest>
\ No newline at end of file
package ee.ttu.thesis;
import android.app.Application;
import com.androidnetworking.AndroidNetworking;
import com.androidnetworking.interceptors.HttpLoggingInterceptor;
import javax.inject.Inject;
import ee.ttu.thesis.data.DataManager;
import ee.ttu.thesis.di.component.ApplicationComponent;
import ee.ttu.thesis.di.component.DaggerApplicationComponent;
import ee.ttu.thesis.di.module.ApplicationModule;
import uk.co.chrisjenx.calligraphy.CalligraphyConfig;
/**
* Created by hajola on 9.05.17.
*/
public class ThesisApp extends Application {
@Inject
DataManager mDataManager;
private ApplicationComponent mApplicationComponent;
@Override
public void onCreate() {
super.onCreate();
mApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this)).build();
mApplicationComponent.inject(this);
AndroidNetworking.initialize(getApplicationContext());
if (BuildConfig.DEBUG) {
AndroidNetworking.enableLogging(HttpLoggingInterceptor.Level.BODY);
}
}
public ApplicationComponent getComponent() {
return mApplicationComponent;
}
public void setComponent(ApplicationComponent applicationComponent) {
mApplicationComponent = applicationComponent;
}
}
package ee.ttu.thesis.data;
import android.content.Context;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.CheckIn;
import ee.ttu.thesis.data.model.CheckInResponse;
import ee.ttu.thesis.data.model.Game;
import ee.ttu.thesis.data.model.GamesRequest;
import ee.ttu.thesis.data.model.Message;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.User;
import ee.ttu.thesis.data.model.UserGame;
import ee.ttu.thesis.data.network.ApiHelper;
import ee.ttu.thesis.data.prefs.PreferencesHelper;
import ee.ttu.thesis.di.ApplicationContext;
import io.reactivex.Observable;
/**
* Created by hajola on 9.05.17.
*/
@Singleton
public class AppDataManager implements DataManager {
private final Context mContext;
private final ApiHelper mApiHelper;
private final PreferencesHelper mPreferencesHelper;
@Inject
public AppDataManager(@ApplicationContext Context context,
PreferencesHelper preferencesHelper,
ApiHelper apiHelper) {
mContext = context;
mApiHelper = apiHelper;
mPreferencesHelper = preferencesHelper;
}
@Override
public Observable<List<UserGame>> getUserGames(GamesRequest.UserGamesRequest request) {
return mApiHelper.getUserGames(request);
}
@Override
public Observable<UserGame> addUserToAGame(GamesRequest.AddGameRequest request) {
return mApiHelper.addUserToAGame(request);
}
@Override
public Observable<List<Point>> getPoints(GamesRequest.PointsRequest request) {
return mApiHelper.getPoints(request);
}
@Override
public Observable<CheckInResponse> postCheckIn(CheckIn checkIn) {
return mApiHelper.postCheckIn(checkIn);
}
@Override
public Observable<String> startGame(String userGameId) {
return mApiHelper.startGame(userGameId);
}
@Override
public Observable<List<Game>> getGame(String gameCode) {
return mApiHelper.getGame(gameCode);
}
@Override
public Observable<User> makeUser(String userName, String deviceId) {
return mApiHelper.makeUser(userName, deviceId);
}
@Override
public Observable<String> postMessage(Message request) {
return mApiHelper.postMessage(request);
}
@Override
public Observable<String> postAnswer(Answer answer) {
return mApiHelper.postAnswer(answer);
}
@Override
public int getCurrentUserId() {
return mPreferencesHelper.getCurrentUserId();
}
@Override
public void setCurrentUserId(int userId) {
mPreferencesHelper.setCurrentUserId(userId);
}
}
package ee.ttu.thesis.data;
import ee.ttu.thesis.data.network.ApiHelper;
import ee.ttu.thesis.data.prefs.PreferencesHelper;
/**
* Created by hajola on 9.05.17.
*/
public interface DataManager extends ApiHelper, PreferencesHelper {
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by hajola on 18.05.17.
*/
public class Answer {
@Expose
@SerializedName("id")
private int id;
@Expose
@SerializedName("user_game")
private int user_game_id;
@Expose
@SerializedName("point")
private int point_id;
@Expose
@SerializedName("problem_type")
private ProblemType problem_type;
@Expose
@SerializedName("given_answer")
private String answer;
@Expose
@SerializedName("is_correct")
private boolean is_correct;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUser_game_id() {
return user_game_id;
}
public void setUser_game_id(int user_game_id) {
this.user_game_id = user_game_id;
}
public int getPoint_id() {
return point_id;
}
public void setPoint_id(int point_id) {
this.point_id = point_id;
}
public ProblemType getProblem_type() {
return problem_type;
}
public void setProblem_type(ProblemType problem_type) {
this.problem_type = problem_type;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
public boolean is_correct() {
return is_correct;
}
public void setIs_correct(boolean is_correct) {
this.is_correct = is_correct;
}
public Answer(int user_game_id, int point_id, ProblemType problem_type, String answer, boolean is_correct) {
this.user_game_id = user_game_id;
this.point_id = point_id;
this.problem_type = problem_type;
this.answer = answer;
this.is_correct = is_correct;
}
public Answer(String answer) {
this.answer = answer;
}
public Answer(int point_id, ProblemType problem_type, String answer, boolean is_correct) {
this.point_id = point_id;
this.problem_type = problem_type;
this.answer = answer;
this.is_correct = is_correct;
}
public Answer(int point_id, String answer, boolean is_correct) {
this.point_id = point_id;
this.answer = answer;
this.is_correct = is_correct;
}
public static boolean isAnswerCorrect(Point point, String answer){
for (Solution s : point.getSolutions()) {
if (s.getSolution().equals(answer)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return "vastus: " + answer;
}
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.Date;
import java.util.List;
/**
* Created by hajola on 19.05.17.
*/
public class Bound {
@Expose
@SerializedName("id")
private int id;
@Expose
@SerializedName("notification_text")
private String text;
@Expose
@SerializedName("violated_on")
private Date violated_on;
public Date getViolated_on() {
return violated_on;
}
public void setViolated_on(Date violated_on) {
this.violated_on = violated_on;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by hajola on 17.05.17.
*/
public class CheckIn {
public CheckIn(int user_game_id, double lat, double lon, int current_point_id, int latest_answer_id) {
this.user_game_id = user_game_id;
this.lat = lat;
this.lon = lon;
this.current_point_id = current_point_id;
this.latest_answer_id = latest_answer_id;
}
public CheckIn(int user_game_id, double lat, double lon, int current_point_id) {
this.user_game_id = user_game_id;
this.lat = lat;
this.lon = lon;
this.current_point_id = current_point_id;
}
@Expose
@SerializedName("user_game_id")
private int user_game_id;
@Expose
@SerializedName("lat")
private double lat;
@Expose
@SerializedName("lon")
private double lon;
@Expose
@SerializedName("current_point_id")
private int current_point_id;
@Expose
@SerializedName("latest_answer_id")
private int latest_answer_id;
public int getUser_game_id() {
return user_game_id;
}
public void setUser_game_id(int user_game_id) {
this.user_game_id = user_game_id;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
public int getCurrent_point_id() {
return current_point_id;
}
public void setCurrent_point_id(int current_point_id) {
this.current_point_id = current_point_id;
}
public int getLatest_answer_id() {
return latest_answer_id;
}
public void setLatest_answer_id(int latest_answer_id) {
this.latest_answer_id = latest_answer_id;
}
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;
import io.reactivex.Observable;
/**
* Created by hajola on 17.05.17.
*/
public class CheckInResponse {
@Expose
@SerializedName("bounds")
private List<Bound> bounds;
@Expose
@SerializedName("messages")
private List<Message> messages;
@Expose
@SerializedName("answer")
private Answer answer;
public List<Bound> getBounds() {
return bounds;
}
public void setBounds(List<Bound> bounds) {
this.bounds = bounds;
}
public List<Message> getMessages() {
return messages;
}
public void setMessages(List<Message> messages) {
this.messages = messages;
}
public Answer getAnswer() {
return answer;
}
public void setAnswer(Answer answer) {
this.answer = answer;
}
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created by hajola on 19.05.17.
*/
public class Conversation {
@Expose
@SerializedName("id")
private int id;
@Expose
@SerializedName("user_game")
private int user_game_id;
@Expose
@SerializedName("created_by")
private int user_id;
@Expose
@SerializedName("created_at")
private Date created_at;
@Expose
@SerializedName("messages")
private List<Message> messages;
public Conversation(int id, int user_game_id, int user_id) {
this.id = id;
this.user_game_id = user_game_id;
this.user_id = user_id;
}
public int getId() {
return id;
}
public void addMessage(Message message){
if(messages == null){
messages = new ArrayList<>();
messages.add(message);
}
}
public void setId(int id) {
this.id = id;
}
public int getUser_game_id() {
return user_game_id;
}
public void setUser_game_id(int user_game_id) {
this.user_game_id = user_game_id;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public Date getCreated_at() {
return created_at;
}
public void setCreated_at(Date created_at) {
this.created_at = created_at;
}
public List<Message> getMessages() {
return messages;
}
public void setMessages(List<Message> messages) {
this.messages = messages;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Conversation that = (Conversation) o;
if (id == that.id) return true;
return false;
}
@Override
public int hashCode() {
int result = id;
return result;
}
}
package ee.ttu.thesis.data.model;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.View;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
/**
* Created by hajola on 23.03.17.
*/
public class Game implements Parcelable {
private int userGameId;
public int getUserGameId() {
return userGameId;
}
public void setUserGameId(int userGameId) {
this.userGameId = userGameId;
}
@Expose
@SerializedName("id")
private int id;
@Expose
@SerializedName("title")
private String title;
@SerializedName("game_code")
private String gameCode;
@Expose
@SerializedName("description")
private String description;
@Expose
@SerializedName("location_name")
private String locationName;
@Expose
@SerializedName("max_duration")
private int maxDuration;
@Expose
@SerializedName("start_time")
private Date startTime;
@Expose
@SerializedName("end_time")
private Date endTime;
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getGameCode() {
return gameCode;
}
public void setGameCode(String gameCode) {
this.gameCode = gameCode;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLocationName() {
return locationName;
}
public void setLocationName(String locationName) {
this.locationName = locationName;
}
public int getMaxDuration() {
return maxDuration;
}
public void setMaxDuration(int maxDuration) {
this.maxDuration = maxDuration;
}
@Override
public String toString() {
String s = "";
s += "Desciription: " + description;
s += "\ntitle: " + title;
s += "\ngameCode: " + gameCode;
s += "\nstartTime: " + startTime.toString();
return s;
}
public Game() {
}
public boolean isUpcoming(){
Date now = new Date();
Date start = getStartTime();
Date end = getEndTime();
if (start.before(now) && end.after(now)) {
return true;
} else if (start.after(now)) {
return false;
} else {
return false;
}
}
public boolean isCurrent(){
Date now = new Date();
Date start = getStartTime();
Date end = getEndTime();
if (start.before(now) && end.after(now)) {
return true;
} else if (start.after(now)) {
return false;
} else {
return false;
}
}
public boolean isPast(){
Date now = new Date();
Date start = getStartTime();
Date end = getEndTime();
if (start.before(now) && end.after(now)) {
return false;
} else if (start.after(now)) {
return false;
} else {
return true;
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.userGameId);
dest.writeInt(this.id);
dest.writeString(this.title);
dest.writeString(this.gameCode);
dest.writeString(this.description);
dest.writeString(this.locationName);
dest.writeInt(this.maxDuration);
dest.writeLong(this.startTime != null ? this.startTime.getTime() : -1);
dest.writeLong(this.endTime != null ? this.endTime.getTime() : -1);
}
protected Game(Parcel in) {
this.userGameId = in.readInt();
this.id = in.readInt();
this.title = in.readString();
this.gameCode = in.readString();
this.description = in.readString();
this.locationName = in.readString();
this.maxDuration = in.readInt();
long tmpStartTime = in.readLong();
this.startTime = tmpStartTime == -1 ? null : new Date(tmpStartTime);
long tmpEndTime = in.readLong();
this.endTime = tmpEndTime == -1 ? null : new Date(tmpEndTime);
}
public static final Creator<Game> CREATOR = new Creator<Game>() {
@Override
public Game createFromParcel(Parcel source) {
return new Game(source);
}
@Override
public Game[] newArray(int size) {
return new Game[size];
}
};
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by hajola on 9.05.17.
*/
public class GamesRequest {
private GamesRequest(){
}
public static class UserGamesRequest {
@Expose
@SerializedName("user")
private int user_id;
public UserGamesRequest(int user_id) {
this.user_id = user_id;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
}
public static class PointsRequest {
@Expose
@SerializedName("game")
private int game_id;
public PointsRequest(int game_id) {
this.game_id = game_id;
}
public int getGame_id() {
return game_id;
}
public void setGame_id(int game_id) {
this.game_id = game_id;
}
}
public static class AddGameRequest {
@Expose
@SerializedName("user")
private int user_id;
@Expose
@SerializedName("game_code")
private String game_code;
public AddGameRequest(int user_id, String game_code) {
this.user_id = user_id;
this.game_code = game_code;
}
public String getGame_code() {
return game_code;
}
public void setGame_code(String game_code) {
this.game_code = game_code;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
}
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.Date;
/**
* Created by hajola on 19.05.17.
*/
public class Message {
@Expose
@SerializedName("id")
private int id;
@Expose
@SerializedName("user")
private int user_id;
@Expose
@SerializedName("content")
private String content;
@Expose
@SerializedName("user_game")
private int user_game_id;
public Message(int user_id, String content, int user_game_id) {
this.user_id = user_id;
this.content = content;
this.user_game_id = user_game_id;
}
public int getUser_game_id() {
return user_game_id;
}
public void setUser_game_id(int user_game_id) {
this.user_game_id = user_game_id;
}
public int getUser_id() {
return user_id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
package ee.ttu.thesis.data.model;
import java.util.ArrayList;
import java.util.Date;
import ee.ttu.thesis.ui.game.messages.NotificationAdapter;
/**
* Created by hajola on 19.04.17.
*/
public class Notification {
private int type;
private String text;
private Date time;
public Notification(int type, String text, Date time) {
this.type = type;
this.text = text;
this.time = time;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
// public static ArrayList<Notification> getNotifications() {
// ArrayList<Notification> notifications = new ArrayList<>();
//// notification = new Notification(NotificationAdapter.GAME_UPDATE, "Second point completed!");
//// notifications.add(notification);
// Notification notification = new Notification(NotificationAdapter.HEADER, "You messaged the coordinator");
// notifications.add(notification);
// notification = new Notification(NotificationAdapter.SENT_MESSAGE, "Could we get another hint?");
// notifications.add(notification);
// notification = new Notification(NotificationAdapter.RECEIVED_MESSAGE, "Sure! The same thing that go to the beach to enjoy makes it tick.");
// notifications.add(notification);
// notification = new Notification(NotificationAdapter.SENT_MESSAGE, "Thanks!");
// notifications.add(notification);
// notification = new Notification(NotificationAdapter.REPLY, "");
// notifications.add(notification);
// notification = new Notification(NotificationAdapter.BOUNDS, "You are leaving the game area. There are no points here.");
// notifications.add(notification);
// notification = new Notification(NotificationAdapter.GAME_UPDATE, "Game start");
// notifications.add(notification);
//
//
// return notifications;
// }
}
package ee.ttu.thesis.data.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
import ee.ttu.thesis.utils.Constants;
/**
* Created by hajola on 23.03.17.
*/
public class Point implements Parcelable {
@Expose
@SerializedName("id")
private int id;
@Expose
@SerializedName("game")
private int game_id;
@Expose
@SerializedName("lat")
private double lat;
@Expose
@SerializedName("point_type")
private List<PointType> pointTypes;
@Expose
@SerializedName("lon")
private double lon;
@Expose
@SerializedName("title")
private String title;
@Expose
@SerializedName("question")
private String question;
@Expose
@SerializedName("time_penalty")
private int timePenalty;
@Expose
@SerializedName("hint")
private String hint;
@Expose
@SerializedName("problem_description")
private String problemDescription;
@Expose
@SerializedName("solutions")
private List<Solution> solutions;
@Expose
@SerializedName("description")
private String description;
@Expose
@SerializedName("problem_type")
private ProblemType problemType;
@Expose
@SerializedName("order")
private int order;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getGame_id() {
return game_id;
}
public void setGame_id(int game_id) {
this.game_id = game_id;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getHint() {
return hint;
}
public void setHint(String hint) {
this.hint = hint;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public List<PointType> getPointTypes() {
return pointTypes;
}
public void setPointTypes(List<PointType> pointTypes) {
this.pointTypes = pointTypes;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public int getTimePenalty() {
return timePenalty;
}
public void setTimePenalty(int timePenalty) {
this.timePenalty = timePenalty;
}
public String getProblemDescription() {
return problemDescription;
}
public void setProblemDescription(String problemDescription) {
this.problemDescription = problemDescription;
}
public List<Solution> getSolutions() {
return solutions;
}
public void setSolutions(List<Solution> solutions) {
this.solutions = solutions;
}
public ProblemType getProblemType() {
return problemType;
}
public void setProblemType(ProblemType problemType) {
this.problemType = problemType;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id);
dest.writeInt(this.game_id);
dest.writeDouble(this.lat);
dest.writeList(this.pointTypes);
dest.writeDouble(this.lon);
dest.writeString(this.title);
dest.writeString(this.question);
dest.writeInt(this.timePenalty);
dest.writeString(this.hint);
dest.writeString(this.problemDescription);
dest.writeList(this.solutions);
dest.writeString(this.description);
dest.writeParcelable(this.problemType, flags);
dest.writeInt(this.order);
}
public Point() {
}
protected Point(Parcel in) {
this.id = in.readInt();
this.game_id = in.readInt();
this.lat = in.readDouble();
this.pointTypes = new ArrayList<PointType>();
in.readList(this.pointTypes, PointType.class.getClassLoader());
this.lon = in.readDouble();
this.title = in.readString();
this.question = in.readString();
this.timePenalty = in.readInt();
this.hint = in.readString();
this.problemDescription = in.readString();
this.solutions = new ArrayList<Solution>();
in.readList(this.solutions, Solution.class.getClassLoader());
this.description = in.readString();
this.problemType = in.readParcelable(ProblemType.class.getClassLoader());
this.order = in.readInt();
}
public static final Parcelable.Creator<Point> CREATOR = new Parcelable.Creator<Point>() {
@Override
public Point createFromParcel(Parcel source) {
return new Point(source);
}
@Override
public Point[] newArray(int size) {
return new Point[size];
}
};
@Override
public String toString() {
return super.toString();
}
}
package ee.ttu.thesis.data.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.orhanobut.logger.Logger;
import java.io.Console;
/**
* Created by hajola on 17.05.17.
*/
public class PointType implements Parcelable {
public static final String MAP = "MAP";
public static final String DISTANCE = "DST";
public static final String HINT = "HNT";
public static final String COMPASS = "CMP";
@Expose
@SerializedName("title")
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.title);
}
public PointType() {
}
public PointType(String title) {
this.title = title;
}
@Override
public boolean equals(Object obj) {
return obj.equals(title);
}
protected PointType(Parcel in) {
this.title = in.readString();
}
public static final Parcelable.Creator<PointType> CREATOR = new Parcelable.Creator<PointType>() {
@Override
public PointType createFromParcel(Parcel source) {
return new PointType(source);
}
@Override
public PointType[] newArray(int size) {
return new PointType[size];
}
};
}
package ee.ttu.thesis.data.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by hajola on 17.05.17.
*/
public class ProblemType implements Parcelable {
public static final String NFC = "NFC";
public static final String QUIZ = "QUZ";
public static final String QR = "QRC";
public static final String CAMERA = "CAM";
public static final String LOCATION = "LOC";
@Expose
@SerializedName("id")
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Expose
@SerializedName("title")
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ProblemType() {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id);
dest.writeString(this.title);
}
protected ProblemType(Parcel in) {
this.id = in.readInt();
this.title = in.readString();
}
public static final Creator<ProblemType> CREATOR = new Creator<ProblemType>() {
@Override
public ProblemType createFromParcel(Parcel source) {
return new ProblemType(source);
}
@Override
public ProblemType[] newArray(int size) {
return new ProblemType[size];
}
};
}
package ee.ttu.thesis.data.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by hajola on 17.05.17.
*/
public class Solution implements Parcelable {
@Expose
@SerializedName("id")
private int id;
@Expose
@SerializedName("solution")
private String solution;
@Expose
@SerializedName("is_correct_answer")
private boolean isCorrectAnswer;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSolution() {
return solution;
}
public void setSolution(String solution) {
this.solution = solution;
}
public boolean isCorrectAnswer() {
return isCorrectAnswer;
}
public void setCorrectAnswer(boolean correctAnswer) {
isCorrectAnswer = correctAnswer;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id);
dest.writeString(this.solution);
dest.writeByte(this.isCorrectAnswer ? (byte) 1 : (byte) 0);
}
public Solution() {
}
protected Solution(Parcel in) {
this.id = in.readInt();
this.solution = in.readString();
this.isCorrectAnswer = in.readByte() != 0;
}
public static final Parcelable.Creator<Solution> CREATOR = new Parcelable.Creator<Solution>() {
@Override
public Solution createFromParcel(Parcel source) {
return new Solution(source);
}
@Override
public Solution[] newArray(int size) {
return new Solution[size];
}
};
}
package ee.ttu.thesis.data.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by hajola on 18.05.17.
*/
public class User implements Parcelable {
@Expose
@SerializedName("user_id")
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id);
}
public User() {
}
protected User(Parcel in) {
this.id = in.readInt();
}
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
}
package ee.ttu.thesis.data.model;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by hajola on 9.05.17.
*/
public class UserGame {
@Expose
@SerializedName("user_game_id")
private int UserGameId;
@Expose
@SerializedName("game")
private Game game;
public int getUserGameId() {
return UserGameId;
}
public void setUserGameId(int userGameId) {
UserGameId = userGameId;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
@Override
public String toString() {
return "id: " + UserGameId + " game: " + game.toString();
}
}
package ee.ttu.thesis.data.network;
/**
* Created by hajola on 9.05.17.
*/
public final class ApiEndPoint {
public static final String BASE_URL = "http://128.199.63.125/api";
public static final String ENDPOINT_GET_GAMES = BASE_URL
+ "/user/games";
public static final String ENDPOINT_ADD_USER_GAME = BASE_URL
+ "/game/adduser";
public static final String ENDPOINT_GET_POINTS = BASE_URL
+ "/game/points";
public static final String ENDPOINT_POST_CHECK_IN = BASE_URL
+ "/game/checkin";
public static final String ENDPOINT_START_GAME = BASE_URL
+ "/game/start";
public static final String ENDPOINT_GET_GAME = BASE_URL
+ "/games";
public static final String ENDPOINT_MAKE_USER = BASE_URL
+ "/user/add";
public static final String ENDPOINT_POST_MESSAGE = BASE_URL
+ "/game/message";
public static final String ENDPOINT_POST_ANSWER = BASE_URL
+ "/game/addanswer";
private ApiEndPoint() {
// This class is not publicly instantiable
}
}
package ee.ttu.thesis.data.network;
import java.util.List;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.CheckIn;
import ee.ttu.thesis.data.model.CheckInResponse;
import ee.ttu.thesis.data.model.Game;
import ee.ttu.thesis.data.model.GamesRequest;
import ee.ttu.thesis.data.model.Message;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.User;
import ee.ttu.thesis.data.model.UserGame;
import io.reactivex.Observable;
import javax.inject.Singleton;
/**
* Created by hajola on 9.05.17.
*/
@Singleton
public interface ApiHelper {
Observable<List<UserGame>> getUserGames(GamesRequest.UserGamesRequest request);
Observable<UserGame> addUserToAGame(GamesRequest.AddGameRequest request);
Observable<List<Point>> getPoints(GamesRequest.PointsRequest request);
Observable<CheckInResponse> postCheckIn(CheckIn checkIn);
Observable<String> startGame(String userGameId);
Observable<List<Game>> getGame(String gameCode);
Observable<User> makeUser(String userName, String deviceId);
Observable<String> postMessage(Message request);
Observable<String> postAnswer(Answer answer);
}
package ee.ttu.thesis.data.network;
import com.rx2androidnetworking.Rx2AndroidNetworking;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.CheckIn;
import ee.ttu.thesis.data.model.CheckInResponse;
import ee.ttu.thesis.data.model.Game;
import ee.ttu.thesis.data.model.GamesRequest;
import ee.ttu.thesis.data.model.Message;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.User;
import ee.ttu.thesis.data.model.UserGame;
import io.reactivex.Observable;
/**
* Created by hajola on 9.05.17.
*/
@Singleton
public class AppApiHelper implements ApiHelper {
@Inject
public AppApiHelper() {
}
@Override
public Observable<List<UserGame>> getUserGames(GamesRequest.UserGamesRequest request) {
return Rx2AndroidNetworking.get(ApiEndPoint.ENDPOINT_GET_GAMES)
.addQueryParameter("user", Integer.toString(request.getUser_id()))
.build()
.getObjectListObservable(UserGame.class);
}
@Override
public Observable<UserGame> addUserToAGame(GamesRequest.AddGameRequest request) {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_ADD_USER_GAME)
.addBodyParameter("game_code", request.getGame_code())
.addBodyParameter("user_id", Integer.toString(request.getUser_id()))
.build()
.getObjectObservable(UserGame.class);
}
@Override
public Observable<List<Point>> getPoints(GamesRequest.PointsRequest request) {
return Rx2AndroidNetworking.get(ApiEndPoint.ENDPOINT_GET_POINTS)
.addQueryParameter("game_id", Integer.toString(request.getGame_id()))
.build()
.getObjectListObservable(Point.class);
}
@Override
public Observable<CheckInResponse> postCheckIn(CheckIn request) {
if(request.getLatest_answer_id() != 0 ) {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_POST_CHECK_IN)
.addBodyParameter("user_game_id", Integer.toString(request.getUser_game_id()))
.addBodyParameter("lat", Double.toString(request.getLat()))
.addBodyParameter("lon", Double.toString(request.getLon()))
.addBodyParameter("current_point_id", Integer.toString(request.getCurrent_point_id()))
.addBodyParameter("latest_answer_id", Integer.toString(request.getLatest_answer_id()))
.build()
.getObjectObservable(CheckInResponse.class);
} else{
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_POST_CHECK_IN)
.addBodyParameter("user_game_id", Integer.toString(request.getUser_game_id()))
.addBodyParameter("lat", Double.toString(request.getLat()))
.addBodyParameter("lon", Double.toString(request.getLon()))
.addBodyParameter("current_point_id", Integer.toString(request.getCurrent_point_id()))
.build()
.getObjectObservable(CheckInResponse.class);
}
}
@Override
public Observable<String> startGame(String userGameId) {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_START_GAME)
.addBodyParameter("user_game_id", userGameId)
.build()
.getObjectObservable(String.class);
}
@Override
public Observable<List<Game>> getGame(String gameCode) {
return Rx2AndroidNetworking.get(ApiEndPoint.ENDPOINT_GET_GAME)
.addQueryParameter("game_code", gameCode)
.build()
.getObjectListObservable(Game.class);
}
@Override
public Observable<User> makeUser(String userName, String deviceId) {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_MAKE_USER)
.addBodyParameter("username", userName)
.addBodyParameter("device_id", deviceId)
.build()
.getObjectObservable(User.class);
}
@Override
public Observable<String> postMessage(Message request) {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_POST_MESSAGE)
.addBodyParameter("user_game_id", Integer.toString(request.getUser_game_id()))
.addBodyParameter("user_id", Integer.toString(request.getUser_id()))
.addBodyParameter("content", request.getContent())
.build()
.getObjectObservable(String.class);
}
@Override
public Observable<String> postAnswer(Answer answer) {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_POST_ANSWER)
.addBodyParameter("user_game_id", Integer.toString(answer.getUser_game_id()))
.addBodyParameter("point_id", Integer.toString(answer.getPoint_id()))
.addBodyParameter("problem_type_id", Integer.toString(answer.getProblem_type().getId()))
.addBodyParameter("given_answer", answer.getAnswer())
.addBodyParameter("is_correct", answer.is_correct() ? "1" : "0")
.build()
.getObjectObservable(String.class);
}
}
package ee.ttu.thesis.data.prefs;
import android.content.Context;
import android.content.SharedPreferences;
import javax.inject.Inject;
import javax.inject.Singleton;
import ee.ttu.thesis.di.ApplicationContext;
import ee.ttu.thesis.di.PreferenceInfo;
/**
* Created by hajola on 18.05.17.
*/
@Singleton
public class AppPreferencesHelper implements PreferencesHelper {
private static final String PREF_KEY_CURRENT_USER_ID = "PREFS_KEY_CURRENT_USER_ID";
private final SharedPreferences mPrefs;
@Inject
public AppPreferencesHelper(@ApplicationContext Context context,
@PreferenceInfo String prefFileName) {
mPrefs = context.getSharedPreferences(prefFileName, Context.MODE_PRIVATE);
}
@Override
public int getCurrentUserId() {
int userId = mPrefs.getInt(PREF_KEY_CURRENT_USER_ID, 0);
if(userId == 0)
return 1;
return userId;
}
@Override
public void setCurrentUserId(int userId) {
int id = userId;
mPrefs.edit().putInt(PREF_KEY_CURRENT_USER_ID, id).apply();
}
}
package ee.ttu.thesis.data.prefs;
/**
* Created by hajola on 18.05.17.
*/
public interface PreferencesHelper {
int getCurrentUserId();
void setCurrentUserId(int userId);
}
package ee.ttu.thesis.di;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
/**
* Created by hajola on 9.05.17.
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityContext {
}
package ee.ttu.thesis.di;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
/**
* Created by hajola on 9.05.17.
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationContext {
}
package ee.ttu.thesis.di;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;
/**
* Created by hajola on 9.05.17.
*/
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
package ee.ttu.thesis.di;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
/**
* Created by hajola on 18.05.17.
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface PreferenceInfo {
}
package ee.ttu.thesis.di.component;
import dagger.Component;
import ee.ttu.thesis.ui.game.GameActivity;
import ee.ttu.thesis.ui.list.ListActivity;
import ee.ttu.thesis.ui.login.LoginActivity;
import ee.ttu.thesis.ui.start.StartActivity;
import ee.ttu.thesis.di.PerActivity;
import ee.ttu.thesis.di.module.ActivityModule;
/**
* Created by hajola on 9.05.17.
*/
@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
void inject(ListActivity activity);
void inject(GameActivity activity);
void inject(StartActivity activity);
void inject(LoginActivity activity);
}
package ee.ttu.thesis.di.component;
import android.app.Application;
import android.content.Context;
import javax.inject.Singleton;
import dagger.Component;
import ee.ttu.thesis.ThesisApp;
import ee.ttu.thesis.data.DataManager;
import ee.ttu.thesis.di.ApplicationContext;
import ee.ttu.thesis.di.module.ApplicationModule;
/**
* Created by hajola on 9.05.17.
*/
@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(ThesisApp app);
@ApplicationContext
Context context();
Application application();
DataManager getDataManager();
}
\ No newline at end of file
package ee.ttu.thesis.di.module;
import android.app.Activity;
import android.content.Context;
import dagger.Module;
import dagger.Provides;
import ee.ttu.thesis.di.ActivityContext;
import ee.ttu.thesis.di.PerActivity;
import ee.ttu.thesis.ui.game.GamePresenter;
import ee.ttu.thesis.ui.game.GameTreasureHuntPresenter;
import ee.ttu.thesis.ui.list.ListPresenter;
import ee.ttu.thesis.ui.list.ListTreasureHuntPresenter;
import ee.ttu.thesis.ui.login.LoginPresenter;
import ee.ttu.thesis.ui.login.LoginTreasureHuntPresenter;
import ee.ttu.thesis.ui.start.StartPresenter;
import ee.ttu.thesis.ui.start.StartTreasureHuntPresenter;
import ee.ttu.thesis.utils.AppSchedulerProvider;
import ee.ttu.thesis.utils.SchedulerProvider;
import ee.ttu.thesis.ui.game.GameView;
import ee.ttu.thesis.ui.list.ListView;
import ee.ttu.thesis.ui.login.LoginView;
import ee.ttu.thesis.ui.start.StartView;
import io.reactivex.disposables.CompositeDisposable;
/**
* Created by hajola on 9.05.17.
*/
@Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
this.mActivity = activity;
}
@Provides
@ActivityContext
Context provideContext() {
return mActivity;
}
@Provides
Activity provideActivity() {
return mActivity;
}
@Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
@Provides
SchedulerProvider provideSchedulerProvider() {
return new AppSchedulerProvider();
}
@Provides
@PerActivity
ListTreasureHuntPresenter<ListView> provideMainPresenter(ListPresenter<ListView>
presenter) {
return presenter;
}
@Provides
@PerActivity
GameTreasureHuntPresenter<GameView> provideGamePresenter(GamePresenter<GameView>
presenter) {
return presenter;
}
@Provides
@PerActivity
StartTreasureHuntPresenter<StartView> providesStartPresenter(StartPresenter<StartView>
presenter) {
return presenter;
}
@Provides
@PerActivity
LoginTreasureHuntPresenter<LoginView> providesLoginPresenter(LoginPresenter<LoginView>
presenter) {
return presenter;
}
}
package ee.ttu.thesis.di.module;
import android.app.Application;
import android.content.Context;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import ee.ttu.thesis.data.AppDataManager;
import ee.ttu.thesis.data.DataManager;
import ee.ttu.thesis.data.network.ApiHelper;
import ee.ttu.thesis.data.network.AppApiHelper;
import ee.ttu.thesis.data.prefs.AppPreferencesHelper;
import ee.ttu.thesis.data.prefs.PreferencesHelper;
import ee.ttu.thesis.di.ApplicationContext;
import ee.ttu.thesis.di.PreferenceInfo;
/**
* Created by hajola on 9.05.17.
*/
@Module
public class ApplicationModule {
private final Application mApplication;
public ApplicationModule(Application application) {
mApplication = application;
}
@Provides
@ApplicationContext
Context provideContext() {
return mApplication;
}
@Provides
Application provideApplication() {
return mApplication;
}
@Provides
@Singleton
DataManager provideDataManager(AppDataManager appDataManager) {
return appDataManager;
}
@Provides
@Singleton
ApiHelper provideApiHelper(AppApiHelper appApiHelper) {
return appApiHelper;
}
@Provides
@Singleton
PreferencesHelper providePreferencesHelper(AppPreferencesHelper appPreferencesHelper) {
return appPreferencesHelper;
}
@Provides
@PreferenceInfo
String providePreferenceName() {
return "thesis";
}
}
package ee.ttu.thesis.ui.base;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import com.orhanobut.logger.Logger;
import ee.ttu.thesis.R;
import ee.ttu.thesis.ThesisApp;
import ee.ttu.thesis.di.component.ActivityComponent;
import ee.ttu.thesis.di.component.DaggerActivityComponent;
import ee.ttu.thesis.di.module.ActivityModule;
import ee.ttu.thesis.utils.CommonUtils;
import uk.co.chrisjenx.calligraphy.CalligraphyConfig;
import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper;
/**
* Created by hajola on 23.04.17.
*/
public abstract class BaseActivity extends AppCompatActivity implements TreasureHuntView {
private ProgressDialog mProgressDialog;
private ActivityComponent mActivityComponent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityComponent = DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.applicationComponent(((ThesisApp) getApplication()).getComponent())
.build();
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/lato_regular.ttf")
.setFontAttrId(R.attr.fontPath)
.build()
);
Logger.init();
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
public ActivityComponent getActivityComponent() {
return mActivityComponent;
}
@Override
public void showLoading() {
hideLoading();
mProgressDialog = CommonUtils.showLoadingDialog(this);
}
@Override
public void hideLoading() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.cancel();
}
}
public void hideKeyboard() {
View view = this.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
}
\ No newline at end of file
package ee.ttu.thesis.ui.base;
/**
* Created by hajola on 10.05.17.
*/
import com.androidnetworking.common.ANConstants;
import com.androidnetworking.error.ANError;
import javax.inject.Inject;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.DataManager;
import ee.ttu.thesis.utils.Constants;
import ee.ttu.thesis.utils.SchedulerProvider;
import io.reactivex.disposables.CompositeDisposable;
/**
* Base class that implements the Presenter interface and provides a base implementation for
* onAttach() and onDetach(). It also handles keeping a reference to the mvpView that
* can be accessed from the children classes by calling getMvpView().
*/
public class BasePresenter<V extends TreasureHuntView> implements TreauseHuntPresenter<V> {
private final DataManager mDataManager;
private final SchedulerProvider mSchedulerProvider;
private final CompositeDisposable mCompositeDisposable;
private V mThesisView;
@Inject
public BasePresenter(DataManager dataManager,
SchedulerProvider schedulerProvider,
CompositeDisposable compositeDisposable) {
this.mDataManager = dataManager;
this.mSchedulerProvider = schedulerProvider;
this.mCompositeDisposable = compositeDisposable;
}
@Override
public void onAttach(V mvpView) {
mThesisView = mvpView;
}
@Override
public void onDetach() {
mCompositeDisposable.dispose();
mThesisView = null;
}
public boolean isViewAttached() {
return mThesisView != null;
}
public V getmThesisView() {
return mThesisView;
}
public void checkViewAttached() {
if (!isViewAttached()) throw new MvpViewNotAttachedException();
}
public DataManager getDataManager() {
return mDataManager;
}
public SchedulerProvider getSchedulerProvider() {
return mSchedulerProvider;
}
public CompositeDisposable getCompositeDisposable() {
return mCompositeDisposable;
}
@Override
public void handleApiError(ANError error) {
if (error == null || error.getErrorBody() == null) {
getmThesisView().onError(R.string.api_default_error);
return;
}
if (error.getErrorCode() == Constants.API_STATUS_CODE_LOCAL_ERROR
&& error.getErrorDetail().equals(ANConstants.CONNECTION_ERROR)) {
getmThesisView().onError(R.string.connection_error);
return;
}
if (error.getErrorCode() == Constants.API_STATUS_CODE_LOCAL_ERROR
&& error.getErrorDetail().equals(ANConstants.REQUEST_CANCELLED_ERROR)) {
getmThesisView().onError(R.string.api_retry_error);
return;
}
// final GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation();
// final Gson gson = builder.create();
//
// try {
// ApiError apiError = gson.fromJson(error.getErrorBody(), ApiError.class);
//
// if (apiError == null || apiError.getMessage() == null) {
// getMvpView().onError(R.string.api_default_error);
// return;
// }
//
// switch (error.getErrorCode()) {
// case HttpsURLConnection.HTTP_UNAUTHORIZED:
// case HttpsURLConnection.HTTP_FORBIDDEN:
// setUserAsLoggedOut();
// getMvpView().openActivityOnTokenExpire();
// case HttpsURLConnection.HTTP_INTERNAL_ERROR:
// case HttpsURLConnection.HTTP_NOT_FOUND:
// default:
// getMvpView().onError(apiError.getMessage());
// }
// } catch (JsonSyntaxException | NullPointerException e) {
// Logger.e("handleApiError", e);
// getMvpView().onError(R.string.api_default_error);
// }
}
public static class MvpViewNotAttachedException extends RuntimeException {
public MvpViewNotAttachedException() {
super("Please call Presenter.onAttach(MvpView) before" +
" requesting data to the Presenter");
}
}
}
package ee.ttu.thesis.ui.base;
/**
* Created by hajola on 9.05.17.
*/
import android.support.annotation.StringRes;
/**
* Base interface that any class that wants to act as a View in the MVP (Model View Presenter)
* pattern must implement. Generally this interface will be extended by a more specific interface
* that then usually will be implemented by an Activity or Fragment.
*/
public interface TreasureHuntView {
void showLoading();
void hideLoading();
void openActivityOnTokenExpire();
void onError(@StringRes int resId);
void onError(String message);
boolean isNetworkConnected();
void hideKeyboard();
}
\ No newline at end of file
package ee.ttu.thesis.ui.base;
/**
* Created by hajola on 10.05.17.
*/
import com.androidnetworking.error.ANError;
import ee.ttu.thesis.ui.base.TreasureHuntView;
/**
* Every presenter in the app must either implement this interface or extend BasePresenter
* indicating the MvpView type that wants to be attached with.
*/
public interface TreauseHuntPresenter<V extends TreasureHuntView> {
void onAttach(V mvpView);
void onDetach();
void handleApiError(ANError error);
}
package ee.ttu.thesis.ui.future;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.view.View;
import android.widget.TextView;
import java.util.Calendar;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import ee.ttu.thesis.R;
import ee.ttu.thesis.ui.base.BaseActivity;
import ee.ttu.thesis.data.model.Game;
import static ee.ttu.thesis.ui.game.GameActivity.GAME_KEY;
/**
* Created by hajola on 28.04.17.
*/
public class FutureGameActivity extends BaseActivity {
@BindView(R.id.layout_time_to_game_days_TextView)
TextView mDays;
@BindView(R.id.layout_time_to_game_hours_TextView)
TextView mHours;
@BindView(R.id.layout_time_to_game_minutes_TextView)
TextView mMinutes;
@BindView(R.id.layout_time_to_game_seconds_TextView)
TextView mSeconds;
@BindView(R.id.activity_future_game_title)
TextView mTitle;
@BindView(R.id.activity_future_game_description)
TextView mDescription;
Game mGame;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_future_game);
ButterKnife.bind(this);
mGame = getIntent().getParcelableExtra(GAME_KEY);
mTitle.setText(mGame.getTitle());
mDescription.setText(mGame.getDescription());
Calendar cal = Calendar.getInstance(); // creates calendar
cal.setTime(mGame.getStartTime()); // sets calendar time/date
cal.getTime(); // returns new date object, one hour in the future
long difference = cal.getTimeInMillis() - Calendar.getInstance().getTimeInMillis();
new CountDownTimer(difference, 1000) {
public void onTick(long millisUntilFinished) {
int seconds = (int) (millisUntilFinished / 1000);
int minutes = seconds / 60;
int hours = minutes / 60;
int days = hours / 24;
mDays.setText(String.format("%02d", days));
hours -= (days*24);
mHours.setText(String.format("%02d", hours));
minutes -= (days*24*60+hours*60);
mMinutes.setText(String.format("%02d", minutes));
seconds -= (days*24*60*60+hours*60*60 + minutes*60);
mSeconds.setText(String.format("%02d", seconds));
}
public void onFinish() {
// mTextField.setText("done!");
}
}.start();
}
@OnClick(R.id.activity_future_game_go_back_textView)
public void onBackClicked(View v){
finish();
}
@Override
public void showLoading() {
}
@Override
public void hideLoading() {
}
@Override
public void openActivityOnTokenExpire() {
}
@Override
public void onError(@StringRes int resId) {
}
@Override
public void onError(String message) {
}
@Override
public boolean isNetworkConnected() {
return false;
}
@Override
public void hideKeyboard() {
}
}
package ee.ttu.thesis.ui.game;
import java.util.List;
import javax.inject.Inject;
import ee.ttu.thesis.data.DataManager;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.CheckIn;
import ee.ttu.thesis.data.model.CheckInResponse;
import ee.ttu.thesis.data.model.GamesRequest;
import ee.ttu.thesis.data.model.Message;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.ui.base.BasePresenter;
import ee.ttu.thesis.utils.SchedulerProvider;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
/**
* Created by hajola on 17.05.17.
*/
public class GamePresenter<V extends GameView> extends BasePresenter<V> implements GameTreasureHuntPresenter<V> {
@Inject
public GamePresenter(DataManager dataManager, SchedulerProvider schedulerProvider, CompositeDisposable compositeDisposable) {
super(dataManager, schedulerProvider, compositeDisposable);
}
@Override
public void onViewInitialized(GamesRequest.PointsRequest request) {
getmThesisView().showLoading();
getCompositeDisposable().add(getDataManager()
.getPoints(request)
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(new Consumer<List<Point>>() {
@Override
public void accept(@NonNull List<Point> points) throws Exception {;
if (!isViewAttached()) {
getmThesisView().hideLoading();
return;
}
if (points != null) {
getmThesisView().loadPoints(points);
}
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
getmThesisView().hideLoading();
getmThesisView().onError(throwable.getMessage());
}
}));
}
@Override
public void postCheckIn(CheckIn checkIn) {
getCompositeDisposable().add(getDataManager()
.postCheckIn(checkIn)
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(new Consumer<CheckInResponse>() {
@Override
public void accept(@NonNull CheckInResponse checkInResponse) throws Exception {
if (!isViewAttached()) {
return;
}
getmThesisView().checkInResponse(checkInResponse);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
getmThesisView().onError(throwable.getMessage());
}
}));
}
@Override
public void postMessage(Message request) {
getmThesisView().showLoading();
getCompositeDisposable().add(getDataManager()
.postMessage(request)
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
getmThesisView().hideLoading();
if (!isViewAttached()) {
return;
}
getmThesisView().messagePosted();
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
getmThesisView().onError(throwable.getMessage());
}
}));
}
@Override
public void postAnswer(Answer answer) {
getmThesisView().showLoading();
getCompositeDisposable().add(getDataManager()
.postAnswer(answer)
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
getmThesisView().hideLoading();
if (!isViewAttached()) {
return;
}
getmThesisView().answerPosted(s);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
getmThesisView().onError(throwable.getMessage());
}
}));
}
}
package ee.ttu.thesis.ui.game;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.CheckIn;
import ee.ttu.thesis.data.model.GamesRequest;
import ee.ttu.thesis.data.model.Message;
import ee.ttu.thesis.ui.base.TreauseHuntPresenter;
/**
* Created by hajola on 17.05.17.
*/
public interface GameTreasureHuntPresenter<V extends GameView> extends TreauseHuntPresenter<V> {
void onViewInitialized(GamesRequest.PointsRequest request);
void postCheckIn(CheckIn checkIn);
void postMessage(Message request);
void postAnswer(Answer answer);
}
package ee.ttu.thesis.ui.game;
import java.util.List;
import ee.ttu.thesis.data.model.CheckInResponse;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.ui.base.TreasureHuntView;
/**
* Created by hajola on 17.05.17.
*/
public interface GameView extends TreasureHuntView {
void loadPoints(List<Point> response);
void checkInResponse(CheckInResponse checkInResponse);
void messagePosted();
void answerPosted(String id);
}
package ee.ttu.thesis.ui.game.map;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MapStyleOptions;
import com.google.android.gms.maps.model.MarkerOptions;
import com.orhanobut.logger.Logger;
import java.util.ArrayList;
import java.util.List;
import butterknife.ButterKnife;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.Game;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.PointType;
import ee.ttu.thesis.ui.game.GameActivity;
import ee.ttu.thesis.ui.game.onMapUpdateListener;
import ee.ttu.thesis.utils.RxBus;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import static ee.ttu.thesis.ui.game.GameActivity.GAME_KEY;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
/**
* Created by hajola on 18.04.17.
*/
public class MapFragment extends Fragment implements OnMapReadyCallback {
private CameraPosition mCameraPosition;
private GoogleMap mMap;
private final LatLng mDefaultLocation = new LatLng(59.397212, 24.666660);
private static final int DEFAULT_ZOOM = 12;
private Location mLastKnownLocation;
private boolean isCameraAboveUser = false;
private static final String KEY_CAMERA_POSITION = "camera_position";
private static final String KEY_LOCATION = "location";
Game mGame;
int mCurrentPoint = 0;
RxBus _rxBus;
CompositeDisposable mDisposables;
List<Point> mPoints;
public static MapFragment newInstance(Game game, ArrayList<Point> points) {
Bundle args = new Bundle();
args.putParcelable(GAME_KEY, game);
args.putParcelableArrayList(POINT_KEY, points);
MapFragment fragment = new MapFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onStop() {
super.onStop();
mDisposables.clear();
}
@Override
public void onStart() {
super.onStart();
_rxBus = ((GameActivity) getActivity()).getRxBusSingleton();
mDisposables = new CompositeDisposable();
mDisposables.add(_rxBus.asFlowable()
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
if (o instanceof Location) {
updateLocationUI((Location) o);
} else if(o instanceof Answer){
if(((Answer) o).is_correct()){
mCurrentPoint++;
newPoint();
}
}
}
}));
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_map, container, false);
ButterKnife.bind(this, v);
mGame = getArguments().getParcelable(GAME_KEY);
mPoints = getArguments().getParcelableArrayList(POINT_KEY);
return v;
}
@Override
public void onSaveInstanceState(Bundle outState) {
if (mMap != null) {
outState.putParcelable(KEY_CAMERA_POSITION, mMap.getCameraPosition());
outState.putParcelable(KEY_LOCATION, mLastKnownLocation);
super.onSaveInstanceState(outState);
}
}
private void newPoint() {
Point point = mPoints.get(mCurrentPoint);
if(point.getPointTypes().contains(new PointType("MAP"))){
mMap.clear();
Drawable circleDrawable = getResources().getDrawable(R.drawable.ic_location_on_black_24dp);
BitmapDescriptor markerIcon = getMarkerIconFromDrawable(circleDrawable);
MarkerOptions marker = new MarkerOptions()
.position(new LatLng(point.getLat(), point.getLon()))
.title(point.getTitle())
.snippet(point.getDescription())
.icon(markerIcon);
mMap.addMarker(marker);
getDeviceLocation();
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
try {
MapStyleOptions style = MapStyleOptions.loadRawResourceStyle(getActivity(), R.raw.mapstyle);
mMap.setMapStyle(style);
} catch (Exception e) {
Logger.wtf("Exception " + e.getMessage());
}
newPoint();
}
private BitmapDescriptor getMarkerIconFromDrawable(Drawable drawable) {
Canvas canvas = new Canvas();
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.setColorFilter(getResources().getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN);
drawable.draw(canvas);
return BitmapDescriptorFactory.fromBitmap(bitmap);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
mLastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
}
SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mLastKnownLocation = ((GameActivity) getActivity()).getmCurrentLocation();
if(mLastKnownLocation!= null)
updateLocationUI(mLastKnownLocation);
}
private void getDeviceLocation() {
if (mCameraPosition != null) {
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition));
} else if (mLastKnownLocation != null) {
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(mLastKnownLocation.getLatitude(),
mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
isCameraAboveUser = true;
} else {
Logger.d("Current location is null. Using defaults.");
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
mMap.getUiSettings().setMyLocationButtonEnabled(false);
}
}
public void updateLocationUI(Location newLocation) {
this.mLastKnownLocation = newLocation;
if(!isCameraAboveUser && mMap != null)
getDeviceLocation();
}
}
package ee.ttu.thesis.ui.game.map;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.google.android.gms.maps.SupportMapFragment;
/**
* Created by hajola on 29.04.17.
*/
public class WorkAroundMapFragment extends SupportMapFragment {
private OnTouchListener mListener;
@Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);
TouchableWrapper frameLayout = new TouchableWrapper(getActivity());
frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
((ViewGroup) layout).addView(frameLayout,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return layout;
}
public void setListener(OnTouchListener listener) {
mListener = listener;
}
public interface OnTouchListener {
public abstract void onTouch();
}
public class TouchableWrapper extends FrameLayout {
public TouchableWrapper(Context context) {
super(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mListener.onTouch();
break;
case MotionEvent.ACTION_UP:
mListener.onTouch();
break;
}
return super.dispatchTouchEvent(event);
}
}
}
\ No newline at end of file
package ee.ttu.thesis.ui.game.messages;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.orhanobut.logger.Logger;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Bound;
import ee.ttu.thesis.data.model.Conversation;
import ee.ttu.thesis.data.model.Message;
import ee.ttu.thesis.data.model.Notification;
import ee.ttu.thesis.data.model.User;
import ee.ttu.thesis.ui.base.BaseActivity;
/**
* Created by hajola on 18.04.17.
*/
public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Object> mObjects;
private BaseActivity mContext;
private User user;
public final static int
BOUNDS = 1,
GAME_UPDATE = 4,
RECEIVED_MESSAGE = 6,
SENT_MESSAGE = 7;
private NotificationFragment mFragment;
public NotificationAdapter(List<Object> mObjects, BaseActivity mContext, NotificationFragment fragment, User user) {
this.mObjects = mObjects;
this.mContext = mContext;
this.mFragment = fragment;
this.user = user;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
RecyclerView.ViewHolder viewHolder;
switch (viewType) {
case SENT_MESSAGE:
View sent_view = inflater.inflate(R.layout.item_game_notification_message_sent, parent, false);
viewHolder = new ViewHolderNotificationMessageSent(sent_view);
break;
case RECEIVED_MESSAGE:
View received_view = inflater.inflate(R.layout.item_game_notification_message_received, parent, false);
viewHolder = new ViewHolderNotificationMessageReceived(received_view);
break;
case BOUNDS:
View bound_view = inflater.inflate(R.layout.item_game_notification, parent, false);
viewHolder = new ViewHolderGameNotification(bound_view);
break;
default:
View notification_view = inflater.inflate(R.layout.item_game_notification, parent, false);
viewHolder = new ViewHolderGameNotification(notification_view);
break;
}
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case SENT_MESSAGE:
ViewHolderNotificationMessageSent viewHolderNotificationMessageSent = (ViewHolderNotificationMessageSent) holder;
configureSentViewHolder(viewHolderNotificationMessageSent, position);
break;
case RECEIVED_MESSAGE:
ViewHolderNotificationMessageReceived viewHolderNotificationMessageReceived = (ViewHolderNotificationMessageReceived) holder;
configureReceivedViewHolder(viewHolderNotificationMessageReceived, position);
break;
case BOUNDS:
ViewHolderGameNotification viewHolderGameNotificationBounds = (ViewHolderGameNotification) holder;
configureBoundsViewHolder(viewHolderGameNotificationBounds, position);
break;
default:
ViewHolderGameNotification viewHolderGameNotification = (ViewHolderGameNotification) holder;
configureNotificationViewHolder(viewHolderGameNotification, position);
break;
}
}
private void configureBoundsViewHolder(final ViewHolderGameNotification viewHolderGameNotification, int position) {
final Bound bound = (Bound) mObjects.get(position);
viewHolderGameNotification.getmMessage().setText(bound.getText());
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
viewHolderGameNotification.getmTime().setText(getTimeDiff(new Date(), bound.getViolated_on()));
}
});
}
}, 0, 60000);
}
private void configureNotificationViewHolder(final ViewHolderGameNotification viewHolderGameNotification, int position) {
final Notification notification = (Notification) mObjects.get(position);
viewHolderGameNotification.getmMessage().setText(notification.getText());
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
viewHolderGameNotification.getmTime().setText(getTimeDiff(new Date(), notification.getTime()));
}
});
}
}, 0, 60000);
}
private void configureReceivedViewHolder(ViewHolderNotificationMessageReceived viewHolderNotificationMessageReceived, int position) {
Message object = (Message) mObjects.get(position);
viewHolderNotificationMessageReceived.getmMessageText().setText(object.getContent());
}
private void configureSentViewHolder(ViewHolderNotificationMessageSent viewHolderNotificationMessageSent, int position) {
Message object = (Message) mObjects.get(position);
viewHolderNotificationMessageSent.getmMessageText().setText(object.getContent());
}
public String getTimeDiff(Date dateOne, Date dateTwo) {
String diff = "";
long timeDiff = Math.abs(dateOne.getTime() - dateTwo.getTime());
diff = String.format("%d minutes ago", TimeUnit.MILLISECONDS.toMinutes(timeDiff) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(timeDiff)));
return diff;
}
@Override
public int getItemViewType(int position) {
if (mObjects.get(position) instanceof Message && ((Message) mObjects.get(position)).getUser_id() == user.getId())
return SENT_MESSAGE;
else if (mObjects.get(position) instanceof Message)
return RECEIVED_MESSAGE;
else if (mObjects.get(position) instanceof Notification && ((Notification) mObjects.get(position)).getType() == GAME_UPDATE)
return GAME_UPDATE;
else if (mObjects.get(position) instanceof Bound)
return BOUNDS;
else
Logger.d(mObjects.get(position));
throw new IllegalArgumentException("This viewtype does not exist");
}
public void remove(int position) {
mObjects.remove(position);
notifyItemRemoved(position);
}
@Override
public int getItemCount() {
return mObjects.size();
}
}
package ee.ttu.thesis.ui.game.messages;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.Bound;
import ee.ttu.thesis.data.model.CheckInResponse;
import ee.ttu.thesis.data.model.Game;
import ee.ttu.thesis.data.model.Message;
import ee.ttu.thesis.data.model.Notification;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.User;
import ee.ttu.thesis.ui.base.BaseActivity;
import ee.ttu.thesis.ui.game.GameActivity;
import ee.ttu.thesis.utils.BottomOffsetDecoration;
import ee.ttu.thesis.utils.DeviceDimensionsHelper;
import ee.ttu.thesis.utils.RxBus;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import jp.wasabeef.recyclerview.animators.FadeInRightAnimator;
import static ee.ttu.thesis.ui.game.GameActivity.GAME_KEY;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
import static ee.ttu.thesis.ui.game.GameActivity.USER_KEY;
/**
* Created by hajola on 21.04.17.
*/
public class NotificationFragment extends Fragment {
@BindView(R.id.activity_game_recyclerview)
RecyclerView mRecyclerView;
@BindView(R.id.fragment_notification_editText)
EditText mEditText;
@BindView(R.id.fragment_notification_send)
ImageView mSend;
ArrayList<Object> mShownObjects = new ArrayList<>();
NotificationAdapter mAdapter;
BottomOffsetDecoration mOffsetDecoration;
Game mGame;
User mUser;
int mCurrentPoint = 0;
RxBus _rxBus;
CompositeDisposable mDisposables;
List<Point> mPoints;
public static NotificationFragment newInstance(Game game, ArrayList<Point> points, User user) {
Bundle args = new Bundle();
args.putParcelable(GAME_KEY, game);
args.putParcelable(USER_KEY, user);
args.putParcelableArrayList(POINT_KEY, points);
NotificationFragment fragment = new NotificationFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_notifications, container, false);
ButterKnife.bind(this, v);
mGame = getArguments().getParcelable(GAME_KEY);
mPoints = getArguments().getParcelableArrayList(POINT_KEY);
mUser = getArguments().getParcelable(USER_KEY);
return v;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mShownObjects.add(new Notification(NotificationAdapter.GAME_UPDATE, "Game Start", new Date()));
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
mAdapter = new NotificationAdapter(mShownObjects, (BaseActivity) getActivity(), this, mUser);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(layoutManager);
mOffsetDecoration = new BottomOffsetDecoration(DeviceDimensionsHelper.convertDpToPixel(24, getActivity()), mShownObjects.size());
mRecyclerView.addItemDecoration(mOffsetDecoration);
mRecyclerView.setItemAnimator(new FadeInRightAnimator());
}
@OnClick(R.id.fragment_notification_send)
public void onSendClicked(View view) {
String text = mEditText.getText().toString();
mEditText.setText("");
Message message = new Message(mUser.getId(), text, mGame.getUserGameId());
addMessage(message);
if (_rxBus.hasObservers())
_rxBus.send(message);
}
private void addMessage(Message message) {
mShownObjects.add(message);
mAdapter.notifyItemInserted(mShownObjects.size() - 1);
}
@Override
public void onStop() {
super.onStop();
mDisposables.clear();
}
@Override
public void onStart() {
super.onStart();
_rxBus = ((GameActivity) getActivity()).getRxBusSingleton();
mDisposables = new CompositeDisposable();
mDisposables.add(_rxBus.asFlowable()
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
if (o instanceof Answer) {
mCurrentPoint++;
} else if (o instanceof CheckInResponse) {
// bounds
addBounds(((CheckInResponse) o).getBounds());
// messages
addMessages(((CheckInResponse) o).getMessages());
}
}
}));
}
private void addMessages(List<Message> messages) {
for (Message message : messages) {
mShownObjects.add(message);
mAdapter.notifyItemInserted(mShownObjects.size() - 1);
}
}
private void addBounds(List<Bound> bounds) {
for (Object object : mShownObjects) {
if (object instanceof Bound) {
ListIterator<Bound> iterator = bounds.listIterator();
while (iterator.hasNext()) {
Bound bound = iterator.next();
bound.setViolated_on(new Date());
if (bound.getId() == ((Bound) object).getId()) {
iterator.remove();
}
}
}
}
for (int i = 0; i < bounds.size(); i++) {
bounds.get(i).setViolated_on(new Date());
mShownObjects.add(bounds.get(i));
mAdapter.notifyItemInserted(mShownObjects.size() - 1);
}
}
}
package ee.ttu.thesis.ui.game.messages;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import ee.ttu.thesis.R;
/**
* Created by hajola on 18.04.17.
*/
public class ViewHolderGameNotification extends RecyclerView.ViewHolder {
@BindView(R.id.item_game_notification_message)
TextView mMessage;
@BindView(R.id.item_game_notification_timeTV)
TextView mTime;
public TextView getmTime() {
return mTime;
}
public void setmTime(TextView mTime) {
this.mTime = mTime;
}
public ViewHolderGameNotification(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public TextView getmMessage() {
return mMessage;
}
public void setmMessage(TextView mMessage) {
this.mMessage = mMessage;
}
}
package ee.ttu.thesis.ui.game.messages;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import ee.ttu.thesis.R;
/**
* Created by hajola on 23.04.17.
*/
public class ViewHolderNotificationMessageReceived extends RecyclerView.ViewHolder {
@BindView(R.id.item_game_notification_message_received_text)
TextView mMessageText;
@BindView(R.id.item_game_notification_message_received_root)
LinearLayout mContainer;
public ViewHolderNotificationMessageReceived(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public LinearLayout getmContainer() {
return mContainer;
}
public void setmContainer(LinearLayout mContainer) {
this.mContainer = mContainer;
}
public TextView getmMessageText() {
return mMessageText;
}
public void setmMessageText(TextView mMessageText) {
this.mMessageText = mMessageText;
}
}
package ee.ttu.thesis.ui.game.messages;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import ee.ttu.thesis.R;
/**
* Created by hajola on 23.04.17.
*/
public class ViewHolderNotificationMessageSent extends RecyclerView.ViewHolder {
@BindView(R.id.item_game_notification_message_sent_text)
TextView mMessageText;
@BindView(R.id.item_game_notification_message_sent_root)
LinearLayout mContainer;
public ViewHolderNotificationMessageSent(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public TextView getmMessageText() {
return mMessageText;
}
public void setmMessageText(TextView mMessageText) {
this.mMessageText = mMessageText;
}
public LinearLayout getmContainer() {
return mContainer;
}
public void setmContainer(LinearLayout mContainer) {
this.mContainer = mContainer;
}
}
package ee.ttu.thesis.ui.game;
import android.location.Location;
/**
* Created by hajola on 24.04.17.
*/
public interface onMapUpdateListener {
void onLocationChanged(Location newLocation);
}
package ee.ttu.thesis.ui.game.point;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.orhanobut.logger.Logger;
import ee.ttu.thesis.R;
import ee.ttu.thesis.utils.DeviceDimensionsHelper;
public class CompassView extends View {
// setup initial color
private final int paintColor = Color.GREEN;
private int circleColor;
private int centerColor;
private int lineColor;
private int searchColor;
private int textColor;
// defines paint and canvas
private Paint drawPaint;
private Paint textPaint;
private Paint linePaint;
int size; // Size of the customview, a square
int width, height;
int distance = 1000;
int defaultDistance = 500;//size that is described on the compass
int degrees = Integer.MAX_VALUE;
Path line = new Path();
public CompassView(Context context) {
super(context);
}
public CompassView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
circleColor = context.getResources().getColor(R.color.colorCompassCircle);
centerColor = context.getResources().getColor(R.color.colorCompassCenter);
lineColor = context.getResources().getColor(R.color.colorCompassLine);
searchColor = context.getResources().getColor(R.color.colorCompassFinDot);
textColor = context.getResources().getColor(R.color.colorCompassText);
setupPaint();
}
// Setup paint with color and stroke styles
private void setupPaint() {
drawPaint = new Paint();
drawPaint.setColor(circleColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
textPaint = new Paint();
textPaint.setColor(textColor);
textPaint.setAntiAlias(true);
textPaint.setTextSize(40);
linePaint = new Paint();
linePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
linePaint.setAntiAlias(true);
linePaint.setFilterBitmap(true);
linePaint.setColor(lineColor);
linePaint.setStrokeWidth(1);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setPathEffect(new DashPathEffect(new float[] {10,5}, 0));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int cx = width/2;
int cy = size/2 + getPaddingTop();
int radius = (size/2);
// circle
drawPaint.setColor(circleColor);
drawPaint.setStrokeWidth(5);
canvas.drawCircle(cx, cy, radius, drawPaint);
// centerdot
drawPaint.setStrokeWidth(20);
drawPaint.setColor(centerColor);
canvas.drawPoint(cx, cy, drawPaint);
// search dot
if(degrees != Integer.MAX_VALUE) {
double newRadius = radius;
if(distance/defaultDistance < 1){
double dividor = ((double) distance)/((double)defaultDistance);
newRadius *= dividor;
}
int y = (int) (-newRadius * Math.cos(Math.toRadians(degrees)));
int x = (int) (newRadius * Math.sin(Math.toRadians(degrees)));
x += cx;
y += cy;
drawPaint.setStrokeWidth(35);
drawPaint.setColor(searchColor);
canvas.drawPoint(x, y, drawPaint);
}
// line
line.moveTo(cx, cy);
line.lineTo(cx+radius, cy);
canvas.drawPath(line, linePaint);
// text
int text_width = (int) textPaint.measureText(defaultDistance + " meters");
canvas.drawText(defaultDistance + " meters", cx + (radius/2 - text_width/2), cy, textPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
size = 0;
width = getMeasuredWidth();
height = getMeasuredHeight();
int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();
int heigthWithoutPadding = height - getPaddingTop() - getPaddingBottom();
// set the dimensions
if (widthWithoutPadding > heigthWithoutPadding) {
size = heigthWithoutPadding;
} else {
size = widthWithoutPadding;
}
setMeasuredDimension(size + getPaddingLeft() + getPaddingRight(), size + getPaddingTop() + getPaddingBottom());
}
public void updateUI(int degrees, int distance){
this.degrees = degrees;
this.distance = distance;
invalidate();
}
}
package ee.ttu.thesis.ui.game.point;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.Solution;
import ee.ttu.thesis.ui.game.GameActivity;
import ee.ttu.thesis.utils.RxBus;
import io.reactivex.disposables.CompositeDisposable;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
/**
* Created by hajola on 27.04.17.
*/
public class DialogFragmentSolveQuestion extends DialogFragment {
@BindView(R.id.dialog_question_radiogroup)
RadioGroup mRadioGroup;
@BindView(R.id.dialog_question_title)
TextView mTitle;
Point mPoint;
int correctId;
String correctSolution;
RxBus _rxBus = null;
CompositeDisposable mDisposables;
public static DialogFragmentSolveQuestion newInstance(Point point) {
Bundle args = new Bundle();
args.putParcelable(POINT_KEY, point);
DialogFragmentSolveQuestion fragment = new DialogFragmentSolveQuestion();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog_question, container, false);
ButterKnife.bind(this, v);
mPoint = getArguments().getParcelable(POINT_KEY);
mTitle.setText(mPoint.getQuestion());
for (Solution s : mPoint.getSolutions()) {
RadioButton button = (RadioButton) inflater.inflate(R.layout.item_dialog_question_radiobutton, container, false);
button.setText(s.getSolution());
button.setId(View.generateViewId());
if (s.isCorrectAnswer()) {
correctId = button.getId();
correctSolution = (String) button.getText();
}
mRadioGroup.addView(button);
}
return v;
}
@OnClick(R.id.dialog_question_cancel_button)
public void onCancelClicked(View v) {
dismiss();
}
@OnClick(R.id.dialog_question_submit_button)
public void onSubmitClicked(View v) {
Answer answer = new Answer(mPoint.getId(), mPoint.getProblemType(), correctSolution, correctId == mRadioGroup.getCheckedRadioButtonId());
if ( _rxBus.hasObservers() )
_rxBus.send(answer);
dismiss();
}
@Override
public void onStop() {
super.onStop();
mDisposables.clear();
}
@Override
public void onStart() {
super.onStart();
_rxBus = ((GameActivity) getActivity()).getRxBusSingleton();
mDisposables = new CompositeDisposable();
// mDisposables.add(_rxBus.asFlowable()
// .subscribeOn(AndroidSchedulers.mainThread())
// .subscribe(new Consumer<Object>() {
// @Override
// public void accept(@NonNull Object o) throws Exception {
//
// }
// }));
}
}
package ee.ttu.thesis.ui.game.point;
import android.content.Context;
import android.location.Location;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.maps.model.LatLng;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.CheckInResponse;
import ee.ttu.thesis.data.model.Game;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.PointType;
import ee.ttu.thesis.data.model.ProblemType;
import ee.ttu.thesis.ui.game.GameActivity;
import ee.ttu.thesis.utils.RxBus;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import static ee.ttu.thesis.ui.game.GameActivity.GAME_KEY;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
/**
* Created by hajola on 21.04.17.
* https://github.com/googlesamples/android-play-location/blob/master/LocationUpdates/app/src/main/java/com/google/android/gms/location/sample/locationupdates/MainActivity.java
*/
public class GameFragment extends Fragment {
@BindView(R.id.fragment_solve_point_title)
TextView mTitle;
@BindView(R.id.fragment_solve_point_order)
TextView mOrder;
@BindView(R.id.fragment_solve_point_description)
TextView mDescription;
TextView mDistance;
CompassView mCompassView;
@BindView(R.id.fragment_compass_hint_root)
LinearLayout mHintRoot;
@BindView(R.id.fragment_compass_compass_root)
LinearLayout mCompassRoot;
@BindView(R.id.fragment_compass_distance_root)
LinearLayout mDistanceRoot;
TextView mHintView;
@BindView(R.id.fragment_howtosolvecontent)
FrameLayout mSolveContent;
Game mGame;
Location mLastKnownLocation = null;
int mCurrentPoint = 0;
RxBus _rxBus;
CompositeDisposable mDisposables;
List<Point> mPoints;
public static GameFragment newInstance(Game game, ArrayList<Point> points) {
Bundle args = new Bundle();
args.putParcelable(GAME_KEY, game);
args.putParcelableArrayList(POINT_KEY, points);
GameFragment fragment = new GameFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_game, container, false);
ButterKnife.bind(this, v);
mGame = getArguments().getParcelable(GAME_KEY);
mPoints = getArguments().getParcelableArrayList(POINT_KEY);
return v;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
displayNewPoint();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mLastKnownLocation = ((GameActivity) getActivity()).getmCurrentLocation();
insertHowToSolveFragment();
if (mLastKnownLocation != null)
updateLocationUI(mLastKnownLocation);
}
private void insertHowToSolveFragment() {
Fragment fragment = null;
switch (mPoints.get(mCurrentPoint).getProblemType().getTitle()) {
case ProblemType.NFC:
fragment = GameNFCFragment.newInstance(mPoints.get(mCurrentPoint));
break;
case ProblemType.LOCATION:
fragment = GameLocationFragment.newInstance(mPoints.get(mCurrentPoint));
break;
case ProblemType.QUIZ:
fragment = GameLocationFragment.newInstance(mPoints.get(mCurrentPoint));
break;
case ProblemType.CAMERA:
fragment = GamePhotoFragment.newInstance(mPoints.get(mCurrentPoint));
break;
case ProblemType.QR:
fragment = GameQRFragment.newInstance(mPoints.get(mCurrentPoint));
break;
}
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.fragment_howtosolvecontent, fragment);
ft.commit();
}
@Override
public void onStop() {
super.onStop();
mDisposables.clear();
}
@Override
public void onStart() {
super.onStart();
_rxBus = ((GameActivity) getActivity()).getRxBusSingleton();
mDisposables = new CompositeDisposable();
mDisposables.add(_rxBus.asFlowable()
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
if (o instanceof Location) {
updateLocationUI((Location) o);
} else if (o instanceof Answer) {
if (((Answer) o).is_correct()) {
onPointCompleted();
} else {
onWrongAnswer();
}
} else if (o instanceof CheckInResponse) {
}
}
}));
}
private void updateLocationUI(Location mCurrentLocation) {
mLastKnownLocation = mCurrentLocation;
if (mLastKnownLocation != null && mPoints.get(mCurrentPoint) != null) {
LatLng point2 = new LatLng(mLastKnownLocation.getLatitude(), mLastKnownLocation.getLongitude());
LatLng point = new LatLng(mPoints.get(mCurrentPoint).getLat(), mPoints.get(mCurrentPoint).getLon());
double lat1 = point.latitude;
double lon1 = point.longitude;
double lat2 = point2.latitude;
double lon2 = point2.longitude;
double y = Math.sin(lon2 - lon1) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2 - lon1);
Location loc1 = new Location("");
loc1.setLatitude(lat1);
loc1.setLongitude(lon1);
Location loc2 = new Location("");
loc2.setLatitude(lat2);
loc2.setLongitude(lon2);
int distanceInMeters = (int) loc1.distanceTo(loc2);
int degrees = (int) Math.toDegrees(atan2(y, x));
if (degrees < 0) {
degrees += 360;
}
if (mDistance != null)
mDistance.setText("" + distanceInMeters + " meters away from the point ");
if (mCompassView != null)
mCompassView.updateUI(degrees, distanceInMeters);
}
}
private void displayNewPoint() {
Point point = mPoints.get(mCurrentPoint);
if (!point.getPointTypes().contains(new PointType(PointType.HINT))) {
mHintRoot.removeAllViews();
mHintView = null;
} else {
if ( mHintView == null) {
mHintView = (TextView) getActivity().getLayoutInflater().inflate(R.layout.layout_hint, null);
mHintRoot.addView(mHintView);
}
mHintView.setText(mPoints.get(mCurrentPoint).getHint());
}
if (!point.getPointTypes().contains((new PointType(PointType.COMPASS)))) {
mCompassRoot.removeAllViews();
mCompassView = null;
} else {
if ( mCompassView == null) {
mCompassView = (CompassView) getActivity().getLayoutInflater().inflate(R.layout.layout_compass, null);
mCompassRoot.addView(mCompassView);
}
}
if (!point.getPointTypes().contains((new PointType(PointType.DISTANCE)))) {
mDistanceRoot.removeAllViews();
mDistance = null;
} else {
if ( mDistance == null) {
mDistance = (TextView) getActivity().getLayoutInflater().inflate(R.layout.layout_distance, null);
mDistanceRoot.addView(mDistance);
}
}
mTitle.setText(mPoints.get(mCurrentPoint).getTitle());
mOrder.setText(mPoints.get(mCurrentPoint).getOrder() + " / " + mPoints.size());
mDescription.setText(mPoints.get(mCurrentPoint).getDescription());
insertHowToSolveFragment();
}
public void onPointCompleted() {
try {
final MediaPlayer mp = MediaPlayer.create(getActivity(), R.raw.success);
mp.start();
} catch (Exception e) {
e.printStackTrace();
}
if (mPoints.size() - 1 <= mCurrentPoint) {
// TODO WON GAME
Toast.makeText(getActivity(), "Game won!", Toast.LENGTH_SHORT).show();
} else {
mCurrentPoint++;
displayNewPoint();
}
}
public void onWrongAnswer() {
}
}
package ee.ttu.thesis.ui.game.point;
import android.graphics.PorterDuff;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.view.View;
import com.orhanobut.logger.Logger;
import butterknife.OnClick;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.data.model.ProblemType;
import ee.ttu.thesis.utils.DeviceDimensionsHelper;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
/**
* Created by hajola on 27.04.17.
*/
public class GameLocationFragment extends SolveFragment {
public static GameLocationFragment newInstance(Point point) {
Bundle args = new Bundle();
args.putParcelable(POINT_KEY, point);
GameLocationFragment fragment = new GameLocationFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onIconClicked(v);
}
});
}
@Override
public void onStart() {
super.onStart();
mDisposables.add(_rxBus.asFlowable()
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
if (o instanceof Location) {
}
}
}));
}
@Override
public void onStop() {
super.onStop();
mDisposables.clear();
}
@OnClick(R.id.fragment_solve_icon)
public void onIconClicked(View v) {
Logger.d("LocationClicked");
if (mPoint.getProblemType().getTitle().equals(ProblemType.QUIZ)) {
onAskAQuestion();
} else {
Answer answer = new Answer(mPoint.getId(), mPoint.getProblemType(), "automaatne", true);
if (_rxBus.hasObservers())
_rxBus.send(answer);
}
}
private void onAskAQuestion() {
mIcon.setImageDrawable(getResources().getDrawable(R.drawable.ic_create_black_24dp));
mIcon.setBackground(getActivity().getResources().getDrawable(R.drawable.circle_login_icons));
mInstructions.setText(mPoint.getProblemDescription());
mIcon.setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.DST_OUT);
mIcon.setElevation(DeviceDimensionsHelper.convertDpToPixel(4, getActivity()));
mIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
displayQuestionnaire();
}
});
mInstructions.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
displayQuestionnaire();
}
});
}
private void displayQuestionnaire() {
FragmentManager fm = getChildFragmentManager();
DialogFragmentSolveQuestion dialogFragmentSolveQuestion = DialogFragmentSolveQuestion.newInstance(mPoint);
dialogFragmentSolveQuestion.show(fm, "fragment_location_questionnaire");
}
}
\ No newline at end of file
package ee.ttu.thesis.ui.game.point;
import android.nfc.NdefMessage;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.Bundle;
import android.widget.Toast;
import com.orhanobut.logger.Logger;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.ui.game.GameActivity;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.utils.RxBus;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
/**
* Created by hajola on 25.04.17.
*/
public class GameNFCFragment extends SolveFragment {
public static GameNFCFragment newInstance(Point point) {
Bundle args = new Bundle();
args.putParcelable(POINT_KEY, point);
GameNFCFragment fragment = new GameNFCFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onStart() {
super.onStart();
mDisposables.add(_rxBus.asFlowable()
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
if (o instanceof Tag) {
onNewNFCTag((Tag) o);
}
}
}));
}
@Override
public void onStop() {
super.onStop();
mDisposables.clear();
}
public void onNewNFCTag(Tag tag) {
Logger.d("TAG: " + tag.toString());
Answer answer = new Answer(mPoint.getId(), mPoint.getProblemType(), tag.toString(), Answer.isAnswerCorrect(mPoint, tag.toString()));
if(_rxBus.hasObservers())
_rxBus.send(answer);
}
}
package ee.ttu.thesis.ui.game.point;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Toast;
import butterknife.OnClick;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Point;
import static android.app.Activity.RESULT_OK;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
/**
* Created by hajola on 27.04.17.
*/
public class GamePhotoFragment extends SolveFragment {
static final int REQUEST_IMAGE_CAPTURE = 1;
public static GamePhotoFragment newInstance(Point point) {
Bundle args = new Bundle();
args.putParcelable(POINT_KEY, point);
GamePhotoFragment fragment = new GamePhotoFragment();
fragment.setArguments(args);
return fragment;
}
@OnClick(R.id.fragment_solve_icon)
public void onIconClicked(View v) {
dispatchTakePictureIntent();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Toast.makeText(getActivity(), "Mängujuht hindaks pilti (oota 4s)", Toast.LENGTH_LONG).show();
onPhotoTaken();
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// mOnPointCompletedListener.onPointCompleted();
}
}, 4000);
}
}
public void onPhotoTaken() {
// mOnPointCompletedListener.onWrongAnswer();
mInstructions.setText("Please wait");
mIcon.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mInstructions.setText("Please wait");
mIcon.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
}
}, 6000);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
package ee.ttu.thesis.ui.game.point;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.view.View;
import com.orhanobut.logger.Logger;
import butterknife.OnClick;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Point;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
public class GameQRFragment extends SolveFragment {
public static GameQRFragment newInstance(Point point) {
Bundle args = new Bundle();
args.putParcelable(POINT_KEY, point);
GameQRFragment fragment = new GameQRFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onStart() {
super.onStart();
}
@OnClick(R.id.fragment_solve_icon)
public void onIconClicked(View v) {
FragmentManager fm = getChildFragmentManager();
QRScannerDialogFragment qrScannerDialogFragment = QRScannerDialogFragment.newInstance(mPoint);
qrScannerDialogFragment.show(fm, "fragment_qr_scanner");
}
}
\ No newline at end of file
package ee.ttu.thesis.ui.game.point;
import android.Manifest;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.orhanobut.logger.Logger;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import ee.ttu.thesis.R;
import ee.ttu.thesis.data.model.Answer;
import ee.ttu.thesis.data.model.Point;
import ee.ttu.thesis.ui.game.GameActivity;
import ee.ttu.thesis.utils.QRDataListener;
import ee.ttu.thesis.utils.QRReader;
import ee.ttu.thesis.utils.RxBus;
import io.reactivex.disposables.CompositeDisposable;
import static ee.ttu.thesis.ui.game.GameActivity.POINT_KEY;
/**
* Created by hajola on 26.04.17.
*/
public class QRScannerDialogFragment extends DialogFragment {
@BindView(R.id.dialog_qr_scanner_camera_view)
SurfaceView mCameraView;
@BindView(R.id.dialog_qr_scanner_cancel_button)
Button mCancelButton;
QRReader mQrReader;
Point mPoint;
RxBus _rxBus = null;
boolean answerSent = false;
CompositeDisposable mDisposables;
public static QRScannerDialogFragment newInstance(Point point) {
Bundle args = new Bundle();
args.putParcelable(POINT_KEY, point);
QRScannerDialogFragment fragment = new QRScannerDialogFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog_qr_scanner, container, false);
ButterKnife.bind(this, v);
mPoint = getArguments().getParcelable(POINT_KEY);
return v;
}
@Override
public void onStop() {
super.onStop();
mDisposables.clear();
}
@Override
public void onStart() {
super.onStart();
_rxBus = ((GameActivity) getActivity()).getRxBusSingleton();
mDisposables = new CompositeDisposable();
// mDisposables.add(_rxBus.asFlowable()
// .subscribeOn(AndroidSchedulers.mainThread())
// .subscribe(new Consumer<Object>() {
// @Override
// public void accept(@NonNull Object o) throws Exception {
//
// }
// }));
}
@OnClick(R.id.dialog_qr_scanner_cancel_button)
public void onCancelClicked(View v) {
dismiss();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Logger.d( "view created: ");
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.CAMERA},
1);
mQrReader = new QRReader.Builder(getActivity(), mCameraView, new QRDataListener() {
@Override
public void onDetected(final String data) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if(!answerSent) {
answerSent = true;
Answer answer = new Answer(mPoint.getId(), mPoint.getProblemType(), data, Answer.isAnswerCorrect(mPoint, data));
if (_rxBus.hasObservers())
_rxBus.send(answer);
}
dismiss();
}
});
}
}).facing(QRReader.BACK_CAM)
.enableAutofocus(true)
.height(mCameraView.getHeight())
.width(mCameraView.getWidth())
.build();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onResume() {
super.onResume();
mQrReader.initAndStart(mCameraView);
}
@Override
public void onPause() {
super.onPause();
mQrReader.releaseAndCleanup();
}
}
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment