├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
└── runConfigurations.xml
├── app
├── .gitignore
├── build.gradle
├── google-services.json
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── codingwithmitch
│ │ └── googledirectionstest
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── codingwithmitch
│ │ │ └── googledirectionstest
│ │ │ ├── Constants.java
│ │ │ ├── Topics.java
│ │ │ ├── UserClient.java
│ │ │ ├── adapters
│ │ │ ├── ChatMessageRecyclerAdapter.java
│ │ │ ├── ChatroomRecyclerAdapter.java
│ │ │ ├── ImageListRecyclerAdapter.java
│ │ │ └── UserRecyclerAdapter.java
│ │ │ ├── models
│ │ │ ├── ChatMessage.java
│ │ │ ├── Chatroom.java
│ │ │ ├── ClusterMarker.java
│ │ │ ├── PolylineData.java
│ │ │ ├── User.java
│ │ │ ├── UserLocation.java
│ │ │ └── UserMarker.java
│ │ │ ├── services
│ │ │ └── LocationService.java
│ │ │ ├── ui
│ │ │ ├── ChatroomActivity.java
│ │ │ ├── IProfile.java
│ │ │ ├── ImageListFragment.java
│ │ │ ├── LoginActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── ProfileActivity.java
│ │ │ ├── RegisterActivity.java
│ │ │ └── UserListFragment.java
│ │ │ └── util
│ │ │ ├── Check.java
│ │ │ ├── MyClusterManagerRenderer.java
│ │ │ └── ViewWeightAnimationWrapper.java
│ └── res
│ │ ├── anim
│ │ ├── slide_in_down.xml
│ │ ├── slide_in_up.xml
│ │ ├── slide_out_down.xml
│ │ └── slide_out_up.xml
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── cartman_cop.jpg
│ │ ├── chef.png
│ │ ├── cwm_logo.png
│ │ ├── eric_cartman.jpg
│ │ ├── grey_border_top.xml
│ │ ├── ic_add_white_24dp.xml
│ │ ├── ic_check_green_24dp.xml
│ │ ├── ic_full_screen_black_24dp.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_refresh_black_24dp.xml
│ │ ├── ike.jpg
│ │ ├── kyle.jpg
│ │ ├── satan.jpg
│ │ ├── theme_button.xml
│ │ └── tweek.jpg
│ │ ├── layout
│ │ ├── activity_chatroom.xml
│ │ ├── activity_login.xml
│ │ ├── activity_main.xml
│ │ ├── activity_profile.xml
│ │ ├── activity_register.xml
│ │ ├── fragment_image_list.xml
│ │ ├── fragment_user_list.xml
│ │ ├── layout_chat_message_list_item.xml
│ │ ├── layout_chatroom_list_item.xml
│ │ ├── layout_custom_marker.xml
│ │ ├── layout_image_list_item.xml
│ │ └── layout_user_list_item.xml
│ │ ├── menu
│ │ ├── chatroom_menu.xml
│ │ └── menu_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimen.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── codingwithmitch
│ └── googledirectionstest
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "com.codingwithmitch.googledirectionstest"
7 | minSdkVersion 15
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | multiDexEnabled true
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | implementation fileTree(dir: 'libs', include: ['*.jar'])
24 | implementation 'com.android.support:appcompat-v7:27.1.1'
25 | implementation 'com.android.support.constraint:constraint-layout:1.1.2'
26 | implementation 'com.android.support:support-v4:27.1.1'
27 | testImplementation 'junit:junit:4.12'
28 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
29 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
30 |
31 | //Android Support Design Library
32 | implementation 'com.android.support:design:27.1.1'
33 | //RecyclerView
34 | implementation 'com.android.support:recyclerview-v7:27.1.1'
35 |
36 | // Support multidex
37 | implementation 'com.android.support:multidex:1.0.3'
38 |
39 | // Firebase Core
40 | implementation 'com.google.firebase:firebase-core:16.0.1'
41 |
42 | //Firebase Authentication
43 | implementation 'com.google.firebase:firebase-auth:16.0.2'
44 |
45 | // Firestore Firestore
46 | implementation 'com.google.firebase:firebase-firestore:17.0.4'
47 |
48 | //Google Play Services for Maps
49 | implementation 'com.google.android.gms:play-services-maps:15.0.1'
50 |
51 | // Maps utils (required for custom markers)
52 | implementation 'com.google.maps.android:android-maps-utils:0.5+'
53 |
54 | // Google play services for location information
55 | implementation 'com.google.android.gms:play-services-location:15.0.1'
56 |
57 | // Google Maps Services (needed for directions)
58 | implementation 'com.google.maps:google-maps-services:0.2.9'
59 | implementation 'org.slf4j:slf4j-nop:1.7.25'
60 |
61 | // glide
62 | implementation 'com.github.bumptech.glide:glide:4.8.0'
63 | annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
64 |
65 | // Circle ImageView
66 | implementation 'de.hdodenhof:circleimageview:2.2.0'
67 |
68 | }
69 | apply plugin: 'com.google.gms.google-services'
70 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "482608123904",
4 | "firebase_url": "https://silver-harmony-212817.firebaseio.com",
5 | "project_id": "silver-harmony-212817",
6 | "storage_bucket": "silver-harmony-212817.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:482608123904:android:6a2adede06d9e24e",
12 | "android_client_info": {
13 | "package_name": "com.codingwithmitch.googledirectionstest"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "482608123904-eulmj1657vrl29udm779lia0kdcm4siv.apps.googleusercontent.com",
19 | "client_type": 1,
20 | "android_info": {
21 | "package_name": "com.codingwithmitch.googledirectionstest",
22 | "certificate_hash": "5452be846acdcd729bb27a60a61dabfe596954c4"
23 | }
24 | },
25 | {
26 | "client_id": "482608123904-5ci8llit1l8kgagqksl20k4q0q5htjof.apps.googleusercontent.com",
27 | "client_type": 3
28 | }
29 | ],
30 | "api_key": [
31 | {
32 | "current_key": "AIzaSyCNU8TSa18XAjs5kfsMsvQ-yw756pAS5Hc"
33 | }
34 | ],
35 | "services": {
36 | "analytics_service": {
37 | "status": 1
38 | },
39 | "appinvite_service": {
40 | "status": 2,
41 | "other_platform_oauth_client": [
42 | {
43 | "client_id": "482608123904-5ci8llit1l8kgagqksl20k4q0q5htjof.apps.googleusercontent.com",
44 | "client_type": 3
45 | }
46 | ]
47 | },
48 | "ads_service": {
49 | "status": 2
50 | }
51 | }
52 | }
53 | ],
54 | "configuration_version": "1"
55 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/codingwithmitch/googledirectionstest/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.codingwithmitch.googledirectionstest", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
35 |
38 |
39 |
42 |
43 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/Constants.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest;
2 |
3 | public class Constants {
4 |
5 | public static final int ERROR_DIALOG_REQUEST = 9001;
6 | public static final String MAPVIEW_BUNDLE_KEY = "com.codingwithmitch.googledirectionstest.MAPVIEW_BUNDLE_KEY";
7 | public static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 9002;
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/Topics.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest;
2 |
3 | public class Topics {
4 |
5 | // Making sure the device can use google maps
6 | // Enabling location information
7 | // Enabling Google Maps and other API's from Google Cloud Console
8 | // Getting started with a Google map (Using the API key and inflating a MapView
9 | // (chose to use MapView instead of MapFragment https://developers.google.com/maps/documentation/android-sdk/map#the_map_object)
10 | // Get last known location and upload to Firebase
11 | // Continue retrieving last known location every 5 seconds using a service
12 | // Upload that location to Firebase
13 | // Retrieve location of everyone in a chatroom from Firebase every 5 seconds
14 | // Add markers for every person in chatroom
15 | // animating the camera movement
16 | // Setting view bounds
17 | // ClickListeners for markers
18 | // Retrieving distance and travel duration
19 | // Creating info windows when markers are clicked
20 | // Displaying distance and travel duration in an info window
21 | // Calculating different possible routes
22 | // Add polylines for routes
23 | // Hiding markers
24 | // removing markers
25 | // Initiating a trip in Google Maps app when a trip is selected
26 | // Enabling traffic information (Unfortunately there's not much we can do here)
27 | // Custom icons for the map (Creating a clusterItem and all that stuff)
28 | // https://developers.google.com/maps/documentation/android-sdk/utility/marker-clustering
29 | // https://stackoverflow.com/questions/32158927/android-google-map-icongenerator-making-a-transparent-marker-icon
30 | // Stopping the Location service when user has signed out (checking for null pointer in "saveUserLocation" method in service
31 | // Make sure to talk about the UserClient thing
32 |
33 |
34 |
35 | // MIGHT DO THIS:
36 | // 1) show how to get location simply using "getLastKnownLocation"
37 | // 2) show how to get location updates using a LocationRequest
38 | // 3) show how to get location updates using a service that automatically updates the database if app in background or foreground
39 | // (This also uses the LocationRequest) If greater than API 26 we can use a background service that lasts until app is closed.
40 |
41 |
42 | // Notes:
43 | // 1) After polylines have been added, the positions will no longer change on the map
44 | // This can be reset by pressing the reset button in the top left
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/UserClient.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest;
2 |
3 | import android.app.Application;
4 |
5 | import com.codingwithmitch.googledirectionstest.models.User;
6 | import com.codingwithmitch.googledirectionstest.services.LocationService;
7 | import com.google.firebase.firestore.FirebaseFirestore;
8 |
9 | public class UserClient extends Application {
10 |
11 | private User user = null;
12 |
13 | public User getUser() {
14 | return user;
15 | }
16 |
17 | public void setUser(User user) {
18 | this.user = user;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/adapters/ChatMessageRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.adapters;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.NonNull;
5 | import android.support.v4.content.ContextCompat;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.TextView;
11 |
12 | import com.codingwithmitch.googledirectionstest.R;
13 | import com.codingwithmitch.googledirectionstest.models.ChatMessage;
14 | import com.codingwithmitch.googledirectionstest.models.Chatroom;
15 | import com.codingwithmitch.googledirectionstest.models.User;
16 | import com.google.android.gms.tasks.OnCompleteListener;
17 | import com.google.android.gms.tasks.Task;
18 | import com.google.firebase.auth.FirebaseAuth;
19 | import com.google.firebase.firestore.DocumentReference;
20 | import com.google.firebase.firestore.DocumentSnapshot;
21 | import com.google.firebase.firestore.FirebaseFirestore;
22 |
23 | import java.lang.reflect.Array;
24 | import java.util.ArrayList;
25 |
26 | public class ChatMessageRecyclerAdapter extends RecyclerView.Adapter{
27 |
28 | private ArrayList mMessages = new ArrayList<>();
29 | private ArrayList mUsers = new ArrayList<>();
30 | private Context mContext;
31 |
32 | public ChatMessageRecyclerAdapter(ArrayList messages,
33 | ArrayList users,
34 | Context context) {
35 | this.mMessages = messages;
36 | this.mUsers = users;
37 | this.mContext = context;
38 | }
39 |
40 | @NonNull
41 | @Override
42 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
43 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_chat_message_list_item, parent, false);
44 | final ViewHolder holder = new ViewHolder(view);
45 | return holder;
46 | }
47 |
48 | @Override
49 | public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
50 |
51 |
52 | if(FirebaseAuth.getInstance().getUid().equals(mMessages.get(position).getUser().getUser_id())){
53 | ((ViewHolder)holder).username.setTextColor(ContextCompat.getColor(mContext, R.color.green1));
54 | }
55 | else{
56 | ((ViewHolder)holder).username.setTextColor(ContextCompat.getColor(mContext, R.color.blue2));
57 | }
58 |
59 | ((ViewHolder)holder).username.setText(mMessages.get(position).getUser().getUsername());
60 | ((ViewHolder)holder).message.setText(mMessages.get(position).getMessage());
61 | }
62 |
63 |
64 |
65 | @Override
66 | public int getItemCount() {
67 | return mMessages.size();
68 | }
69 |
70 | public class ViewHolder extends RecyclerView.ViewHolder
71 | {
72 | TextView message, username;
73 |
74 | public ViewHolder(View itemView) {
75 | super(itemView);
76 | message = itemView.findViewById(R.id.chat_message_message);
77 | username = itemView.findViewById(R.id.chat_message_username);
78 | }
79 | }
80 |
81 |
82 | }
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/adapters/ChatroomRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.adapters;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 |
10 | import com.codingwithmitch.googledirectionstest.R;
11 | import com.codingwithmitch.googledirectionstest.models.Chatroom;
12 |
13 | import java.util.ArrayList;
14 | import java.util.HashSet;
15 | import java.util.Set;
16 |
17 | public class ChatroomRecyclerAdapter extends RecyclerView.Adapter{
18 |
19 | private ArrayList mChatrooms = new ArrayList<>();
20 | private ChatroomRecyclerClickListener mChatroomRecyclerClickListener;
21 |
22 | public ChatroomRecyclerAdapter(ArrayList chatrooms, ChatroomRecyclerClickListener chatroomRecyclerClickListener) {
23 | this.mChatrooms = chatrooms;
24 | mChatroomRecyclerClickListener = chatroomRecyclerClickListener;
25 | }
26 |
27 | // private Set mChatrooms = new HashSet<>();
28 | // private ChatroomRecyclerClickListener mChatroomRecyclerClickListener;
29 | //
30 | // public ChatroomRecyclerAdapter(Set chatrooms, ChatroomRecyclerClickListener chatroomRecyclerClickListener) {
31 | // this.mChatrooms = chatrooms;
32 | // mChatroomRecyclerClickListener = chatroomRecyclerClickListener;
33 | // }
34 |
35 | @NonNull
36 | @Override
37 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
38 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_chatroom_list_item, parent, false);
39 | final ViewHolder holder = new ViewHolder(view, mChatroomRecyclerClickListener);
40 |
41 |
42 | return holder;
43 | }
44 |
45 | @Override
46 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
47 |
48 | // ((ViewHolder)holder).chatroomTitle.setText(((Chatroom)(mChatrooms.toArray()[position])).getTitle());
49 | ((ViewHolder)holder).chatroomTitle.setText(mChatrooms.get(position).getTitle());
50 | }
51 |
52 | @Override
53 | public int getItemCount() {
54 | return mChatrooms.size();
55 | }
56 |
57 | public class ViewHolder extends RecyclerView.ViewHolder implements
58 | View.OnClickListener
59 | {
60 | TextView chatroomTitle;
61 | ChatroomRecyclerClickListener clickListener;
62 |
63 | public ViewHolder(View itemView, ChatroomRecyclerClickListener clickListener) {
64 | super(itemView);
65 | chatroomTitle = itemView.findViewById(R.id.chatroom_title);
66 | this.clickListener = clickListener;
67 | itemView.setOnClickListener(this);
68 | }
69 |
70 | @Override
71 | public void onClick(View v) {
72 | clickListener.onChatroomSelected(getAdapterPosition());
73 | }
74 | }
75 |
76 | public interface ChatroomRecyclerClickListener {
77 | public void onChatroomSelected(int position);
78 | }
79 | }
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/adapters/ImageListRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.adapters;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.support.annotation.NonNull;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 |
13 | import com.bumptech.glide.Glide;
14 | import com.bumptech.glide.request.RequestOptions;
15 | import com.codingwithmitch.googledirectionstest.R;
16 | import com.codingwithmitch.googledirectionstest.models.User;
17 |
18 | import java.util.ArrayList;
19 |
20 | public class ImageListRecyclerAdapter extends RecyclerView.Adapter{
21 |
22 | private ArrayList mImages = new ArrayList<>();
23 | private ImageListRecyclerClickListener mImageListRecyclerClickListener;
24 | private Context mContext;
25 |
26 | public ImageListRecyclerAdapter(Context context, ArrayList images, ImageListRecyclerClickListener imageListRecyclerClickListener) {
27 | mContext = context;
28 | mImages = images;
29 | mImageListRecyclerClickListener = imageListRecyclerClickListener;
30 | }
31 |
32 | @NonNull
33 | @Override
34 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
35 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_image_list_item, parent, false);
36 | final ViewHolder holder = new ViewHolder(view, mImageListRecyclerClickListener);
37 | return holder;
38 | }
39 |
40 | @Override
41 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
42 |
43 | RequestOptions requestOptions = new RequestOptions()
44 | .placeholder(R.drawable.cwm_logo)
45 | .error(R.drawable.cwm_logo);
46 |
47 | Glide.with(mContext)
48 | .setDefaultRequestOptions(requestOptions)
49 | .load(mImages.get(position))
50 | .into(((ViewHolder)holder).image);
51 | }
52 |
53 | @Override
54 | public int getItemCount() {
55 | return mImages.size();
56 | }
57 |
58 | public class ViewHolder extends RecyclerView.ViewHolder implements
59 | View.OnClickListener
60 | {
61 | ImageView image;
62 | ImageListRecyclerClickListener mClickListener;
63 |
64 | public ViewHolder(View itemView, ImageListRecyclerClickListener clickListener) {
65 | super(itemView);
66 | image = itemView.findViewById(R.id.image);
67 | mClickListener = clickListener;
68 | itemView.setOnClickListener(this);
69 | }
70 |
71 | @Override
72 | public void onClick(View v) {
73 | mClickListener.onImageSelected(getAdapterPosition());
74 | }
75 | }
76 |
77 | public interface ImageListRecyclerClickListener{
78 | void onImageSelected(int position);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/adapters/UserRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.adapters;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 |
10 | import com.codingwithmitch.googledirectionstest.R;
11 | import com.codingwithmitch.googledirectionstest.models.Chatroom;
12 | import com.codingwithmitch.googledirectionstest.models.User;
13 |
14 | import java.util.ArrayList;
15 |
16 | public class UserRecyclerAdapter extends RecyclerView.Adapter{
17 |
18 | private ArrayList mUsers = new ArrayList<>();
19 | private UserListRecyclerClickListener mUserListRecyclerClickListener;
20 |
21 | public UserRecyclerAdapter(ArrayList mUsers, UserListRecyclerClickListener mUserListRecyclerClickListener) {
22 | this.mUsers = mUsers;
23 | this.mUserListRecyclerClickListener = mUserListRecyclerClickListener;
24 | }
25 |
26 | @NonNull
27 | @Override
28 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
29 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_user_list_item, parent, false);
30 | final ViewHolder holder = new ViewHolder(view, mUserListRecyclerClickListener);
31 | return holder;
32 | }
33 |
34 | @Override
35 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
36 |
37 | ((ViewHolder)holder).username.setText(mUsers.get(position).getUsername());
38 | ((ViewHolder)holder).email.setText(mUsers.get(position).getEmail());
39 | }
40 |
41 | @Override
42 | public int getItemCount() {
43 | return mUsers.size();
44 | }
45 |
46 | public class ViewHolder extends RecyclerView.ViewHolder implements
47 | View.OnClickListener
48 | {
49 | TextView username, email;
50 | UserListRecyclerClickListener mClickListener;
51 |
52 | public ViewHolder(View itemView, UserListRecyclerClickListener clickListener) {
53 | super(itemView);
54 | username = itemView.findViewById(R.id.username);
55 | email = itemView.findViewById(R.id.email);
56 | mClickListener = clickListener;
57 | itemView.setOnClickListener(this);
58 | }
59 |
60 | @Override
61 | public void onClick(View v) {
62 | mClickListener.onUserSelected(getAdapterPosition());
63 | }
64 | }
65 |
66 | public interface UserListRecyclerClickListener{
67 | void onUserSelected(int position);
68 | }
69 |
70 | }
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/models/ChatMessage.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.models;
2 |
3 | import com.google.firebase.firestore.ServerTimestamp;
4 |
5 | import java.util.Date;
6 |
7 | public class ChatMessage {
8 |
9 | private User user;
10 | private String message;
11 | private String message_id;
12 | private @ServerTimestamp Date timestamp;
13 |
14 | public ChatMessage(User user, String message, String message_id, Date timestamp) {
15 | this.user = user;
16 | this.message = message;
17 | this.message_id = message_id;
18 | this.timestamp = timestamp;
19 | }
20 |
21 | public ChatMessage() {
22 |
23 | }
24 |
25 | public User getUser() {
26 | return user;
27 | }
28 |
29 | public void setUser(User user) {
30 | this.user = user;
31 | }
32 |
33 | public String getMessage() {
34 | return message;
35 | }
36 |
37 | public void setMessage(String message) {
38 | this.message = message;
39 | }
40 |
41 | public String getMessage_id() {
42 | return message_id;
43 | }
44 |
45 | public void setMessage_id(String message_id) {
46 | this.message_id = message_id;
47 | }
48 |
49 | public Date getTimestamp() {
50 | return timestamp;
51 | }
52 |
53 | public void setTimestamp(Date timestamp) {
54 | this.timestamp = timestamp;
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | return "ChatMessage{" +
60 | "user=" + user +
61 | ", message='" + message + '\'' +
62 | ", message_id='" + message_id + '\'' +
63 | ", timestamp=" + timestamp +
64 | '}';
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/models/Chatroom.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.models;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | public class Chatroom implements Parcelable {
7 |
8 | private String title;
9 | private String chatroom_id;
10 |
11 |
12 | public Chatroom(String title, String chatroom_id) {
13 | this.title = title;
14 | this.chatroom_id = chatroom_id;
15 | }
16 |
17 | public Chatroom() {
18 |
19 | }
20 |
21 | protected Chatroom(Parcel in) {
22 | title = in.readString();
23 | chatroom_id = in.readString();
24 | }
25 |
26 | public static final Creator CREATOR = new Creator() {
27 | @Override
28 | public Chatroom createFromParcel(Parcel in) {
29 | return new Chatroom(in);
30 | }
31 |
32 | @Override
33 | public Chatroom[] newArray(int size) {
34 | return new Chatroom[size];
35 | }
36 | };
37 |
38 | public String getTitle() {
39 | return title;
40 | }
41 |
42 | public void setTitle(String title) {
43 | this.title = title;
44 | }
45 |
46 | public String getChatroom_id() {
47 | return chatroom_id;
48 | }
49 |
50 | public void setChatroom_id(String chatroom_id) {
51 | this.chatroom_id = chatroom_id;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "Chatroom{" +
57 | "title='" + title + '\'' +
58 | ", chatroom_id='" + chatroom_id + '\'' +
59 | '}';
60 | }
61 |
62 | @Override
63 | public int describeContents() {
64 | return 0;
65 | }
66 |
67 | @Override
68 | public void writeToParcel(Parcel dest, int flags) {
69 | dest.writeString(title);
70 | dest.writeString(chatroom_id);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/models/ClusterMarker.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.models;
2 |
3 | import com.google.android.gms.maps.model.LatLng;
4 | import com.google.maps.android.clustering.ClusterItem;
5 |
6 | public class ClusterMarker implements ClusterItem {
7 |
8 | private LatLng position;
9 | private String title;
10 | private String snippet;
11 | private int iconPicture;
12 | private User user;
13 |
14 | public ClusterMarker(LatLng position, String title, String snippet, int iconPicture, User user) {
15 | this.position = position;
16 | this.title = title;
17 | this.snippet = snippet;
18 | this.iconPicture = iconPicture;
19 | this.user = user;
20 | }
21 |
22 | public int getIconPicture() {
23 | return iconPicture;
24 | }
25 |
26 | public void setIconPicture(int iconPicture) {
27 | this.iconPicture = iconPicture;
28 | }
29 |
30 | public User getUser() {
31 | return user;
32 | }
33 |
34 | public void setUser(User user) {
35 | this.user = user;
36 | }
37 |
38 | public void setPosition(LatLng position) {
39 | this.position = position;
40 | }
41 |
42 | public void setTitle(String title) {
43 | this.title = title;
44 | }
45 |
46 | public void setSnippet(String snippet) {
47 | this.snippet = snippet;
48 | }
49 |
50 | public LatLng getPosition() {
51 | return position;
52 | }
53 |
54 | public String getTitle() {
55 | return title;
56 | }
57 |
58 | public String getSnippet() {
59 | return snippet;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/models/PolylineData.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.models;
2 |
3 | import com.google.android.gms.maps.model.Polyline;
4 | import com.google.maps.model.DirectionsLeg;
5 |
6 | public class PolylineData {
7 |
8 | private Polyline polyline;
9 | private DirectionsLeg leg;
10 |
11 | public PolylineData(Polyline polyline, DirectionsLeg leg) {
12 | this.polyline = polyline;
13 | this.leg = leg;
14 | }
15 |
16 | public Polyline getPolyline() {
17 | return polyline;
18 | }
19 |
20 | public void setPolyline(Polyline polyline) {
21 | this.polyline = polyline;
22 | }
23 |
24 | public DirectionsLeg getLeg() {
25 | return leg;
26 | }
27 |
28 | public void setLeg(DirectionsLeg leg) {
29 | this.leg = leg;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return "PolylineData{" +
35 | "polyline=" + polyline +
36 | ", leg=" + leg +
37 | '}';
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/models/User.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.models;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | public class User implements Parcelable{
7 |
8 | private String email;
9 | private String user_id;
10 | private String username;
11 | private String avatar;
12 |
13 | public User(String email, String user_id, String username, String avatar) {
14 | this.email = email;
15 | this.user_id = user_id;
16 | this.username = username;
17 | this.avatar = avatar;
18 | }
19 |
20 | public User() {
21 |
22 | }
23 |
24 | protected User(Parcel in) {
25 | email = in.readString();
26 | user_id = in.readString();
27 | username = in.readString();
28 | avatar = in.readString();
29 | }
30 |
31 | public static final Creator CREATOR = new Creator() {
32 | @Override
33 | public User createFromParcel(Parcel in) {
34 | return new User(in);
35 | }
36 |
37 | @Override
38 | public User[] newArray(int size) {
39 | return new User[size];
40 | }
41 | };
42 |
43 | public String getAvatar() {
44 | return avatar;
45 | }
46 |
47 | public void setAvatar(String avatar) {
48 | this.avatar = avatar;
49 | }
50 |
51 | public static Creator getCREATOR() {
52 | return CREATOR;
53 | }
54 |
55 | public String getEmail() {
56 | return email;
57 | }
58 |
59 | public void setEmail(String email) {
60 | this.email = email;
61 | }
62 |
63 | public String getUser_id() {
64 | return user_id;
65 | }
66 |
67 | public void setUser_id(String user_id) {
68 | this.user_id = user_id;
69 | }
70 |
71 | public String getUsername() {
72 | return username;
73 | }
74 |
75 | public void setUsername(String username) {
76 | this.username = username;
77 | }
78 |
79 | @Override
80 | public String toString() {
81 | return "User{" +
82 | "email='" + email + '\'' +
83 | ", user_id='" + user_id + '\'' +
84 | ", username='" + username + '\'' +
85 | ", avatar='" + avatar + '\'' +
86 | '}';
87 | }
88 |
89 | @Override
90 | public int describeContents() {
91 | return 0;
92 | }
93 |
94 | @Override
95 | public void writeToParcel(Parcel dest, int flags) {
96 | dest.writeString(email);
97 | dest.writeString(user_id);
98 | dest.writeString(username);
99 | dest.writeString(avatar);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/models/UserLocation.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.models;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.google.firebase.firestore.GeoPoint;
7 | import com.google.firebase.firestore.ServerTimestamp;
8 |
9 | import java.util.Date;
10 |
11 | public class UserLocation implements Parcelable {
12 |
13 | private User user;
14 | private GeoPoint geo_point;
15 | private @ServerTimestamp Date timestamp;
16 |
17 | public UserLocation(User user, GeoPoint geo_point, Date timestamp) {
18 | this.user = user;
19 | this.geo_point = geo_point;
20 | this.timestamp = timestamp;
21 | }
22 |
23 | public UserLocation() {
24 |
25 | }
26 |
27 | protected UserLocation(Parcel in) {
28 | user = in.readParcelable(User.class.getClassLoader());
29 | }
30 |
31 | public static final Creator CREATOR = new Creator() {
32 | @Override
33 | public UserLocation createFromParcel(Parcel in) {
34 | return new UserLocation(in);
35 | }
36 |
37 | @Override
38 | public UserLocation[] newArray(int size) {
39 | return new UserLocation[size];
40 | }
41 | };
42 |
43 | public User getUser() {
44 | return user;
45 | }
46 |
47 | public void setUser(User user) {
48 | this.user = user;
49 | }
50 |
51 | public GeoPoint getGeo_point() {
52 | return geo_point;
53 | }
54 |
55 | public void setGeo_point(GeoPoint geo_point) {
56 | this.geo_point = geo_point;
57 | }
58 |
59 | public Date getTimestamp() {
60 | return timestamp;
61 | }
62 |
63 | public void setTimestamp(Date timestamp) {
64 | this.timestamp = timestamp;
65 | }
66 |
67 | @Override
68 | public String toString() {
69 | return "UserLocation{" +
70 | "user=" + user +
71 | ", geo_point=" + geo_point +
72 | ", timestamp=" + timestamp +
73 | '}';
74 | }
75 |
76 | @Override
77 | public int describeContents() {
78 | return 0;
79 | }
80 |
81 | @Override
82 | public void writeToParcel(Parcel dest, int flags) {
83 | dest.writeParcelable(user, flags);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/models/UserMarker.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.models;
2 |
3 | import com.google.android.gms.maps.model.Marker;
4 |
5 | public class UserMarker {
6 |
7 | private Marker marker;
8 | private User user;
9 |
10 |
11 | public UserMarker(Marker marker, User user) {
12 | this.marker = marker;
13 | this.user = user;
14 | }
15 |
16 | public UserMarker() {
17 | }
18 |
19 |
20 | public Marker getMarker() {
21 | return marker;
22 | }
23 |
24 | public void setMarker(Marker marker) {
25 | this.marker = marker;
26 | }
27 |
28 | public User getUser() {
29 | return user;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return "UserMarker{" +
35 | "marker=" + marker +
36 | ", user=" + user +
37 | '}';
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/services/LocationService.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.services;
2 |
3 |
4 | import android.Manifest;
5 | import android.app.Notification;
6 | import android.app.NotificationChannel;
7 | import android.app.NotificationManager;
8 | import android.app.Service;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.pm.PackageManager;
12 | import android.location.Location;
13 | import android.location.LocationListener;
14 | import android.location.LocationManager;
15 | import android.os.Build;
16 | import android.os.Bundle;
17 | import android.os.Handler;
18 | import android.os.IBinder;
19 | import android.os.Looper;
20 | import android.support.annotation.NonNull;
21 | import android.support.annotation.Nullable;
22 | import android.support.annotation.RequiresApi;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.support.v4.app.NotificationCompat;
25 | import android.util.Log;
26 | import android.widget.Toast;
27 |
28 | import com.codingwithmitch.googledirectionstest.R;
29 | import com.codingwithmitch.googledirectionstest.UserClient;
30 | import com.codingwithmitch.googledirectionstest.models.User;
31 | import com.codingwithmitch.googledirectionstest.models.UserLocation;
32 | import com.google.android.gms.location.FusedLocationProviderClient;
33 | import com.google.android.gms.location.LocationCallback;
34 | import com.google.android.gms.location.LocationRequest;
35 | import com.google.android.gms.location.LocationResult;
36 | import com.google.android.gms.location.LocationServices;
37 | import com.google.android.gms.location.LocationSettingsRequest;
38 | import com.google.android.gms.location.SettingsClient;
39 | import com.google.android.gms.tasks.OnCompleteListener;
40 | import com.google.android.gms.tasks.Task;
41 | import com.google.firebase.auth.FirebaseAuth;
42 | import com.google.firebase.firestore.DocumentReference;
43 | import com.google.firebase.firestore.FirebaseFirestore;
44 | import com.google.firebase.firestore.GeoPoint;
45 |
46 | import java.util.HashMap;
47 |
48 |
49 |
50 | public class LocationService extends Service {
51 |
52 | private static final String TAG = "LocationService";
53 |
54 | private FusedLocationProviderClient mFusedLocationClient;
55 | private final static long UPDATE_INTERVAL = 4 * 1000; /* 4 secs */
56 | private final static long FASTEST_INTERVAL = 2000; /* 2 sec */
57 |
58 | @Nullable
59 | @Override
60 | public IBinder onBind(Intent intent) {
61 | return null;
62 | }
63 |
64 | @Override
65 | public void onCreate() {
66 | super.onCreate();
67 |
68 | mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
69 |
70 | if (Build.VERSION.SDK_INT >= 26) {
71 | String CHANNEL_ID = "my_channel_01";
72 | NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
73 | "My Channel",
74 | NotificationManager.IMPORTANCE_DEFAULT);
75 |
76 | ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
77 |
78 | Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
79 | .setContentTitle("")
80 | .setContentText("").build();
81 |
82 | startForeground(1, notification);
83 | }
84 | }
85 |
86 | @Override
87 | public int onStartCommand(Intent intent, int flags, int startId) {
88 | Log.d(TAG, "onStartCommand: called.");
89 | getLocation();
90 | return START_NOT_STICKY;
91 | }
92 |
93 | @Override
94 | public void onDestroy() {
95 | super.onDestroy();
96 | Log.e(TAG, "onDestroy: called");
97 |
98 | }
99 |
100 |
101 |
102 | private void getLocation() {
103 |
104 | // ---------------------------------- LocationRequest ------------------------------------
105 | // Create the location request to start receiving updates
106 | LocationRequest mLocationRequest = new LocationRequest();
107 | // mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
108 | mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
109 | // mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
110 | // mLocationRequest.setPriority(LocationRequest.PRIORITY_NO_POWER);
111 | mLocationRequest.setInterval(UPDATE_INTERVAL);
112 | mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
113 |
114 | // Create LocationSettingsRequest object using location request
115 | LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
116 | builder.addLocationRequest(mLocationRequest);
117 | LocationSettingsRequest locationSettingsRequest = builder.build();
118 |
119 | // Check whether location settings are satisfied
120 | // https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
121 | SettingsClient settingsClient = LocationServices.getSettingsClient(this);
122 | settingsClient.checkLocationSettings(locationSettingsRequest);
123 |
124 | // new Google API SDK v11 uses getFusedLocationProviderClient(this)
125 | if (ActivityCompat.checkSelfPermission(this,
126 | Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
127 | && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
128 | != PackageManager.PERMISSION_GRANTED) {
129 | Log.d(TAG, "getLocation: stopping the location service.");
130 | stopSelf();
131 | return;
132 | }
133 | Log.d(TAG, "getLocation: getting location information.");
134 | mFusedLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback() {
135 | @Override
136 | public void onLocationResult(LocationResult locationResult) {
137 |
138 | Log.d(TAG, "onLocationResult: got location result.");
139 |
140 | Location location = locationResult.getLastLocation();
141 |
142 | if (location != null) {
143 | User user = ((UserClient)(getApplicationContext())).getUser();
144 | GeoPoint geoPoint = new GeoPoint(location.getLatitude(), location.getLongitude());
145 | UserLocation userLocation = new UserLocation(user, geoPoint, null);
146 | saveUserLocation(userLocation);
147 | }
148 | }
149 | },
150 | Looper.myLooper());
151 | }
152 |
153 | private void saveUserLocation(final UserLocation userLocation){
154 |
155 | try{
156 | DocumentReference locationRef = FirebaseFirestore.getInstance()
157 | .collection(getString(R.string.collection_user_locations))
158 | .document(FirebaseAuth.getInstance().getUid());
159 |
160 | locationRef.set(userLocation).addOnCompleteListener(new OnCompleteListener() {
161 | @Override
162 | public void onComplete(@NonNull Task task) {
163 | if(task.isSuccessful()){
164 | Log.d(TAG, "onComplete: \ninserted user location into database." +
165 | "\n latitude: " + userLocation.getGeo_point().getLatitude() +
166 | "\n longitude: " + userLocation.getGeo_point().getLongitude());
167 | }
168 | }
169 | });
170 | }catch (NullPointerException e){
171 | Log.e(TAG, "saveUserLocation: User instance is null, stopping location service.");
172 | Log.e(TAG, "saveUserLocation: NullPointerException: " + e.getMessage() );
173 | stopSelf();
174 | }
175 |
176 | }
177 |
178 |
179 |
180 |
181 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/ChatroomActivity.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 | import android.os.Build;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.design.widget.Snackbar;
8 | import android.support.v4.app.FragmentTransaction;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.support.v7.widget.LinearLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.util.Log;
13 | import android.view.Menu;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.widget.EditText;
17 | import android.widget.TextView;
18 |
19 | import com.codingwithmitch.googledirectionstest.R;
20 | import com.codingwithmitch.googledirectionstest.UserClient;
21 | import com.codingwithmitch.googledirectionstest.adapters.ChatMessageRecyclerAdapter;
22 | import com.codingwithmitch.googledirectionstest.adapters.ChatroomRecyclerAdapter;
23 | import com.codingwithmitch.googledirectionstest.models.ChatMessage;
24 | import com.codingwithmitch.googledirectionstest.models.Chatroom;
25 | import com.codingwithmitch.googledirectionstest.models.User;
26 | import com.codingwithmitch.googledirectionstest.models.UserLocation;
27 | import com.google.android.gms.tasks.OnCompleteListener;
28 | import com.google.android.gms.tasks.Task;
29 | import com.google.firebase.auth.FirebaseAuth;
30 | import com.google.firebase.firestore.CollectionReference;
31 | import com.google.firebase.firestore.DocumentReference;
32 | import com.google.firebase.firestore.DocumentSnapshot;
33 | import com.google.firebase.firestore.EventListener;
34 | import com.google.firebase.firestore.FirebaseFirestore;
35 | import com.google.firebase.firestore.FirebaseFirestoreException;
36 | import com.google.firebase.firestore.ListenerRegistration;
37 | import com.google.firebase.firestore.Query;
38 | import com.google.firebase.firestore.QueryDocumentSnapshot;
39 | import com.google.firebase.firestore.QuerySnapshot;
40 |
41 | import java.util.ArrayList;
42 | import java.util.HashSet;
43 | import java.util.Set;
44 |
45 | public class ChatroomActivity extends AppCompatActivity implements
46 | View.OnClickListener
47 | {
48 |
49 | private static final String TAG = "ChatroomActivity";
50 |
51 | //widgets
52 | private Chatroom mChatroom;
53 | private EditText mMessage;
54 |
55 | //vars
56 | private ListenerRegistration mChatMessageEventListener, mUserListEventListener;
57 | private RecyclerView mChatMessageRecyclerView;
58 | private ChatMessageRecyclerAdapter mChatMessageRecyclerAdapter;
59 | private FirebaseFirestore mDb;
60 | private ArrayList mMessages = new ArrayList<>();
61 | private Set mMessageIds = new HashSet<>();
62 | private ArrayList mUserList = new ArrayList<>();
63 | private ArrayList mUserLocations = new ArrayList<>();
64 | private UserListFragment mUserListFragment;
65 |
66 |
67 | @Override
68 | protected void onCreate(@Nullable Bundle savedInstanceState) {
69 | super.onCreate(savedInstanceState);
70 | setContentView(R.layout.activity_chatroom);
71 | mMessage = findViewById(R.id.input_message);
72 | mChatMessageRecyclerView = findViewById(R.id.chatmessage_recycler_view);
73 |
74 | findViewById(R.id.checkmark).setOnClickListener(this);
75 |
76 | mDb = FirebaseFirestore.getInstance();
77 |
78 | getIncomingIntent();
79 | initChatroomRecyclerView();
80 | getChatroomUsers();
81 | }
82 |
83 | private void getChatMessages(){
84 |
85 | CollectionReference messagesRef = mDb
86 | .collection(getString(R.string.collection_chatrooms))
87 | .document(mChatroom.getChatroom_id())
88 | .collection(getString(R.string.collection_chat_messages));
89 |
90 | mChatMessageEventListener = messagesRef
91 | .orderBy("timestamp", Query.Direction.ASCENDING)
92 | .addSnapshotListener(new EventListener() {
93 | @Override
94 | public void onEvent(@javax.annotation.Nullable QuerySnapshot queryDocumentSnapshots, @javax.annotation.Nullable FirebaseFirestoreException e) {
95 | if (e != null) {
96 | Log.e(TAG, "onEvent: Listen failed.", e);
97 | return;
98 | }
99 |
100 | if(queryDocumentSnapshots != null){
101 | for (QueryDocumentSnapshot doc : queryDocumentSnapshots) {
102 |
103 | ChatMessage message = doc.toObject(ChatMessage.class);
104 | if(!mMessageIds.contains(message.getMessage_id())){
105 | mMessageIds.add(message.getMessage_id());
106 | mMessages.add(message);
107 | mChatMessageRecyclerView.smoothScrollToPosition(mMessages.size() - 1);
108 | }
109 |
110 | }
111 | mChatMessageRecyclerAdapter.notifyDataSetChanged();
112 |
113 | }
114 | }
115 | });
116 | }
117 |
118 | private void getUserLocation(User user){
119 | DocumentReference locationsRef = mDb
120 | .collection(getString(R.string.collection_user_locations))
121 | .document(user.getUser_id());
122 |
123 | locationsRef.get().addOnCompleteListener(new OnCompleteListener() {
124 | @Override
125 | public void onComplete(@NonNull Task task) {
126 |
127 | if(task.isSuccessful()){
128 | if(task.getResult().toObject(UserLocation.class) != null){
129 |
130 | mUserLocations.add(task.getResult().toObject(UserLocation.class));
131 | }
132 | }
133 | }
134 | });
135 |
136 | }
137 |
138 |
139 | private void getChatroomUsers(){
140 |
141 | CollectionReference usersRef = mDb
142 | .collection(getString(R.string.collection_chatrooms))
143 | .document(mChatroom.getChatroom_id())
144 | .collection(getString(R.string.collection_chatroom_user_list));
145 |
146 | mUserListEventListener = usersRef
147 | .addSnapshotListener(new EventListener() {
148 | @Override
149 | public void onEvent(@javax.annotation.Nullable QuerySnapshot queryDocumentSnapshots, @javax.annotation.Nullable FirebaseFirestoreException e) {
150 | if (e != null) {
151 | Log.e(TAG, "onEvent: Listen failed.", e);
152 | return;
153 | }
154 |
155 | if(queryDocumentSnapshots != null){
156 |
157 | // Clear the list and add all the users again
158 | mUserList.clear();
159 | mUserList = new ArrayList<>();
160 |
161 | // Clear the user locations list
162 | mUserLocations.clear();
163 | mUserLocations = new ArrayList<>();
164 |
165 | for (QueryDocumentSnapshot doc : queryDocumentSnapshots) {
166 | User user = doc.toObject(User.class);
167 | mUserList.add(user);
168 | getUserLocation(user);
169 | }
170 |
171 | Log.d(TAG, "onEvent: user list size: " + mUserList.size());
172 | }
173 | }
174 | });
175 | }
176 |
177 | private void initChatroomRecyclerView(){
178 | mChatMessageRecyclerAdapter = new ChatMessageRecyclerAdapter(mMessages, new ArrayList(), this);
179 | mChatMessageRecyclerView.setAdapter(mChatMessageRecyclerAdapter);
180 | mChatMessageRecyclerView.setLayoutManager(new LinearLayoutManager(this));
181 |
182 | mChatMessageRecyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
183 | @Override
184 | public void onLayoutChange(View v,
185 | int left, int top, int right, int bottom,
186 | int oldLeft, int oldTop, int oldRight, int oldBottom) {
187 | if (bottom < oldBottom) {
188 | mChatMessageRecyclerView.postDelayed(new Runnable() {
189 | @Override
190 | public void run() {
191 | if(mMessages.size() > 0){
192 | mChatMessageRecyclerView.smoothScrollToPosition(
193 | mChatMessageRecyclerView.getAdapter().getItemCount() - 1);
194 | }
195 |
196 | }
197 | }, 100);
198 | }
199 | }
200 | });
201 |
202 | }
203 |
204 |
205 | private void insertNewMessage(){
206 | String message = mMessage.getText().toString();
207 |
208 | if(!message.equals("")){
209 | message = message.replaceAll(System.getProperty("line.separator"), "");
210 |
211 | DocumentReference newMessageDoc = mDb
212 | .collection(getString(R.string.collection_chatrooms))
213 | .document(mChatroom.getChatroom_id())
214 | .collection(getString(R.string.collection_chat_messages))
215 | .document();
216 |
217 | ChatMessage newChatMessage = new ChatMessage();
218 | newChatMessage.setMessage(message);
219 | newChatMessage.setMessage_id(newMessageDoc.getId());
220 |
221 | User user = ((UserClient)(getApplicationContext())).getUser();
222 | Log.d(TAG, "insertNewMessage: retrieved user client: " + user.toString());
223 | newChatMessage.setUser(user);
224 |
225 | newMessageDoc.set(newChatMessage).addOnCompleteListener(new OnCompleteListener() {
226 | @Override
227 | public void onComplete(@NonNull Task task) {
228 | if(task.isSuccessful()){
229 | clearMessage();
230 | }else{
231 | View parentLayout = findViewById(android.R.id.content);
232 | Snackbar.make(parentLayout, "Something went wrong.", Snackbar.LENGTH_SHORT).show();
233 | }
234 | }
235 | });
236 | }
237 | }
238 |
239 | private void clearMessage(){
240 | mMessage.setText("");
241 | }
242 |
243 | private void inflateUserListFragment(){
244 | UserListFragment fragment = UserListFragment.newInstance();
245 | Bundle bundle = new Bundle();
246 | bundle.putParcelableArrayList(getString(R.string.intent_user_list), mUserList);
247 | bundle.putParcelableArrayList(getString(R.string.intent_user_locations), mUserLocations);
248 | fragment.setArguments(bundle);
249 |
250 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
251 | transaction.replace(R.id.user_list_container, fragment, getString(R.string.fragment_user_list));
252 | transaction.addToBackStack(getString(R.string.fragment_user_list));
253 | transaction.commit();
254 | }
255 |
256 |
257 | private void getIncomingIntent(){
258 | if(getIntent().hasExtra(getString(R.string.intent_chatroom))){
259 | mChatroom = getIntent().getParcelableExtra(getString(R.string.intent_chatroom));
260 | setChatroomName();
261 | joinChatroom();
262 | }
263 | }
264 |
265 | private void leaveChatroom(){
266 |
267 | DocumentReference joinChatroomRef = mDb
268 | .collection(getString(R.string.collection_chatrooms))
269 | .document(mChatroom.getChatroom_id())
270 | .collection(getString(R.string.collection_chatroom_user_list))
271 | .document(FirebaseAuth.getInstance().getUid());
272 |
273 | joinChatroomRef.delete();
274 | }
275 |
276 | private void joinChatroom(){
277 |
278 | DocumentReference joinChatroomRef = mDb
279 | .collection(getString(R.string.collection_chatrooms))
280 | .document(mChatroom.getChatroom_id())
281 | .collection(getString(R.string.collection_chatroom_user_list))
282 | .document(FirebaseAuth.getInstance().getUid());
283 |
284 | User user = ((UserClient)(getApplicationContext())).getUser();
285 | joinChatroomRef.set(user); // Don't care about listening for completion.
286 | }
287 |
288 | private void setChatroomName(){
289 | getSupportActionBar().setTitle(mChatroom.getTitle());
290 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
291 | getSupportActionBar().setHomeButtonEnabled(true);
292 | }
293 |
294 | @Override
295 | protected void onResume() {
296 | super.onResume();
297 | getChatMessages();
298 | }
299 |
300 |
301 | @Override
302 | protected void onDestroy() {
303 | super.onDestroy();
304 | if(mChatMessageEventListener != null){
305 | mChatMessageEventListener.remove();
306 | }
307 | if(mUserListEventListener != null){
308 | mUserListEventListener.remove();
309 | }
310 | }
311 |
312 | @Override
313 | public boolean onCreateOptionsMenu(Menu menu) {
314 | getMenuInflater().inflate(R.menu.chatroom_menu, menu);
315 | return super.onCreateOptionsMenu(menu);
316 | }
317 |
318 | @Override
319 | public boolean onOptionsItemSelected(MenuItem item) {
320 | switch(item.getItemId()){
321 | case android.R.id.home:{
322 | UserListFragment fragment =
323 | (UserListFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_user_list));
324 | if(fragment != null){
325 | if(fragment.isVisible()){
326 | getSupportFragmentManager().popBackStack();
327 | return true;
328 | }
329 | }
330 | finish();
331 | return true;
332 | }
333 | case R.id.action_chatroom_user_list:{
334 | inflateUserListFragment();
335 | return true;
336 | }
337 | case R.id.action_chatroom_leave:{
338 | leaveChatroom();
339 | return true;
340 | }
341 | default:{
342 | return super.onOptionsItemSelected(item);
343 | }
344 | }
345 |
346 | }
347 |
348 | @Override
349 | public void onClick(View v) {
350 | switch (v.getId()){
351 | case R.id.checkmark:{
352 | insertNewMessage();
353 | }
354 | }
355 | }
356 |
357 | }
358 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/IProfile.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 | public interface IProfile {
4 |
5 | void onImageSelected(int resource);
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/ImageListFragment.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 |
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.support.v7.widget.StaggeredGridLayoutManager;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 |
14 | import com.codingwithmitch.googledirectionstest.R;
15 | import com.codingwithmitch.googledirectionstest.adapters.ImageListRecyclerAdapter;
16 |
17 | import java.util.ArrayList;
18 |
19 | /**
20 | * A simple {@link Fragment} subclass.
21 | * Use the {@link ImageListFragment#newInstance} factory method to
22 | * create an instance of this fragment.
23 | */
24 | public class ImageListFragment extends Fragment implements ImageListRecyclerAdapter.ImageListRecyclerClickListener{
25 |
26 | private static final String TAG = "ImageListFragment";
27 | private static final int NUM_COLUMNS = 2;
28 |
29 | //widgets
30 | private RecyclerView mRecyclerView;
31 |
32 |
33 | //vars
34 | private ArrayList mImageResources = new ArrayList<>();
35 | private IProfile mIProfile;
36 |
37 | public ImageListFragment() {
38 | // Required empty public constructor
39 | }
40 |
41 |
42 | public static ImageListFragment newInstance() {
43 | return new ImageListFragment();
44 | }
45 |
46 | @Override
47 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
48 | Bundle savedInstanceState) {
49 | View view = inflater.inflate(R.layout.fragment_image_list, container, false);
50 | mRecyclerView = view.findViewById(R.id.image_list_recyclerview);
51 |
52 | getImageResouces();
53 | initRecyclerview();
54 |
55 | return view;
56 | }
57 |
58 | private void getImageResouces(){
59 | mImageResources.add(R.drawable.cwm_logo);
60 | mImageResources.add(R.drawable.cartman_cop);
61 | mImageResources.add(R.drawable.eric_cartman);
62 | mImageResources.add(R.drawable.ike);
63 | mImageResources.add(R.drawable.kyle);
64 | mImageResources.add(R.drawable.satan);
65 | mImageResources.add(R.drawable.chef);
66 | mImageResources.add(R.drawable.tweek);
67 | }
68 |
69 | private void initRecyclerview(){
70 | ImageListRecyclerAdapter mAdapter = new ImageListRecyclerAdapter(getActivity(), mImageResources, this);
71 | StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(NUM_COLUMNS, LinearLayoutManager.VERTICAL);
72 | mRecyclerView.setLayoutManager(staggeredGridLayoutManager);
73 | mRecyclerView.setAdapter(mAdapter);
74 | }
75 |
76 | @Override
77 | public void onAttach(Context context) {
78 | super.onAttach(context);
79 | mIProfile = (IProfile) getActivity();
80 | }
81 |
82 | @Override
83 | public void onImageSelected(int position) {
84 | mIProfile.onImageSelected(mImageResources.get(position));
85 | }
86 | }
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.view.WindowManager;
10 | import android.widget.Button;
11 | import android.widget.EditText;
12 | import android.widget.ProgressBar;
13 | import android.widget.TextView;
14 | import android.widget.Toast;
15 |
16 | import com.codingwithmitch.googledirectionstest.R;
17 | import com.codingwithmitch.googledirectionstest.UserClient;
18 | import com.codingwithmitch.googledirectionstest.models.User;
19 | import com.google.android.gms.tasks.OnCompleteListener;
20 | import com.google.android.gms.tasks.OnFailureListener;
21 | import com.google.android.gms.tasks.Task;
22 | import com.google.firebase.auth.AuthResult;
23 | import com.google.firebase.auth.FirebaseAuth;
24 | import com.google.firebase.auth.FirebaseUser;
25 | import com.google.firebase.firestore.DocumentReference;
26 | import com.google.firebase.firestore.DocumentSnapshot;
27 | import com.google.firebase.firestore.FirebaseFirestore;
28 | import com.google.firebase.firestore.FirebaseFirestoreSettings;
29 |
30 | import static android.text.TextUtils.isEmpty;
31 |
32 | public class LoginActivity extends AppCompatActivity implements
33 | View.OnClickListener
34 | {
35 |
36 | private static final String TAG = "LoginActivity";
37 |
38 | //Firebase
39 | private FirebaseAuth.AuthStateListener mAuthListener;
40 |
41 | // widgets
42 | private EditText mEmail, mPassword;
43 | private ProgressBar mProgressBar;
44 |
45 | @Override
46 | protected void onCreate(Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | setContentView(R.layout.activity_login);
49 | mEmail = findViewById(R.id.email);
50 | mPassword = findViewById(R.id.password);
51 | mProgressBar = findViewById(R.id.progressBar);
52 |
53 | setupFirebaseAuth();
54 | findViewById(R.id.email_sign_in_button).setOnClickListener(this);
55 | findViewById(R.id.link_register).setOnClickListener(this);
56 |
57 | hideSoftKeyboard();
58 | }
59 |
60 |
61 |
62 |
63 | private void showDialog(){
64 | mProgressBar.setVisibility(View.VISIBLE);
65 |
66 | }
67 |
68 | private void hideDialog(){
69 | if(mProgressBar.getVisibility() == View.VISIBLE){
70 | mProgressBar.setVisibility(View.INVISIBLE);
71 | }
72 | }
73 |
74 | private void hideSoftKeyboard(){
75 | this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
76 | }
77 |
78 | /*
79 | ----------------------------- Firebase setup ---------------------------------
80 | */
81 | private void setupFirebaseAuth(){
82 | Log.d(TAG, "setupFirebaseAuth: started.");
83 |
84 | mAuthListener = new FirebaseAuth.AuthStateListener() {
85 | @Override
86 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
87 | FirebaseUser user = firebaseAuth.getCurrentUser();
88 | if (user != null) {
89 | Log.d(TAG, "setupFirebaseAuth:signed_in:" + user.getUid());
90 | Toast.makeText(LoginActivity.this, "Authenticated with: " + user.getEmail(), Toast.LENGTH_SHORT).show();
91 |
92 | FirebaseFirestore db = FirebaseFirestore.getInstance();
93 | FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
94 | .setTimestampsInSnapshotsEnabled(true)
95 | .build();
96 | db.setFirestoreSettings(settings);
97 |
98 | DocumentReference userRef = db.collection(getString(R.string.collection_users))
99 | .document(user.getUid());
100 |
101 | userRef.get().addOnCompleteListener(new OnCompleteListener() {
102 | @Override
103 | public void onComplete(@NonNull Task task) {
104 | if(task.isSuccessful()){
105 | Log.d(TAG, "setupFirebaseAuth: successfully set the user client.");
106 | User user = task.getResult().toObject(User.class);
107 | ((UserClient)(getApplicationContext())).setUser(user);
108 | }
109 | }
110 | });
111 |
112 | Intent intent = new Intent(LoginActivity.this, MainActivity.class);
113 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
114 | startActivity(intent);
115 | finish();
116 |
117 | } else {
118 | // User is signed out
119 | Log.d(TAG, "setupFirebaseAuth:signed_out");
120 | }
121 | // ...
122 | }
123 | };
124 | }
125 |
126 | @Override
127 | public void onStart() {
128 | super.onStart();
129 | FirebaseAuth.getInstance().addAuthStateListener(mAuthListener);
130 | }
131 |
132 | @Override
133 | public void onStop() {
134 | super.onStop();
135 | if (mAuthListener != null) {
136 | FirebaseAuth.getInstance().removeAuthStateListener(mAuthListener);
137 | }
138 | }
139 |
140 | private void signIn(){
141 | //check if the fields are filled out
142 | if(!isEmpty(mEmail.getText().toString())
143 | && !isEmpty(mPassword.getText().toString())){
144 | Log.d(TAG, "onClick: attempting to authenticate.");
145 |
146 | showDialog();
147 |
148 | FirebaseAuth.getInstance().signInWithEmailAndPassword(mEmail.getText().toString(),
149 | mPassword.getText().toString())
150 | .addOnCompleteListener(new OnCompleteListener() {
151 | @Override
152 | public void onComplete(@NonNull Task task) {
153 |
154 | hideDialog();
155 |
156 | }
157 | }).addOnFailureListener(new OnFailureListener() {
158 | @Override
159 | public void onFailure(@NonNull Exception e) {
160 | Toast.makeText(LoginActivity.this, "Authentication Failed", Toast.LENGTH_SHORT).show();
161 | hideDialog();
162 | }
163 | });
164 | }else{
165 | Toast.makeText(LoginActivity.this, "You didn't fill in all the fields.", Toast.LENGTH_SHORT).show();
166 | }
167 | }
168 |
169 | @Override
170 | public void onClick(View view) {
171 | switch (view.getId()){
172 | case R.id.link_register:{
173 | Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
174 | startActivity(intent);
175 | break;
176 | }
177 |
178 | case R.id.email_sign_in_button:{
179 | signIn();
180 | break;
181 | }
182 | }
183 | }
184 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 | import android.Manifest;
4 | import android.app.ActivityManager;
5 | import android.app.AlarmManager;
6 | import android.app.AlertDialog;
7 | import android.app.Dialog;
8 | import android.app.PendingIntent;
9 | import android.content.BroadcastReceiver;
10 | import android.content.Context;
11 | import android.content.DialogInterface;
12 | import android.content.Intent;
13 | import android.content.IntentFilter;
14 | import android.content.pm.PackageManager;
15 |
16 | import android.location.Location;
17 | import android.location.LocationManager;
18 | import android.os.Build;
19 | import android.os.Looper;
20 | import android.support.annotation.NonNull;
21 | import android.support.annotation.RequiresApi;
22 | import android.support.design.widget.Snackbar;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.support.v4.content.ContextCompat;
25 | import android.support.v4.content.LocalBroadcastManager;
26 | import android.support.v7.app.AppCompatActivity;
27 | import android.os.Bundle;
28 | import android.support.v7.widget.LinearLayoutManager;
29 | import android.support.v7.widget.RecyclerView;
30 | import android.text.InputType;
31 | import android.util.Log;
32 | import android.view.Menu;
33 | import android.view.MenuItem;
34 | import android.view.View;
35 | import android.widget.EditText;
36 | import android.widget.ProgressBar;
37 | import android.widget.Toast;
38 |
39 | import com.codingwithmitch.googledirectionstest.R;
40 | import com.codingwithmitch.googledirectionstest.UserClient;
41 | import com.codingwithmitch.googledirectionstest.adapters.ChatroomRecyclerAdapter;
42 | import com.codingwithmitch.googledirectionstest.models.Chatroom;
43 | import com.codingwithmitch.googledirectionstest.models.UserLocation;
44 | import com.codingwithmitch.googledirectionstest.models.User;
45 | import com.codingwithmitch.googledirectionstest.services.LocationService;
46 | import com.google.android.gms.common.ConnectionResult;
47 | import com.google.android.gms.common.GoogleApiAvailability;
48 | import com.google.android.gms.location.FusedLocationProviderClient;
49 | import com.google.android.gms.location.LocationCallback;
50 | import com.google.android.gms.location.LocationRequest;
51 | import com.google.android.gms.location.LocationResult;
52 | import com.google.android.gms.location.LocationServices;
53 | import com.google.android.gms.location.LocationSettingsRequest;
54 | import com.google.android.gms.location.SettingsClient;
55 | import com.google.android.gms.tasks.OnCompleteListener;
56 | import com.google.android.gms.tasks.Task;
57 | import com.google.firebase.auth.FirebaseAuth;
58 | import com.google.firebase.firestore.CollectionReference;
59 | import com.google.firebase.firestore.DocumentReference;
60 | import com.google.firebase.firestore.DocumentSnapshot;
61 | import com.google.firebase.firestore.EventListener;
62 | import com.google.firebase.firestore.FirebaseFirestore;
63 | import com.google.firebase.firestore.FirebaseFirestoreException;
64 | import com.google.firebase.firestore.GeoPoint;
65 | import com.google.firebase.firestore.ListenerRegistration;
66 | import com.google.firebase.firestore.QueryDocumentSnapshot;
67 | import com.google.firebase.firestore.QuerySnapshot;
68 |
69 | import java.util.ArrayList;
70 | import java.util.Date;
71 | import java.util.HashMap;
72 | import java.util.HashSet;
73 | import java.util.Set;
74 |
75 | import javax.annotation.Nullable;
76 |
77 | import static com.codingwithmitch.googledirectionstest.Constants.ERROR_DIALOG_REQUEST;
78 | import static com.codingwithmitch.googledirectionstest.Constants.PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION;
79 |
80 | public class MainActivity extends AppCompatActivity implements
81 | View.OnClickListener,
82 | ChatroomRecyclerAdapter.ChatroomRecyclerClickListener {
83 |
84 | private static final String TAG = "MainActivity";
85 | private final static long UPDATE_INTERVAL = 4 * 1000; /* 4 secs */
86 | private final static long FASTEST_INTERVAL = 2000; /* 2 sec */
87 |
88 | //widgets
89 | private ProgressBar mProgressBar;
90 |
91 | //vars
92 | private ArrayList mChatrooms = new ArrayList<>();
93 | private Set mChatroomIds = new HashSet<>();
94 | private ChatroomRecyclerAdapter mChatroomRecyclerAdapter;
95 | private RecyclerView mChatroomRecyclerView;
96 | private ListenerRegistration mChatroomEventListener;
97 | private FirebaseFirestore mDb;
98 | private boolean mLocationPermissionGranted = false;
99 | private FusedLocationProviderClient mFusedLocationClient;
100 | private LocationRequest mLocationRequest;
101 |
102 |
103 | @Override
104 | protected void onCreate(Bundle savedInstanceState) {
105 | super.onCreate(savedInstanceState);
106 | setContentView(R.layout.activity_main);
107 | mProgressBar = findViewById(R.id.progressBar);
108 | mChatroomRecyclerView = findViewById(R.id.chatrooms_recycler_view);
109 |
110 | findViewById(R.id.fab_create_chatroom).setOnClickListener(this);
111 |
112 | mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
113 | mDb = FirebaseFirestore.getInstance();
114 |
115 | initSupportActionBar();
116 | initChatroomRecyclerView();
117 |
118 | if(((UserClient)getApplicationContext()).getUser() == null){
119 | fetchAndSetUserClient();
120 | }
121 | else{
122 | getLocationPermission();
123 | }
124 | }
125 |
126 | private void fetchAndSetUserClient(){
127 | DocumentReference userRef = mDb.collection(getString(R.string.collection_users))
128 | .document(FirebaseAuth.getInstance().getUid());
129 |
130 | userRef.get().addOnCompleteListener(new OnCompleteListener() {
131 | @Override
132 | public void onComplete(@NonNull Task task) {
133 | if(task.isSuccessful()){
134 | Log.d(TAG, "setupFirebaseAuth: successfully set the user client.");
135 | User user = task.getResult().toObject(User.class);
136 | ((UserClient)(getApplicationContext())).setUser(user);
137 | getLocationPermission();
138 | }
139 | }
140 | });
141 | }
142 |
143 | private void initSupportActionBar(){
144 | setTitle("Chatrooms");
145 | }
146 |
147 |
148 | public boolean isMapsEnabled(){
149 | final LocationManager manager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );
150 |
151 | if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
152 | buildAlertMessageNoGps();
153 | return false;
154 | }
155 | return true;
156 | }
157 |
158 | private void buildAlertMessageNoGps() {
159 | final AlertDialog.Builder builder = new AlertDialog.Builder(this);
160 | builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
161 | .setCancelable(false)
162 | .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
163 | public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
164 | startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
165 | }
166 | })
167 | .setNegativeButton("No", new DialogInterface.OnClickListener() {
168 | public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
169 | dialog.cancel();
170 | }
171 | });
172 | final AlertDialog alert = builder.create();
173 | alert.show();
174 | }
175 |
176 | public boolean isServicesOK(){
177 | Log.d(TAG, "isServicesOK: checking google services version");
178 |
179 | int available = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(MainActivity.this);
180 |
181 | if(available == ConnectionResult.SUCCESS){
182 | //everything is fine and the user can make map requests
183 | Log.d(TAG, "isServicesOK: Google Play Services is working");
184 | return true;
185 | }
186 | else if(GoogleApiAvailability.getInstance().isUserResolvableError(available)){
187 | //an error occured but we can resolve it
188 | Log.d(TAG, "isServicesOK: an error occured but we can fix it");
189 | Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(MainActivity.this, available, ERROR_DIALOG_REQUEST);
190 | dialog.show();
191 | }else{
192 | Toast.makeText(this, "You can't make map requests", Toast.LENGTH_SHORT).show();
193 | }
194 | return false;
195 | }
196 |
197 | private void getLocationPermission() {
198 | /*
199 | * Request location permission, so that we can get the location of the
200 | * device. The result of the permission request is handled by a callback,
201 | * onRequestPermissionsResult.
202 | */
203 | if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
204 | android.Manifest.permission.ACCESS_FINE_LOCATION)
205 | == PackageManager.PERMISSION_GRANTED) {
206 | getLastKnownLocation();
207 | // startLocationService();
208 | } else {
209 | ActivityCompat.requestPermissions(this,
210 | new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
211 | PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
212 | }
213 | }
214 |
215 | @Override
216 | public void onRequestPermissionsResult(int requestCode,
217 | @NonNull String permissions[],
218 | @NonNull int[] grantResults) {
219 | mLocationPermissionGranted = false;
220 | switch (requestCode) {
221 | case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
222 | // If request is cancelled, the result arrays are empty.
223 | if (grantResults.length > 0
224 | && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
225 | getLastKnownLocation();
226 | // startLocationService();
227 | }
228 | }
229 | }
230 | }
231 |
232 |
233 | private void getLastKnownLocation() {
234 | Log.d(TAG, "getLastKnownLocation: called.");
235 | if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
236 | && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
237 | return;
238 | }
239 | mFusedLocationClient.getLastLocation().addOnCompleteListener(new OnCompleteListener() {
240 | @Override
241 | public void onComplete(@NonNull Task task) {
242 | if (task.isSuccessful()) {
243 | mLocationPermissionGranted = true;
244 | Location location = task.getResult();
245 | User user = ((UserClient)(getApplicationContext())).getUser();
246 | GeoPoint geoPoint = new GeoPoint(location.getLatitude(), location.getLongitude());
247 | UserLocation userLocation = new UserLocation(user, geoPoint, null);
248 | saveUserLocation(userLocation);
249 | startLocationService();
250 | }
251 | }
252 | });
253 |
254 |
255 |
256 | // ---------------------------------- LocationRequest for Activity ------------------------------------
257 | // Create the location request to start receiving updates
258 | // mLocationRequest = new LocationRequest();
259 | //// mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
260 | // mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
261 | //// mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
262 | //// mLocationRequest.setPriority(LocationRequest.PRIORITY_NO_POWER);
263 | // mLocationRequest.setInterval(UPDATE_INTERVAL);
264 | // mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
265 | //
266 | // // Create LocationSettingsRequest object using location request
267 | // LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
268 | // builder.addLocationRequest(mLocationRequest);
269 | // LocationSettingsRequest locationSettingsRequest = builder.build();
270 | //
271 | // // Check whether location settings are satisfied
272 | // // https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
273 | // SettingsClient settingsClient = LocationServices.getSettingsClient(this);
274 | // settingsClient.checkLocationSettings(locationSettingsRequest);
275 | //
276 | // // new Google API SDK v11 uses getFusedLocationProviderClient(this)
277 | // mFusedLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback() {
278 | // @Override
279 | // public void onLocationResult(LocationResult locationResult) {
280 | //
281 | // mLocationPermissionGranted = true;
282 | // Location location = locationResult.getLastLocation();
283 | //
284 | // if(location != null){
285 | // User user = ((UserClient)(getApplicationContext())).getUser();
286 | // GeoPoint geoPoint = new GeoPoint(location.getLatitude(), location.getLongitude());
287 | // UserLocation userLocation = new UserLocation(user, geoPoint, null);
288 | // saveUserLocation(userLocation);
289 | //
290 | // Toast.makeText(getApplicationContext(), "current location:\n"
291 | // + "latitude: " + locationResult.getLastLocation().getLatitude() + "\n"
292 | // + "longitude: " + locationResult.getLastLocation().getLongitude(),
293 | // Toast.LENGTH_SHORT).show();
294 | // }
295 | //
296 | // }
297 | // },
298 | // Looper.myLooper());
299 |
300 |
301 | }
302 |
303 | private void startLocationService(){
304 | if(!isLocationServiceRunning()){
305 | Intent serviceIntent = new Intent(this, LocationService.class);
306 | // this.startService(serviceIntent);
307 |
308 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
309 |
310 | MainActivity.this.startForegroundService(serviceIntent);
311 | }else{
312 | startService(serviceIntent);
313 | }
314 | }
315 | }
316 |
317 | private boolean isLocationServiceRunning() {
318 | ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
319 | for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)){
320 | if("com.codingwithmitch.googledirectionstest.services.LocationService".equals(service.service.getClassName())) {
321 | Log.d(TAG, "isLocationServiceRunning: location service is already running.");
322 | return true;
323 | }
324 | }
325 | Log.d(TAG, "isLocationServiceRunning: location service is not running.");
326 | return false;
327 | }
328 |
329 | private void saveUserLocation(final UserLocation userLocation){
330 |
331 | DocumentReference locationRef = mDb
332 | .collection(getString(R.string.collection_user_locations))
333 | .document(FirebaseAuth.getInstance().getUid());
334 |
335 | locationRef.set(userLocation).addOnCompleteListener(new OnCompleteListener() {
336 | @Override
337 | public void onComplete(@NonNull Task task) {
338 | if(task.isSuccessful()){
339 | Log.d(TAG, "onComplete: \ninserted user location into database." +
340 | "\n latitude: " + userLocation.getGeo_point().getLatitude() +
341 | "\n longitude: " + userLocation.getGeo_point().getLongitude());
342 | }
343 | }
344 | });
345 | }
346 |
347 |
348 | @Override
349 | public void onClick(View view) {
350 | switch (view.getId()){
351 |
352 | case R.id.fab_create_chatroom:{
353 | if(checkMapServices()){
354 | if(mLocationPermissionGranted){
355 | newChatroomDialog();
356 | }
357 | else{
358 | getLocationPermission();
359 | }
360 | }
361 | }
362 | }
363 | }
364 |
365 | private boolean checkMapServices(){
366 | if(isServicesOK()){
367 | if(isMapsEnabled()){
368 | return true;
369 | }
370 | }
371 | return false;
372 | }
373 |
374 | private void initChatroomRecyclerView(){
375 | mChatroomRecyclerAdapter = new ChatroomRecyclerAdapter(mChatrooms, this);
376 | mChatroomRecyclerView.setAdapter(mChatroomRecyclerAdapter);
377 | mChatroomRecyclerView.setLayoutManager(new LinearLayoutManager(this));
378 | }
379 |
380 | private void getChatrooms(){
381 |
382 | CollectionReference chatroomsCollection = mDb
383 | .collection(getString(R.string.collection_chatrooms));
384 |
385 | mChatroomEventListener = chatroomsCollection.addSnapshotListener(new EventListener() {
386 | @Override
387 | public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {
388 | Log.d(TAG, "onEvent: called.");
389 |
390 | if (e != null) {
391 | Log.e(TAG, "onEvent: Listen failed.", e);
392 | return;
393 | }
394 |
395 | if(queryDocumentSnapshots != null){
396 | for (QueryDocumentSnapshot doc : queryDocumentSnapshots) {
397 |
398 | Chatroom chatroom = doc.toObject(Chatroom.class);
399 | if(!mChatroomIds.contains(chatroom.getChatroom_id())){
400 | mChatroomIds.add(chatroom.getChatroom_id());
401 | mChatrooms.add(chatroom);
402 | }
403 | }
404 | Log.d(TAG, "onEvent: number of chatrooms: " + mChatrooms.size());
405 | mChatroomRecyclerAdapter.notifyDataSetChanged();
406 | }
407 |
408 | }
409 | });
410 | }
411 |
412 | private void buildNewChatroom(String chatroomName){
413 |
414 | final Chatroom chatroom = new Chatroom();
415 | chatroom.setTitle(chatroomName);
416 |
417 | DocumentReference newChatroomRef = mDb
418 | .collection(getString(R.string.collection_chatrooms))
419 | .document();
420 |
421 | chatroom.setChatroom_id(newChatroomRef.getId());
422 |
423 | newChatroomRef.set(chatroom).addOnCompleteListener(new OnCompleteListener() {
424 | @Override
425 | public void onComplete(@NonNull Task task) {
426 | hideDialog();
427 |
428 | if(task.isSuccessful()){
429 | navChatroomActivity(chatroom);
430 | }else{
431 | View parentLayout = findViewById(android.R.id.content);
432 | Snackbar.make(parentLayout, "Something went wrong.", Snackbar.LENGTH_SHORT).show();
433 | }
434 | }
435 | });
436 | }
437 |
438 | private void navChatroomActivity(Chatroom chatroom){
439 | Intent intent = new Intent(MainActivity.this, ChatroomActivity.class);
440 | intent.putExtra(getString(R.string.intent_chatroom), chatroom);
441 | startActivity(intent);
442 | }
443 |
444 | private void newChatroomDialog(){
445 |
446 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
447 | builder.setTitle("Enter a chatroom name");
448 |
449 | final EditText input = new EditText(this);
450 | input.setInputType(InputType.TYPE_CLASS_TEXT);
451 | builder.setView(input);
452 |
453 | builder.setPositiveButton("CREATE", new DialogInterface.OnClickListener() {
454 | @Override
455 | public void onClick(DialogInterface dialog, int which) {
456 | if(!input.getText().toString().equals("")){
457 | buildNewChatroom(input.getText().toString());
458 | }
459 | else {
460 | Toast.makeText(MainActivity.this, "Enter a chatroom name", Toast.LENGTH_SHORT).show();
461 | }
462 | }
463 | });
464 | builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
465 | @Override
466 | public void onClick(DialogInterface dialog, int which) {
467 | dialog.cancel();
468 | }
469 | });
470 |
471 | builder.show();
472 | }
473 |
474 | @Override
475 | protected void onDestroy() {
476 | super.onDestroy();
477 | if(mChatroomEventListener != null){
478 | mChatroomEventListener.remove();
479 | }
480 | }
481 |
482 | @Override
483 | protected void onResume() {
484 | super.onResume();
485 | getChatrooms();
486 | }
487 |
488 | @Override
489 | public void onChatroomSelected(int position) {
490 | if(checkMapServices()){
491 | if(mLocationPermissionGranted){
492 | navChatroomActivity(mChatrooms.get(position));
493 | }
494 | else{
495 | getLocationPermission();
496 | }
497 | }
498 | }
499 |
500 | private void signOut(){
501 | FirebaseAuth.getInstance().signOut(); // Sign out Firebase
502 |
503 | ((UserClient)getApplicationContext()).setUser(null); // Reset UserClient instance
504 |
505 | Intent intent = new Intent(this, LoginActivity.class);
506 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
507 | startActivity(intent);
508 | finish();
509 | }
510 |
511 | @Override
512 | public boolean onCreateOptionsMenu(Menu menu) {
513 | getMenuInflater().inflate(R.menu.menu_main, menu);
514 | return super.onCreateOptionsMenu(menu);
515 | }
516 |
517 |
518 | @Override
519 | public boolean onOptionsItemSelected(MenuItem item) {
520 | switch(item.getItemId()){
521 | case R.id.action_sign_out:{
522 | signOut();
523 | return true;
524 | }
525 | case R.id.action_profile:{
526 | startActivity(new Intent(this, ProfileActivity.class));
527 | return true;
528 | }
529 | default:{
530 | return super.onOptionsItemSelected(item);
531 | }
532 | }
533 |
534 | }
535 |
536 | private void showDialog(){
537 | mProgressBar.setVisibility(View.VISIBLE);
538 | }
539 |
540 | private void hideDialog(){
541 | mProgressBar.setVisibility(View.GONE);
542 | }
543 |
544 |
545 | }
546 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/ProfileActivity.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.design.widget.FloatingActionButton;
7 | import android.support.design.widget.Snackbar;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.Toolbar;
10 | import android.util.Log;
11 | import android.view.Menu;
12 | import android.view.MenuItem;
13 | import android.view.View;
14 |
15 | import com.bumptech.glide.Glide;
16 | import com.bumptech.glide.request.RequestOptions;
17 | import com.codingwithmitch.googledirectionstest.R;
18 | import com.codingwithmitch.googledirectionstest.UserClient;
19 | import com.codingwithmitch.googledirectionstest.adapters.ImageListRecyclerAdapter;
20 | import com.codingwithmitch.googledirectionstest.models.User;
21 | import com.codingwithmitch.googledirectionstest.util.ViewWeightAnimationWrapper;
22 | import com.google.android.gms.tasks.OnCompleteListener;
23 | import com.google.android.gms.tasks.Task;
24 | import com.google.firebase.auth.FirebaseAuth;
25 | import com.google.firebase.firestore.DocumentSnapshot;
26 | import com.google.firebase.firestore.FirebaseFirestore;
27 |
28 | import de.hdodenhof.circleimageview.CircleImageView;
29 |
30 | public class ProfileActivity extends AppCompatActivity implements
31 | View.OnClickListener,
32 | IProfile
33 | {
34 |
35 | private static final String TAG = "ProfileActivity";
36 |
37 |
38 | //widgets
39 | private CircleImageView mAvatarImage;
40 |
41 | //vars
42 | private ImageListFragment mImageListFragment;
43 |
44 |
45 | @Override
46 | protected void onCreate(Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | setContentView(R.layout.activity_profile);
49 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
50 | getSupportActionBar().setHomeButtonEnabled(true);
51 | mAvatarImage = findViewById(R.id.image_choose_avatar);
52 |
53 | findViewById(R.id.image_choose_avatar).setOnClickListener(this);
54 | findViewById(R.id.text_choose_avatar).setOnClickListener(this);
55 |
56 | retrieveProfileImage();
57 | }
58 |
59 | private void retrieveProfileImage(){
60 | RequestOptions requestOptions = new RequestOptions()
61 | .error(R.drawable.cwm_logo)
62 | .placeholder(R.drawable.cwm_logo);
63 |
64 | int avatar = 0;
65 | try{
66 | avatar = Integer.parseInt(((UserClient)getApplicationContext()).getUser().getAvatar());
67 | }catch (NumberFormatException e){
68 | Log.e(TAG, "retrieveProfileImage: no avatar image. Setting default. " + e.getMessage() );
69 | }
70 |
71 | Glide.with(ProfileActivity.this)
72 | .setDefaultRequestOptions(requestOptions)
73 | .load(avatar)
74 | .into(mAvatarImage);
75 | }
76 |
77 | @Override
78 | public void onClick(View v) {
79 | mImageListFragment = new ImageListFragment();
80 | getSupportFragmentManager().beginTransaction()
81 | .setCustomAnimations(R.anim.slide_in_up, R.anim.slide_in_down, R.anim.slide_out_down, R.anim.slide_out_up)
82 | .replace(R.id.fragment_container, mImageListFragment, getString(R.string.fragment_image_list))
83 | .commit();
84 | }
85 |
86 | @Override
87 | public boolean onOptionsItemSelected(MenuItem item) {
88 |
89 | switch (item.getItemId()){
90 | case android.R.id.home:{
91 | finish();
92 | }
93 | }
94 | return super.onOptionsItemSelected(item);
95 | }
96 |
97 | @Override
98 | public boolean onCreateOptionsMenu(Menu menu) {
99 | return super.onCreateOptionsMenu(menu);
100 | }
101 |
102 | @Override
103 | public void onImageSelected(int resource) {
104 |
105 | // remove the image selector fragment
106 | getSupportFragmentManager().beginTransaction()
107 | .setCustomAnimations(R.anim.slide_in_up, R.anim.slide_in_down, R.anim.slide_out_down, R.anim.slide_out_up)
108 | .remove(mImageListFragment)
109 | .commit();
110 |
111 | // display the image
112 | RequestOptions requestOptions = new RequestOptions()
113 | .placeholder(R.drawable.cwm_logo)
114 | .error(R.drawable.cwm_logo);
115 |
116 | Glide.with(this)
117 | .setDefaultRequestOptions(requestOptions)
118 | .load(resource)
119 | .into(mAvatarImage);
120 |
121 | // update the client and database
122 | User user = ((UserClient)getApplicationContext()).getUser();
123 | user.setAvatar(String.valueOf(resource));
124 |
125 | FirebaseFirestore.getInstance()
126 | .collection(getString(R.string.collection_users))
127 | .document(FirebaseAuth.getInstance().getUid())
128 | .set(user);
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/RegisterActivity.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.design.widget.Snackbar;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.util.Log;
10 | import android.view.View;
11 | import android.view.WindowManager;
12 | import android.widget.Button;
13 | import android.widget.EditText;
14 | import android.widget.ProgressBar;
15 | import android.widget.Toast;
16 |
17 | import com.codingwithmitch.googledirectionstest.R;
18 | import com.codingwithmitch.googledirectionstest.models.User;
19 | import com.google.android.gms.tasks.OnCompleteListener;
20 | import com.google.android.gms.tasks.OnFailureListener;
21 | import com.google.android.gms.tasks.Task;
22 | import com.google.firebase.auth.AuthResult;
23 | import com.google.firebase.auth.FirebaseAuth;
24 | import com.google.firebase.firestore.DocumentReference;
25 | import com.google.firebase.firestore.FirebaseFirestore;
26 |
27 | import static android.text.TextUtils.isEmpty;
28 | import static com.codingwithmitch.googledirectionstest.util.Check.doStringsMatch;
29 |
30 |
31 | public class RegisterActivity extends AppCompatActivity implements
32 | View.OnClickListener
33 | {
34 | private static final String TAG = "RegisterActivity";
35 |
36 | //widgets
37 | private EditText mEmail, mPassword, mConfirmPassword;
38 | private ProgressBar mProgressBar;
39 |
40 | //vars
41 | private FirebaseFirestore mDb;
42 |
43 |
44 | @Override
45 | protected void onCreate(@Nullable Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | setContentView(R.layout.activity_register);
48 | mEmail = (EditText) findViewById(R.id.input_email);
49 | mPassword = (EditText) findViewById(R.id.input_password);
50 | mConfirmPassword = (EditText) findViewById(R.id.input_confirm_password);
51 | mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
52 |
53 | findViewById(R.id.btn_register).setOnClickListener(this);
54 |
55 | mDb = FirebaseFirestore.getInstance();
56 |
57 | hideSoftKeyboard();
58 | }
59 |
60 | /**
61 | * Register a new email and password to Firebase Authentication
62 | * @param email
63 | * @param password
64 | */
65 | public void registerNewEmail(final String email, String password){
66 |
67 | showDialog();
68 |
69 | FirebaseAuth.getInstance().createUserWithEmailAndPassword(email, password)
70 | .addOnCompleteListener(new OnCompleteListener() {
71 | @Override
72 | public void onComplete(@NonNull Task task) {
73 | Log.d(TAG, "createUserWithEmail:onComplete:" + task.isSuccessful());
74 |
75 | if (task.isSuccessful()){
76 | Log.d(TAG, "onComplete: AuthState: " + FirebaseAuth.getInstance().getCurrentUser().getUid());
77 |
78 | //insert some default data
79 | User user = new User();
80 | user.setEmail(email);
81 | user.setUsername(email.substring(0, email.indexOf("@")));
82 | user.setUser_id(FirebaseAuth.getInstance().getUid());
83 |
84 | DocumentReference newUserRef = mDb
85 | .collection(getString(R.string.collection_users))
86 | .document(FirebaseAuth.getInstance().getUid());
87 |
88 | newUserRef.set(user).addOnCompleteListener(new OnCompleteListener() {
89 | @Override
90 | public void onComplete(@NonNull Task task) {
91 | hideDialog();
92 |
93 | if(task.isSuccessful()){
94 | redirectLoginScreen();
95 | }else{
96 | View parentLayout = findViewById(android.R.id.content);
97 | Snackbar.make(parentLayout, "Something went wrong.", Snackbar.LENGTH_SHORT).show();
98 | }
99 | }
100 | });
101 |
102 | }
103 | else {
104 | View parentLayout = findViewById(android.R.id.content);
105 | Snackbar.make(parentLayout, "Something went wrong.", Snackbar.LENGTH_SHORT).show();
106 | hideDialog();
107 | }
108 |
109 | // ...
110 | }
111 | });
112 | }
113 |
114 | /**
115 | * Redirects the user to the login screen
116 | */
117 | private void redirectLoginScreen(){
118 | Log.d(TAG, "redirectLoginScreen: redirecting to login screen.");
119 |
120 | Intent intent = new Intent(RegisterActivity.this, LoginActivity.class);
121 | startActivity(intent);
122 | finish();
123 | }
124 |
125 |
126 | private void showDialog(){
127 | mProgressBar.setVisibility(View.VISIBLE);
128 |
129 | }
130 |
131 | private void hideDialog(){
132 | if(mProgressBar.getVisibility() == View.VISIBLE){
133 | mProgressBar.setVisibility(View.INVISIBLE);
134 | }
135 | }
136 |
137 | private void hideSoftKeyboard(){
138 | this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
139 | }
140 |
141 | @Override
142 | public void onClick(View view) {
143 | switch (view.getId()){
144 | case R.id.btn_register:{
145 | Log.d(TAG, "onClick: attempting to register.");
146 |
147 | //check for null valued EditText fields
148 | if(!isEmpty(mEmail.getText().toString())
149 | && !isEmpty(mPassword.getText().toString())
150 | && !isEmpty(mConfirmPassword.getText().toString())){
151 |
152 | //check if passwords match
153 | if(doStringsMatch(mPassword.getText().toString(), mConfirmPassword.getText().toString())){
154 |
155 | //Initiate registration task
156 | registerNewEmail(mEmail.getText().toString(), mPassword.getText().toString());
157 | }else{
158 | Toast.makeText(RegisterActivity.this, "Passwords do not Match", Toast.LENGTH_SHORT).show();
159 | }
160 |
161 | }else{
162 | Toast.makeText(RegisterActivity.this, "You must fill out all the fields", Toast.LENGTH_SHORT).show();
163 | }
164 | break;
165 | }
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/ui/UserListFragment.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.ui;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.app.AlertDialog;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.graphics.Bitmap;
9 | import android.graphics.BitmapFactory;
10 | import android.graphics.Canvas;
11 | import android.graphics.Color;
12 | import android.graphics.Paint;
13 | import android.graphics.PorterDuff;
14 | import android.graphics.drawable.BitmapDrawable;
15 | import android.graphics.drawable.Drawable;
16 | import android.net.Uri;
17 | import android.os.Bundle;
18 | import android.os.Handler;
19 | import android.os.Looper;
20 | import android.support.annotation.DrawableRes;
21 | import android.support.annotation.NonNull;
22 | import android.support.annotation.Nullable;
23 | import android.support.design.widget.Snackbar;
24 | import android.support.v4.app.Fragment;
25 | import android.support.v4.content.ContextCompat;
26 | import android.support.v7.widget.LinearLayoutManager;
27 | import android.support.v7.widget.RecyclerView;
28 | import android.util.Log;
29 | import android.view.LayoutInflater;
30 | import android.view.View;
31 | import android.view.ViewGroup;
32 | import android.view.inputmethod.InputMethodManager;
33 | import android.widget.ImageView;
34 | import android.widget.ProgressBar;
35 | import android.widget.RelativeLayout;
36 | import android.widget.Toast;
37 |
38 | import com.codingwithmitch.googledirectionstest.R;
39 | import com.codingwithmitch.googledirectionstest.adapters.UserRecyclerAdapter;
40 | import com.codingwithmitch.googledirectionstest.models.ClusterMarker;
41 | import com.codingwithmitch.googledirectionstest.models.PolylineData;
42 | import com.codingwithmitch.googledirectionstest.models.User;
43 | import com.codingwithmitch.googledirectionstest.models.UserLocation;
44 | import com.codingwithmitch.googledirectionstest.models.UserMarker;
45 | import com.codingwithmitch.googledirectionstest.util.MyClusterManagerRenderer;
46 | import com.codingwithmitch.googledirectionstest.util.ViewWeightAnimationWrapper;
47 | import com.google.android.gms.maps.CameraUpdateFactory;
48 | import com.google.android.gms.maps.GoogleMap;
49 | import com.google.android.gms.maps.MapView;
50 | import com.google.android.gms.maps.OnMapReadyCallback;
51 |
52 | import com.google.android.gms.maps.model.BitmapDescriptorFactory;
53 | import com.google.android.gms.maps.model.LatLng;
54 | import com.google.android.gms.maps.model.LatLngBounds;
55 | import com.google.android.gms.maps.model.Marker;
56 | import com.google.android.gms.maps.model.MarkerOptions;
57 | import com.google.android.gms.maps.model.Polyline;
58 | import com.google.android.gms.maps.model.PolylineOptions;
59 | import com.google.android.gms.tasks.OnCompleteListener;
60 | import com.google.android.gms.tasks.Task;
61 | import com.google.firebase.auth.FirebaseAuth;
62 | import com.google.firebase.firestore.CollectionReference;
63 | import com.google.firebase.firestore.DocumentReference;
64 | import com.google.firebase.firestore.DocumentSnapshot;
65 | import com.google.firebase.firestore.FirebaseFirestore;
66 | import com.google.gson.Gson;
67 | import com.google.gson.GsonBuilder;
68 | import com.google.maps.DirectionsApiRequest;
69 | import com.google.maps.DistanceMatrixApiRequest;
70 | import com.google.maps.GeoApiContext;
71 | import com.google.maps.PendingResult;
72 | import com.google.maps.android.clustering.Cluster;
73 | import com.google.maps.android.clustering.ClusterManager;
74 | import com.google.maps.android.clustering.algo.Algorithm;
75 | import com.google.maps.android.clustering.algo.NonHierarchicalDistanceBasedAlgorithm;
76 | import com.google.maps.internal.PolylineEncoding;
77 | import com.google.maps.model.DirectionsResult;
78 | import com.google.maps.model.DirectionsRoute;
79 | import com.google.maps.model.DistanceMatrix;
80 | import com.google.maps.model.DistanceMatrixElement;
81 | import com.google.maps.model.DistanceMatrixRow;
82 |
83 |
84 | import java.util.ArrayList;
85 | import java.util.Collection;
86 | import java.util.List;
87 | import java.util.Set;
88 |
89 |
90 | import static com.codingwithmitch.googledirectionstest.Constants.MAPVIEW_BUNDLE_KEY;
91 |
92 | public class UserListFragment extends Fragment implements
93 | OnMapReadyCallback,
94 | UserRecyclerAdapter.UserListRecyclerClickListener,
95 | View.OnClickListener,
96 | GoogleMap.OnInfoWindowClickListener,
97 | GoogleMap.OnPolylineClickListener
98 | {
99 |
100 | private static final String TAG = "UserListFragment";
101 |
102 | private static final int MAP_LAYOUT_STATE_CONTRACTED = 0;
103 | private static final int MAP_LAYOUT_STATE_EXPANDED = 1;
104 | private static final int LOCATION_UPDATE_INTERVAL = 3000;
105 |
106 | //widgets
107 | private RecyclerView mUserListRecyclerView;
108 | private MapView mMapView;
109 | private RelativeLayout mMapContainer;
110 | private ProgressBar mProgressBar;
111 |
112 |
113 | //vars
114 | private ArrayList mUserList = new ArrayList<>();
115 | private ArrayList mUserLocations = new ArrayList<>();
116 | private UserRecyclerAdapter mUserRecyclerAdapter;
117 | private GoogleMap mGoogleMap;
118 | private LatLngBounds mMapBoundary;
119 | private int mMapLayoutState = 0;
120 | private com.google.maps.model.LatLng mUserPosition ;
121 | private GeoApiContext mGeoApiContext;
122 | private ArrayList mPolyLinesData = new ArrayList<>();
123 | private ArrayList mClusterMarkers = new ArrayList<>();
124 | private Marker mSelectedMarker = null;
125 | private ArrayList mTripMarkers = new ArrayList<>();
126 | private Handler mHandler = new Handler();
127 | private Runnable mRunnable;
128 | private ClusterManager mClusterManager;
129 | private MyClusterManagerRenderer mClusterManagerRenderer;
130 |
131 |
132 | public static UserListFragment newInstance(){
133 | return new UserListFragment();
134 | }
135 |
136 | @Override
137 | public void onCreate(@Nullable Bundle savedInstanceState) {
138 | super.onCreate(savedInstanceState);
139 | Log.d(TAG, "LifeCycle Event: onCreate: called. ");
140 | if(mUserLocations.size() == 0){ // make sure the list doesn't duplicate by navigating back
141 | if(getArguments() != null){
142 | final ArrayList users = getArguments().getParcelableArrayList(getString(R.string.intent_user_list));
143 | mUserList.addAll(users);
144 |
145 | final ArrayList locations = getArguments().getParcelableArrayList(getString(R.string.intent_user_locations));
146 | mUserLocations.addAll(locations);
147 | }
148 | }
149 |
150 | }
151 |
152 | @Nullable
153 | @Override
154 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
155 | Log.d(TAG, "LifeCycle Event: onCreateView: called. ");
156 | View view = inflater.inflate(R.layout.fragment_user_list, container, false);
157 | mUserListRecyclerView = view.findViewById(R.id.user_list_recycler_view);
158 | mMapContainer = view.findViewById(R.id.map_container);
159 | mProgressBar = view.findViewById(R.id.progressBar);
160 | mMapView = view.findViewById(R.id.user_list_map);
161 | view.findViewById(R.id.btn_full_screen_map).setOnClickListener(this);
162 | view.findViewById(R.id.btn_reset_map).setOnClickListener(this);
163 |
164 | initGoogleMap(savedInstanceState);
165 | initUserListRecyclerView();
166 | hideSoftKeyboard();
167 |
168 | return view;
169 | }
170 |
171 | private void initGoogleMap(Bundle savedInstanceState){
172 |
173 | // *** IMPORTANT ***
174 | // MapView requires that the Bundle you pass contain _ONLY_ MapView SDK
175 | // objects or sub-Bundles.
176 | Bundle mapViewBundle = null;
177 | if (savedInstanceState != null) {
178 | mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
179 | }
180 | mMapView.onCreate(mapViewBundle);
181 | mMapView.getMapAsync(this);
182 |
183 | if(mGeoApiContext == null){
184 | mGeoApiContext = new GeoApiContext.Builder()
185 | .apiKey(getString(R.string.google_maps_api_key))
186 | .build();
187 | }
188 | }
189 |
190 | @Override
191 | public void onSaveInstanceState(Bundle outState) {
192 | super.onSaveInstanceState(outState);
193 |
194 | Bundle mapViewBundle = outState.getBundle(MAPVIEW_BUNDLE_KEY);
195 | if (mapViewBundle == null) {
196 | mapViewBundle = new Bundle();
197 | outState.putBundle(MAPVIEW_BUNDLE_KEY, mapViewBundle);
198 | }
199 |
200 | mMapView.onSaveInstanceState(mapViewBundle);
201 | }
202 |
203 | private void startUserLocationsRunnable(){
204 | Log.d(TAG, "startUserLocationsRunnable: starting runnable for retrieving updated locations.");
205 | mHandler.postDelayed(mRunnable = new Runnable() {
206 | @Override
207 | public void run() {
208 | // If a trip has NOT been calculated, continue updating locations
209 | Log.d(TAG, "run: polylinesdata size: " + mPolyLinesData.size());
210 | if(mPolyLinesData.size() == 0){
211 | retrieveUserLocations();
212 | mHandler.postDelayed(mRunnable, LOCATION_UPDATE_INTERVAL);
213 | }
214 | }
215 | }, LOCATION_UPDATE_INTERVAL);
216 | }
217 |
218 | private void retrieveUserLocations(){
219 | Log.d(TAG, "retrieveUserLocations: retrieving location of all users in the chatroom.");
220 |
221 | try{
222 | for(final ClusterMarker clusterMarker: mClusterMarkers){
223 |
224 | DocumentReference userLocationRef = FirebaseFirestore.getInstance()
225 | .collection(getString(R.string.collection_user_locations))
226 | .document(clusterMarker.getUser().getUser_id());
227 |
228 | userLocationRef.get().addOnCompleteListener(new OnCompleteListener() {
229 | @Override
230 | public void onComplete(@NonNull Task task) {
231 | if(task.isSuccessful()){
232 |
233 | final UserLocation updatedUserLocation = task.getResult().toObject(UserLocation.class);
234 |
235 | // update the location
236 | for (int i = 0; i < mClusterMarkers.size(); i++) {
237 | try {
238 | if (mClusterMarkers.get(i).getUser().getUser_id().equals(updatedUserLocation.getUser().getUser_id())) {
239 |
240 | LatLng updatedLatLng = new LatLng(
241 | updatedUserLocation.getGeo_point().getLatitude(),
242 | updatedUserLocation.getGeo_point().getLongitude()
243 | );
244 |
245 | mClusterMarkers.get(i).setPosition(updatedLatLng);
246 | mClusterManagerRenderer.setUpdateMarker(mClusterMarkers.get(i));
247 | }
248 |
249 |
250 | } catch (NullPointerException e) {
251 | Log.e(TAG, "retrieveUserLocations: NullPointerException: " + e.getMessage());
252 | }
253 | }
254 | }
255 | }
256 | });
257 | }
258 | }catch (IllegalStateException e){
259 | Log.e(TAG, "retrieveUserLocations: Fragment was destroyed during Firestore query. Ending query." + e.getMessage() );
260 | }
261 |
262 | }
263 |
264 | private void initUserListRecyclerView(){
265 | mUserRecyclerAdapter = new UserRecyclerAdapter(mUserList, this);
266 | mUserListRecyclerView.setAdapter(mUserRecyclerAdapter);
267 | mUserListRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
268 | }
269 |
270 |
271 | private void addMapMarkers(){
272 | showProgressBar();
273 |
274 | if(mGoogleMap != null){
275 |
276 | resetMap();
277 |
278 | if(mClusterManager == null){
279 | mClusterManager = new ClusterManager(getActivity().getApplicationContext(), mGoogleMap);
280 | }
281 | if(mClusterManagerRenderer == null){
282 | mClusterManagerRenderer = new MyClusterManagerRenderer(
283 | getActivity(),
284 | mGoogleMap,
285 | mClusterManager
286 | );
287 | mClusterManagerRenderer.setMinClusterSize(5);
288 | mClusterManager.setRenderer(mClusterManagerRenderer);
289 | }
290 | mGoogleMap.setOnInfoWindowClickListener(this);
291 |
292 | for(UserLocation userLocation: mUserLocations){
293 |
294 | Log.d(TAG, "addMapMarkers: location: " + userLocation.getGeo_point().toString());
295 | try{
296 | String snippet = "";
297 | if(userLocation.getUser().getUser_id().equals(FirebaseAuth.getInstance().getUid())){
298 | snippet = "This is you";
299 | }
300 | else{
301 | snippet = "Determine route to " + userLocation.getUser().getUsername() + "?";
302 | }
303 |
304 | int avatar = R.drawable.cwm_logo; // set the default avatar
305 | try{
306 | avatar = Integer.parseInt(userLocation.getUser().getAvatar());
307 | }catch (NumberFormatException e){
308 | Log.d(TAG, "addMapMarkers: no avatar for " + userLocation.getUser().getUsername() + ", setting default.");
309 | }
310 | ClusterMarker newClusterMarker = new ClusterMarker(
311 | new LatLng(userLocation.getGeo_point().getLatitude(), userLocation.getGeo_point().getLongitude()),
312 | userLocation.getUser().getUsername(),
313 | snippet,
314 | avatar,
315 | userLocation.getUser()
316 | );
317 | mClusterManager.addItem(newClusterMarker);
318 | mClusterMarkers.add(newClusterMarker);
319 |
320 | // set the current users location to global variable
321 | if(FirebaseAuth.getInstance().getUid().equals(userLocation.getUser().getUser_id())){
322 | mUserPosition = new com.google.maps.model.LatLng(
323 | userLocation.getGeo_point().getLatitude(),
324 | userLocation.getGeo_point().getLongitude()
325 | );
326 | }
327 | }catch (NullPointerException e){
328 | Log.e(TAG, "addMapMarkers: NullPointerException: " + e.getMessage() );
329 | }
330 |
331 | }
332 | mClusterManager.cluster();
333 |
334 | setCameraView();
335 | hideProgressBar();
336 | }
337 | }
338 |
339 |
340 | private void resetMap(){
341 | if(mGoogleMap != null) {
342 | mGoogleMap.clear();
343 |
344 | if(mClusterManager != null){
345 | mClusterManager.clearItems();
346 | }
347 |
348 | if (mClusterMarkers.size() > 0) {
349 | mClusterMarkers.clear();
350 | mClusterMarkers = new ArrayList<>();
351 | }
352 |
353 | if(mPolyLinesData.size() > 0){
354 | mPolyLinesData.clear();
355 | mPolyLinesData = new ArrayList<>();
356 | }
357 | }
358 | }
359 |
360 | /**
361 | * Determines the view boundary then sets the camera
362 | */
363 | private void setCameraView(){
364 |
365 | // Set a boundary to start
366 | double bottomBoundary = mUserPosition.lat - .1;
367 | double leftBoundary = mUserPosition.lng - .1;
368 | double topBoundary = mUserPosition.lat + .1;
369 | double rightBoundary = mUserPosition.lng + .1;
370 |
371 | mMapBoundary = new LatLngBounds(
372 | new LatLng(bottomBoundary,leftBoundary),
373 | new LatLng(topBoundary, rightBoundary)
374 | );
375 |
376 | mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mMapBoundary, 0));
377 | }
378 |
379 | @Override
380 | public void onUserSelected(int position) {
381 | Log.d(TAG, "onUserSelected: selected a user: " + mUserList.get(position).toString());
382 | String selectedUserId = mUserList.get(position).getUser_id();
383 |
384 | for(ClusterMarker clusterMarker: mClusterMarkers){
385 | if(selectedUserId.equals(clusterMarker.getUser().getUser_id())){
386 | mGoogleMap.animateCamera(
387 | CameraUpdateFactory.newLatLng(
388 | new LatLng(clusterMarker.getPosition().latitude, clusterMarker.getPosition().longitude)),
389 | 600,
390 | null
391 | );
392 | break;
393 | }
394 | }
395 | }
396 |
397 | @Override
398 | public void onClick(View v) {
399 | switch (v.getId()){
400 | case R.id.btn_full_screen_map:{
401 |
402 | if(mMapLayoutState == MAP_LAYOUT_STATE_CONTRACTED){
403 | mMapLayoutState = MAP_LAYOUT_STATE_EXPANDED;
404 | expandMapAnimation();
405 | }
406 | else if(mMapLayoutState == MAP_LAYOUT_STATE_EXPANDED){
407 | mMapLayoutState = MAP_LAYOUT_STATE_CONTRACTED;
408 | contractMapAnimation();
409 | }
410 | break;
411 | }
412 |
413 | case R.id.btn_reset_map:{
414 | addMapMarkers();
415 | startUserLocationsRunnable();
416 | break;
417 | }
418 | }
419 | }
420 |
421 | @Override
422 | public void onInfoWindowClick(final Marker marker) {
423 | Log.d(TAG, "onInfoWindowClick: marker id: " + marker.getId().replace("m", ""));
424 |
425 | if(marker.getTitle().contains("Trip #")){
426 | final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
427 | builder.setMessage("Open Google Maps?")
428 | .setCancelable(true)
429 | .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
430 | public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
431 | String latitude = String.valueOf(marker.getPosition().latitude);
432 | String longitude = String.valueOf(marker.getPosition().longitude);
433 | Uri gmmIntentUri = Uri.parse("google.navigation:q=" + latitude + "," + longitude);
434 | Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
435 | mapIntent.setPackage("com.google.android.apps.maps");
436 |
437 | try{
438 | if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) {
439 | startActivity(mapIntent);
440 | }
441 | }catch (NullPointerException e){
442 | Log.e(TAG, "onClick: NullPointerException: Couldn't open map." + e.getMessage() );
443 | Toast.makeText(getActivity(), "Couldn't open map", Toast.LENGTH_SHORT).show();
444 | }
445 |
446 | }
447 | })
448 | .setNegativeButton("No", new DialogInterface.OnClickListener() {
449 | public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
450 | dialog.cancel();
451 | }
452 | });
453 | final AlertDialog alert = builder.create();
454 | alert.show();
455 | }
456 | else{
457 |
458 | if(marker.getSnippet().equals("This is you")){
459 | marker.hideInfoWindow();
460 | }
461 | else{
462 | resetSelectedMarker();
463 |
464 | final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
465 | builder.setMessage(marker.getSnippet())
466 | .setCancelable(true)
467 | .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
468 | public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
469 | mSelectedMarker = marker;
470 | calculateDirections(marker);
471 | }
472 | })
473 | .setNegativeButton("No", new DialogInterface.OnClickListener() {
474 | public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
475 | dialog.cancel();
476 | }
477 | });
478 | final AlertDialog alert = builder.create();
479 | alert.show();
480 | }
481 | }
482 | }
483 |
484 | private void resetSelectedMarker(){
485 | if(mSelectedMarker != null){
486 | mSelectedMarker.setVisible(true);
487 | mSelectedMarker = null;
488 | removeTripMarkers();
489 | }
490 | }
491 |
492 | private void removeTripMarkers(){
493 | for(Marker marker: mTripMarkers){
494 | marker.remove();
495 | }
496 | }
497 |
498 |
499 | /**
500 | * get duration and distance of route
501 | * @param userLocation
502 | */
503 | private void calculateDurationAndDistance(UserLocation userLocation){
504 | Log.d(TAG, "calculateDurationAndDistance: calculating duration and distance.");
505 | showProgressBar();
506 |
507 | com.google.maps.model.LatLng destination = new com.google.maps.model.LatLng(
508 | userLocation.getGeo_point().getLatitude(),
509 | userLocation.getGeo_point().getLongitude()
510 | );
511 | DistanceMatrixApiRequest matrix = new DistanceMatrixApiRequest(mGeoApiContext);
512 |
513 | matrix.origins(mUserPosition);
514 | matrix.destinations(destination).setCallback(new PendingResult.Callback() {
515 | @Override
516 | public void onResult(DistanceMatrix results) {
517 | Gson gson = new GsonBuilder().setPrettyPrinting().create();
518 | Log.d(TAG, "onResult: destination addresses: " + gson.toJson(results.destinationAddresses));
519 | Log.d(TAG, "onResult: origin addresses: " + gson.toJson(results.originAddresses));
520 |
521 | for(DistanceMatrixRow row: results.rows){
522 | for(DistanceMatrixElement element: row.elements){
523 | Log.d(TAG, "onResult: element: " + element.toString());
524 | }
525 | }
526 | hideProgressBar();
527 | }
528 |
529 | @Override
530 | public void onFailure(Throwable e) {
531 | Log.e(TAG, "onFailure: " + e.getMessage() );
532 | hideProgressBar();
533 | }
534 | });
535 | }
536 |
537 | private void calculateDirections(Marker marker){
538 | Log.d(TAG, "calculateDirections: calculating directions.");
539 |
540 | com.google.maps.model.LatLng destination = new com.google.maps.model.LatLng(
541 | marker.getPosition().latitude,
542 | marker.getPosition().longitude
543 | );
544 | DirectionsApiRequest directions = new DirectionsApiRequest(mGeoApiContext);
545 |
546 | directions.alternatives(true);
547 | directions.origin(mUserPosition);
548 | Log.d(TAG, "calculateDirections: destination: " + destination.toString());
549 | directions.destination(destination).setCallback(new PendingResult.Callback() {
550 | @Override
551 | public void onResult(DirectionsResult result) {
552 |
553 | addPolyLinesToMap(result);
554 |
555 | hideProgressBar();
556 | }
557 |
558 | @Override
559 | public void onFailure(Throwable e) {
560 | Log.e(TAG, "onFailure: " + e.getMessage() );
561 | hideProgressBar();
562 | }
563 | });
564 | }
565 |
566 |
567 | private void addPolyLinesToMap(final DirectionsResult result){
568 | new Handler(Looper.getMainLooper()).post(new Runnable() {
569 | @Override
570 | public void run() {
571 | Log.d(TAG, "run: result routes: " + result.routes.length);
572 | if(mPolyLinesData.size() > 0){
573 | for(PolylineData polylineData: mPolyLinesData){
574 | polylineData.getPolyline().remove();
575 | }
576 | mPolyLinesData.clear();
577 | mPolyLinesData = new ArrayList<>();
578 | }
579 |
580 | double duration = 999999999;
581 | for(DirectionsRoute route: result.routes){
582 | Log.d(TAG, "run: leg: " + route.legs[0].toString());
583 | List decodedPath = PolylineEncoding.decode(route.overviewPolyline.getEncodedPath());
584 |
585 | List newDecodedPath = new ArrayList<>();
586 |
587 | // This loops through all the LatLng coordinates of ONE polyline.
588 | // Uncomment the log for a demonstration
589 | for(com.google.maps.model.LatLng latLng: decodedPath){
590 |
591 | // Log.d(TAG, "run: latlng: " + latLng.toString());
592 |
593 | newDecodedPath.add(new LatLng(
594 | latLng.lat,
595 | latLng.lng
596 | ));
597 | }
598 | Polyline polyline = mGoogleMap.addPolyline(new PolylineOptions().addAll(newDecodedPath));
599 | polyline.setColor(ContextCompat.getColor(getActivity(), R.color.darkGrey));
600 | polyline.setClickable(true);
601 | mPolyLinesData.add(new PolylineData(polyline, route.legs[0]));
602 |
603 | // highlight the fastest route and adjust camera
604 | double tempDuration = route.legs[0].duration.inSeconds;
605 | if(tempDuration < duration){
606 | duration = tempDuration;
607 | onPolylineClick(polyline);
608 | zoomRoute(polyline.getPoints());
609 | }
610 |
611 | // hide the selected marker while polylines are visible
612 | mSelectedMarker.setVisible(false);
613 | }
614 | }
615 | });
616 | }
617 |
618 |
619 | public void zoomRoute(List lstLatLngRoute) {
620 |
621 | if (mGoogleMap == null || lstLatLngRoute == null || lstLatLngRoute.isEmpty()) return;
622 |
623 | LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
624 | for (LatLng latLngPoint : lstLatLngRoute)
625 | boundsBuilder.include(latLngPoint);
626 |
627 | int routePadding = 120;
628 | LatLngBounds latLngBounds = boundsBuilder.build();
629 |
630 | mGoogleMap.animateCamera(
631 | CameraUpdateFactory.newLatLngBounds(latLngBounds, routePadding),
632 | 600,
633 | null
634 | );
635 | }
636 |
637 |
638 |
639 | @Override
640 | public void onPolylineClick(Polyline polyline) {
641 |
642 | int index = 0;
643 | for(PolylineData polylineData: mPolyLinesData){
644 | index++;
645 | Log.d(TAG, "onPolylineClick: toString: " + polylineData.toString());
646 | if(polyline.getId().equals(polylineData.getPolyline().getId())){
647 | polylineData.getPolyline().setColor(ContextCompat.getColor(getActivity(), R.color.blue1));
648 | polylineData.getPolyline().setZIndex(1);
649 | Log.d(TAG, "onPolylineClick: data: " + polylineData.getLeg().endLocation);
650 |
651 | LatLng endLocation = new LatLng(
652 | polylineData.getLeg().endLocation.lat,
653 | polylineData.getLeg().endLocation.lng
654 | );
655 |
656 | Marker marker = mGoogleMap.addMarker(new MarkerOptions()
657 | .position(endLocation)
658 | .title("Trip #" + index)
659 | .snippet("Duration: " + polylineData.getLeg().duration
660 | + "\n" + "Distance: " + polylineData.getLeg().distance
661 | ));
662 |
663 | mTripMarkers.add(marker);
664 |
665 | marker.showInfoWindow();
666 | }
667 | else{
668 | polylineData.getPolyline().setColor(ContextCompat.getColor(getActivity(), R.color.darkGrey));
669 | polylineData.getPolyline().setZIndex(0);
670 | }
671 | }
672 | }
673 |
674 | private void stopLocationUpdates(){
675 | mHandler.removeCallbacks(mRunnable);
676 | }
677 |
678 | @Override
679 | public void onResume() {
680 | Log.d(TAG, "LifeCycle Event: onResume: called.");
681 | mMapView.onResume();
682 | startUserLocationsRunnable(); // update user locations every 'LOCATION_UPDATE_INTERVAL'
683 | super.onResume();
684 | }
685 |
686 | @Override
687 | public void onStart() {
688 | Log.d(TAG, "LifeCycle Event: onStart: called.");
689 | mMapView.onStart();
690 | super.onStart();
691 | }
692 |
693 | @Override
694 | public void onStop() {
695 | Log.d(TAG, "LifeCycle Event: onStop: called.");
696 | mMapView.onStop();
697 | super.onStop();
698 | }
699 |
700 | @Override
701 | public void onMapReady(GoogleMap map) {
702 | Log.d(TAG, "LifeCycle Event: onMapReady: called.");
703 | mGoogleMap = map;
704 | // initialMapAnimation();
705 | addMapMarkers();
706 | // mGoogleMap.setTrafficEnabled(true);
707 | mGoogleMap.setOnPolylineClickListener(this);
708 | }
709 |
710 | @Override
711 | public void onPause() {
712 | Log.d(TAG, "LifeCycle Event: onPause: called.");
713 | stopLocationUpdates(); // stop updating user locations
714 | super.onPause();
715 | mMapView.onPause();
716 | }
717 |
718 | @Override
719 | public void onDestroy() {
720 | Log.d(TAG, "LifeCycle Event: onDestroy: called.");
721 | super.onDestroy();
722 | mMapView.onDestroy();
723 | }
724 |
725 | @Override
726 | public void onLowMemory() {
727 | Log.d(TAG, "LifeCycle Event: onLowMemory: called.");
728 | mMapView.onLowMemory();
729 | super.onLowMemory();
730 | }
731 |
732 |
733 | private void hideSoftKeyboard(){
734 | //Hide the soft keyboard
735 | InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
736 | imm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
737 | }
738 |
739 | private void showProgressBar(){
740 | new Handler(Looper.getMainLooper()).post(new Runnable() {
741 | @Override
742 | public void run() {
743 | mProgressBar.setVisibility(View.VISIBLE);
744 | }
745 | });
746 | }
747 |
748 | private void hideProgressBar(){
749 | new Handler(Looper.getMainLooper()).post(new Runnable() {
750 | @Override
751 | public void run() {
752 | mProgressBar.setVisibility(View.GONE);
753 | }
754 | });
755 | }
756 |
757 | private void initialMapAnimation(){
758 | ViewWeightAnimationWrapper mapAnimationWrapper = new ViewWeightAnimationWrapper(mMapContainer);
759 | ObjectAnimator mapAnimation = ObjectAnimator.ofFloat(mapAnimationWrapper,
760 | "weight",
761 | 0,
762 | 50);
763 | mapAnimation.setDuration(800);
764 | }
765 |
766 | private void expandMapAnimation(){
767 | ViewWeightAnimationWrapper mapAnimationWrapper = new ViewWeightAnimationWrapper(mMapContainer);
768 | ObjectAnimator mapAnimation = ObjectAnimator.ofFloat(mapAnimationWrapper,
769 | "weight",
770 | 50,
771 | 100);
772 | mapAnimation.setDuration(800);
773 |
774 | ViewWeightAnimationWrapper recyclerAnimationWrapper = new ViewWeightAnimationWrapper(mUserListRecyclerView);
775 | ObjectAnimator recyclerAnimation = ObjectAnimator.ofFloat(recyclerAnimationWrapper,
776 | "weight",
777 | 50,
778 | 0);
779 | recyclerAnimation.setDuration(800);
780 |
781 | recyclerAnimation.start();
782 | mapAnimation.start();
783 | }
784 |
785 | private void contractMapAnimation(){
786 | ViewWeightAnimationWrapper mapAnimationWrapper = new ViewWeightAnimationWrapper(mMapContainer);
787 | ObjectAnimator mapAnimation = ObjectAnimator.ofFloat(mapAnimationWrapper,
788 | "weight",
789 | 100,
790 | 50);
791 | mapAnimation.setDuration(800);
792 |
793 | ViewWeightAnimationWrapper recyclerAnimationWrapper = new ViewWeightAnimationWrapper(mUserListRecyclerView);
794 | ObjectAnimator recyclerAnimation = ObjectAnimator.ofFloat(recyclerAnimationWrapper,
795 | "weight",
796 | 0,
797 | 50);
798 | recyclerAnimation.setDuration(800);
799 |
800 | recyclerAnimation.start();
801 | mapAnimation.start();
802 | }
803 |
804 | }
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/util/Check.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.util;
2 |
3 | public class Check {
4 |
5 | /**
6 | * Return true if the @param is null
7 | * @param string
8 | * @return
9 | */
10 | public static boolean isEmpty(String string){
11 | return string.equals("");
12 | }
13 |
14 | /**
15 | * Return true if @param 's1' matches @param 's2'
16 | * @param s1
17 | * @param s2
18 | * @return
19 | */
20 | public static boolean doStringsMatch(String s1, String s2){
21 | return s1.equals(s2);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/util/MyClusterManagerRenderer.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.util;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.graphics.Bitmap;
8 | import android.graphics.Color;
9 | import android.graphics.drawable.BitmapDrawable;
10 | import android.graphics.drawable.ColorDrawable;
11 | import android.graphics.drawable.Drawable;
12 | import android.net.Uri;
13 | import android.util.Log;
14 | import android.view.LayoutInflater;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.widget.ImageView;
18 | import android.widget.Toast;
19 |
20 | import com.bumptech.glide.Glide;
21 | import com.bumptech.glide.request.RequestOptions;
22 | import com.codingwithmitch.googledirectionstest.R;
23 | import com.codingwithmitch.googledirectionstest.models.ClusterMarker;
24 | import com.codingwithmitch.googledirectionstest.models.UserLocation;
25 | import com.google.android.gms.maps.GoogleMap;
26 | import com.google.android.gms.maps.model.BitmapDescriptorFactory;
27 | import com.google.android.gms.maps.model.Marker;
28 | import com.google.android.gms.maps.model.MarkerOptions;
29 | import com.google.firebase.auth.FirebaseAuth;
30 | import com.google.maps.android.clustering.Cluster;
31 | import com.google.maps.android.clustering.ClusterManager;
32 | import com.google.maps.android.clustering.view.DefaultClusterRenderer;
33 | import com.google.maps.android.ui.IconGenerator;
34 |
35 | import java.util.ArrayList;
36 | import java.util.Iterator;
37 | import java.util.List;
38 |
39 | public class MyClusterManagerRenderer extends DefaultClusterRenderer
40 | {
41 |
42 | private static final String TAG = "MyClusterManagerRendere";
43 |
44 | private final IconGenerator iconGenerator;
45 | private final IconGenerator clusterIconGenerator;
46 | private final ImageView imageView;
47 | private final ImageView clusterImageView;
48 | private final int markerWidth;
49 | private final int markerHeight;
50 | private Context context;
51 |
52 | public MyClusterManagerRenderer(Context context, GoogleMap googleMap,
53 | ClusterManager clusterManager) {
54 |
55 | super(context, googleMap, clusterManager);
56 |
57 | this.context = context.getApplicationContext();
58 |
59 | // initialize cluster icon generator
60 | clusterIconGenerator = new IconGenerator(context.getApplicationContext());
61 | View clusterView = LayoutInflater.from(context).inflate(R.layout.layout_custom_marker, null);
62 | clusterIconGenerator.setContentView(clusterView);
63 | clusterImageView = clusterView.findViewById(R.id.profile_image);
64 |
65 | // initialize cluster item icon generator
66 | iconGenerator = new IconGenerator(context.getApplicationContext());
67 | imageView = new ImageView(context.getApplicationContext());
68 | markerWidth = (int) context.getResources().getDimension(R.dimen.custom_marker_image);
69 | markerHeight = (int) context.getResources().getDimension(R.dimen.custom_marker_image);
70 | imageView.setLayoutParams(new ViewGroup.LayoutParams(markerWidth, markerHeight));
71 | int padding = (int) context.getResources().getDimension(R.dimen.custom_marker_padding);
72 | imageView.setPadding(padding, padding, padding, padding);
73 | iconGenerator.setContentView(imageView);
74 |
75 | }
76 |
77 | @Override
78 | protected void onBeforeClusterItemRendered(ClusterMarker item, MarkerOptions markerOptions) {
79 |
80 | imageView.setImageResource(item.getIconPicture());
81 | Bitmap icon = iconGenerator.makeIcon();
82 | markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(item.getTitle());
83 |
84 | }
85 |
86 | @Override
87 | protected void onBeforeClusterRendered(Cluster cluster, MarkerOptions markerOptions) {
88 |
89 | Iterator iterator = cluster.getItems().iterator();
90 |
91 | clusterImageView.setImageResource(iterator.next().getIconPicture());
92 | Bitmap icon = clusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
93 | markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
94 | }
95 |
96 | public void setUpdateMarker(ClusterMarker clusterMarker) {
97 | Marker marker = getMarker(clusterMarker);
98 | if (marker != null) {
99 | marker.setPosition(clusterMarker.getPosition());
100 | }
101 | }
102 |
103 | @Override
104 | protected boolean shouldRenderAsCluster(Cluster cluster) {
105 | return false;
106 | }
107 | }
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codingwithmitch/googledirectionstest/util/ViewWeightAnimationWrapper.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest.util;
2 |
3 | import android.view.View;
4 | import android.widget.LinearLayout;
5 |
6 | public class ViewWeightAnimationWrapper {
7 | private View view;
8 |
9 | public ViewWeightAnimationWrapper(View view) {
10 | if (view.getLayoutParams() instanceof LinearLayout.LayoutParams) {
11 | this.view = view;
12 | } else {
13 | throw new IllegalArgumentException("The view should have LinearLayout as parent");
14 | }
15 | }
16 |
17 | public void setWeight(float weight) {
18 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
19 | params.weight = weight;
20 | view.getParent().requestLayout();
21 | }
22 |
23 | public float getWeight() {
24 | return ((LinearLayout.LayoutParams) view.getLayoutParams()).weight;
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_in_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_in_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_out_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_out_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cartman_cop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/cartman_cop.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chef.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/chef.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cwm_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/cwm_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/eric_cartman.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/eric_cartman.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/grey_border_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check_green_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_full_screen_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_refresh_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ike.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/ike.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/kyle.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/kyle.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/satan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/satan.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/theme_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
6 |
7 |
9 |
12 |
13 |
14 |
15 |
16 | -
17 |
18 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tweek.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/drawable/tweek.jpg
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_chatroom.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
39 |
40 |
51 |
52 |
53 |
54 |
55 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
19 |
20 |
21 |
29 |
30 |
31 |
40 |
41 |
50 |
51 |
55 |
56 |
57 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
26 |
27 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_profile.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
15 |
21 |
22 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_register.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
13 |
14 |
15 |
20 |
21 |
30 |
31 |
32 |
40 |
41 |
42 |
50 |
51 |
59 |
60 |
61 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_image_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_user_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
21 |
22 |
23 |
24 |
29 |
30 |
35 |
36 |
47 |
48 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_chat_message_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_chatroom_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_custom_marker.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_image_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_user_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/chatroom_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #af0a0a
8 | #c40909
9 | #e50909
10 | #FF8333
11 | #29CF40
12 | #66a3ff
13 | #0033cc
14 | #4d94ff
15 | #00c4cc
16 | #00aab1
17 | #007f85
18 | #fff
19 | #00ffffff
20 | #a6a6a6
21 | #c3c3c3
22 | #f2f2f2
23 | #8f737373
24 | #737373
25 | #000
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 50dp
4 | 2dp
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 | 16dp
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GoogleDirectionsTest
3 |
4 | AIzaSyB8ONAh1kZ6ojNOFWARw4VMj8i91tyaa90
5 |
6 |
7 | Email
8 | Password (optional)
9 | Sign in or register
10 | Sign in
11 | Sign out
12 | This email address is invalid
13 | This password is too short
14 | This password is incorrect
15 | This field is required
16 | Resend Verification Email
17 | Forgot Password
18 | Register
19 | Sign In
20 | Password
21 | Tabian Consulting Logo
22 | Email Registration
23 | Email
24 | Confirm Password
25 |
26 |
27 | Users
28 | Chatrooms
29 | Chat Messages
30 | User List
31 | User Locations
32 |
33 |
34 | intent_chatroom
35 | intent_user_list
36 | intent_user_locations
37 | intent_location
38 |
39 |
40 | gps_location
41 |
42 |
43 |
44 | User List
45 | Image List
46 |
47 |
48 | Create Chatroom
49 | Leave chatroom
50 | User list
51 | Profile
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/test/java/com/codingwithmitch/googledirectionstest/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.codingwithmitch.googledirectionstest;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.3'
11 | classpath 'com.google.gms:google-services:4.0.1'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/GoogleMaps2018-Test/fbc16ca897ced730deffd96a7718c879e1a9c691/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 09 09:58:21 PDT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------