Browse Source

init

tags/v1.0.0
Robin Thoni 7 years ago
commit
ee0dee82fa
50 changed files with 1593 additions and 0 deletions
  1. 8
    0
      .gitignore
  2. 1
    0
      app/.gitignore
  3. 33
    0
      app/build.gradle
  4. 17
    0
      app/proguard-rules.pro
  5. 13
    0
      app/src/androidTest/java/com/rthoni/stssaguenay/ApplicationTest.java
  6. 34
    0
      app/src/main/AndroidManifest.xml
  7. BIN
      app/src/main/ic_launcher-web.png
  8. 22
    0
      app/src/main/java/com/rthoni/stssaguenay/business/STSBusiness.java
  9. 19
    0
      app/src/main/java/com/rthoni/stssaguenay/business/StopsBusiness.java
  10. 24
    0
      app/src/main/java/com/rthoni/stssaguenay/business/Utils.java
  11. 149
    0
      app/src/main/java/com/rthoni/stssaguenay/dataaccess/LuPromise.java
  12. 146
    0
      app/src/main/java/com/rthoni/stssaguenay/dataaccess/LuRequest.java
  13. 74
    0
      app/src/main/java/com/rthoni/stssaguenay/dataaccess/StopsDataAccess.java
  14. 27
    0
      app/src/main/java/com/rthoni/stssaguenay/dbo/LuDataAccessConfigDbo.java
  15. 26
    0
      app/src/main/java/com/rthoni/stssaguenay/dbo/LuDbo.java
  16. 56
    0
      app/src/main/java/com/rthoni/stssaguenay/dbo/StopsDbo.java
  17. 87
    0
      app/src/main/java/com/rthoni/stssaguenay/ui/activities/MainActivity.java
  18. 36
    0
      app/src/main/java/com/rthoni/stssaguenay/ui/activities/StopPickerActivity.java
  19. 31
    0
      app/src/main/java/com/rthoni/stssaguenay/ui/fragments/HomeFragment.java
  20. 195
    0
      app/src/main/java/com/rthoni/stssaguenay/ui/fragments/StopPickerFragment.java
  21. 20
    0
      app/src/main/java/com/rthoni/stssaguenay/ui/fragments/StopRoutePickerFragment.java
  22. 9
    0
      app/src/main/res/drawable/ic_add_black_24dp.xml
  23. 35
    0
      app/src/main/res/layout/activity_main.xml
  24. 19
    0
      app/src/main/res/layout/activity_stop_picker.xml
  25. 21
    0
      app/src/main/res/layout/content_main.xml
  26. 28
    0
      app/src/main/res/layout/fragment_home.xml
  27. 31
    0
      app/src/main/res/layout/fragment_stop_picker.xml
  28. 31
    0
      app/src/main/res/layout/fragment_stop_route_picker.xml
  29. 13
    0
      app/src/main/res/layout/simple_recycler_view_item.xml
  30. 10
    0
      app/src/main/res/menu/menu_main.xml
  31. 9
    0
      app/src/main/res/menu/menu_stop_picker.xml
  32. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  33. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  34. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  35. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  36. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  37. 9
    0
      app/src/main/res/values-v21/styles.xml
  38. 6
    0
      app/src/main/res/values-w820dp/dimens.xml
  39. 6
    0
      app/src/main/res/values/colors.xml
  40. 6
    0
      app/src/main/res/values/dimens.xml
  41. 7
    0
      app/src/main/res/values/strings.xml
  42. 20
    0
      app/src/main/res/values/styles.xml
  43. 15
    0
      app/src/test/java/com/rthoni/stssaguenay/ExampleUnitTest.java
  44. 25
    0
      build.gradle
  45. 18
    0
      gradle.properties
  46. BIN
      gradle/wrapper/gradle-wrapper.jar
  47. 6
    0
      gradle/wrapper/gradle-wrapper.properties
  48. 160
    0
      gradlew
  49. 90
    0
      gradlew.bat
  50. 1
    0
      settings.gradle

+ 8
- 0
.gitignore View File

@@ -0,0 +1,8 @@
1
+*.iml
2
+.gradle
3
+/local.properties
4
+/.idea
5
+.DS_Store
6
+/build
7
+/captures
8
+*.apk

+ 1
- 0
app/.gitignore View File

@@ -0,0 +1 @@
1
+/build

+ 33
- 0
app/build.gradle View File

@@ -0,0 +1,33 @@
1
+apply plugin: 'com.android.application'
2
+apply plugin: 'android-apt'
3
+
4
+
5
+android {
6
+    compileSdkVersion 23
7
+    buildToolsVersion "23.0.3"
8
+
9
+    defaultConfig {
10
+        applicationId "com.rthoni.stssaguenay"
11
+        minSdkVersion 15
12
+        targetSdkVersion 23
13
+        versionCode 1
14
+        versionName "1.0"
15
+    }
16
+    buildTypes {
17
+        release {
18
+            minifyEnabled false
19
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20
+        }
21
+    }
22
+}
23
+
24
+dependencies {
25
+    compile fileTree(dir: 'libs', include: ['*.jar'])
26
+    testCompile 'junit:junit:4.12'
27
+    compile 'com.android.support:appcompat-v7:23.4.0'
28
+    compile 'com.android.support:support-annotations:23.4.0'
29
+    compile 'com.android.support:design:23.4.0'
30
+    compile 'com.android.volley:volley:1.0.0'
31
+    compile 'com.jakewharton:butterknife:8.0.1'
32
+    apt 'com.jakewharton:butterknife-compiler:8.0.1'
33
+}

+ 17
- 0
app/proguard-rules.pro View File

@@ -0,0 +1,17 @@
1
+# Add project specific ProGuard rules here.
2
+# By default, the flags in this file are appended to flags specified
3
+# in /home/robin/Android/Sdk/tools/proguard/proguard-android.txt
4
+# You can edit the include path and order by changing the proguardFiles
5
+# directive in build.gradle.
6
+#
7
+# For more details, see
8
+#   http://developer.android.com/guide/developing/tools/proguard.html
9
+
10
+# Add any project specific keep options here:
11
+
12
+# If your project uses WebView with JS, uncomment the following
13
+# and specify the fully qualified class name to the JavaScript interface
14
+# class:
15
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16
+#   public *;
17
+#}

+ 13
- 0
app/src/androidTest/java/com/rthoni/stssaguenay/ApplicationTest.java View File

@@ -0,0 +1,13 @@
1
+package com.rthoni.stssaguenay;
2
+
3
+import android.app.Application;
4
+import android.test.ApplicationTestCase;
5
+
6
+/**
7
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
8
+ */
9
+public class ApplicationTest extends ApplicationTestCase<Application> {
10
+    public ApplicationTest() {
11
+        super(Application.class);
12
+    }
13
+}

+ 34
- 0
app/src/main/AndroidManifest.xml View File

@@ -0,0 +1,34 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+          package="com.rthoni.stssaguenay">
4
+
5
+    <uses-permission android:name="android.permission.INTERNET"/>
6
+
7
+    <application
8
+        android:allowBackup="true"
9
+        android:icon="@mipmap/ic_launcher"
10
+        android:label="@string/app_name"
11
+        android:supportsRtl="true"
12
+        android:theme="@style/AppTheme">
13
+        <activity
14
+            android:name=".ui.activities.MainActivity"
15
+            android:label="@string/app_name"
16
+            android:theme="@style/AppTheme.NoActionBar">
17
+            <intent-filter>
18
+                <action android:name="android.intent.action.MAIN"/>
19
+
20
+                <category android:name="android.intent.category.LAUNCHER"/>
21
+            </intent-filter>
22
+        </activity>
23
+
24
+        <activity
25
+            android:name=".ui.activities.StopPickerActivity"
26
+            android:label="@string/title_activity_stop_picker"
27
+            android:parentActivityName=".ui.activities.MainActivity">
28
+            <meta-data
29
+                android:name="android.support.PARENT_ACTIVITY"
30
+                android:value="com.rthoni.stssaguenay.ui.activities.MainActivity"/>
31
+        </activity>
32
+    </application>
33
+
34
+</manifest>

BIN
app/src/main/ic_launcher-web.png View File


+ 22
- 0
app/src/main/java/com/rthoni/stssaguenay/business/STSBusiness.java View File

@@ -0,0 +1,22 @@
1
+package com.rthoni.stssaguenay.business;
2
+
3
+import com.rthoni.stssaguenay.dbo.LuDataAccessConfigDbo;
4
+
5
+/**
6
+ * Created by robin on 9/29/16.
7
+ */
8
+public class STSBusiness {
9
+
10
+    public static int UNKNOWN_PARAM = 118;
11
+
12
+    private static LuDataAccessConfigDbo _config = null;
13
+
14
+    public static LuDataAccessConfigDbo getConfig()
15
+    {
16
+        if (_config == null) {
17
+            _config = new LuDataAccessConfigDbo();
18
+            _config.setBaseUrl("http://horaires.sts.saguenay.ca/api/");
19
+        }
20
+        return _config;
21
+    }
22
+}

+ 19
- 0
app/src/main/java/com/rthoni/stssaguenay/business/StopsBusiness.java View File

@@ -0,0 +1,19 @@
1
+package com.rthoni.stssaguenay.business;
2
+
3
+import com.rthoni.stssaguenay.dataaccess.LuPromise;
4
+import com.rthoni.stssaguenay.dataaccess.StopsDataAccess;
5
+import com.rthoni.stssaguenay.dbo.LuDataAccessConfigDbo;
6
+import com.rthoni.stssaguenay.dbo.StopsDbo;
7
+
8
+import java.util.List;
9
+
10
+/**
11
+ * Created by robin on 9/29/16.
12
+ */
13
+public class StopsBusiness {
14
+
15
+    public static LuPromise<List<StopsDbo>> getAll(LuDataAccessConfigDbo config, int unknownParam)
16
+    {
17
+        return StopsDataAccess.getAll(config, unknownParam);
18
+    }
19
+}

+ 24
- 0
app/src/main/java/com/rthoni/stssaguenay/business/Utils.java View File

@@ -0,0 +1,24 @@
1
+package com.rthoni.stssaguenay.business;
2
+
3
+import java.text.Normalizer;
4
+
5
+/**
6
+ * Created by robin on 9/29/16.
7
+ */
8
+public class Utils {
9
+
10
+    public static String unaccent(String s) {
11
+        String normalized = Normalizer.normalize(s, Normalizer.Form.NFD);
12
+        return normalized.replaceAll("[^\\p{ASCII}]", "");
13
+    }
14
+
15
+    public static String normalizeString(String str)
16
+    {
17
+        return unaccent(str).toLowerCase().replaceAll("[^a-z0-9]", " ").replaceAll(" +", " ");
18
+    }
19
+
20
+    public static boolean stringMatch(String str1, String str2)
21
+    {
22
+        return normalizeString(str1).contains(str2);
23
+    }
24
+}

+ 149
- 0
app/src/main/java/com/rthoni/stssaguenay/dataaccess/LuPromise.java View File

@@ -0,0 +1,149 @@
1
+package com.rthoni.stssaguenay.dataaccess;
2
+
3
+/**
4
+ *
5
+ * Created by robin on 11/27/15.
6
+ */
7
+public class LuPromise<T> {
8
+
9
+    public interface LuConsumer<T> {
10
+        void execute(T data);
11
+    }
12
+
13
+    public interface LuConverter<T, T2> {
14
+        T2 convert(T data);
15
+    }
16
+
17
+    public static class LuPromiseError {
18
+
19
+        public LuPromiseError()
20
+        {
21
+
22
+        }
23
+
24
+        public LuPromiseError(String error, int statusCode)
25
+        {
26
+            _error = error;
27
+            _statusCode = statusCode;
28
+        }
29
+
30
+        public String getError() {
31
+            return _error;
32
+        }
33
+
34
+        public void setError(String error) {
35
+            _error = error;
36
+        }
37
+
38
+        public int getStatusCode() {
39
+            return _statusCode;
40
+        }
41
+
42
+        public void setStatusCode(int statusCode) {
43
+            _statusCode = statusCode;
44
+        }
45
+
46
+        private String _error;
47
+
48
+        private int _statusCode;
49
+
50
+        @Override
51
+        public String toString() {
52
+            return _error + " (HTTP Code : " + _statusCode + ")";
53
+        }
54
+    }
55
+
56
+    public enum LuPromiseStatus {
57
+        Running,
58
+        Resolved,
59
+        Failed
60
+    }
61
+
62
+    private LuConsumer<T> _onSuccess = new LuConsumer<T>() {
63
+        @Override
64
+        public void execute(T data) {
65
+        }
66
+    };
67
+
68
+    private LuConsumer<LuPromiseError> _onFailed = new LuConsumer<LuPromiseError>() {
69
+        @Override
70
+        public void execute(LuPromiseError data) {
71
+        }
72
+    };
73
+
74
+    private LuPromiseStatus _status = LuPromiseStatus.Running;
75
+
76
+    private T _data = null;
77
+
78
+    private LuPromiseError _error = null;
79
+
80
+    public LuPromise<T> then(LuConsumer<T> onSuccess, LuConsumer<LuPromiseError> onFailed)
81
+    {
82
+        _onFailed = onFailed;
83
+        if (_status == LuPromiseStatus.Failed) {
84
+            _onFailed.execute(_error);
85
+        }
86
+        return then(onSuccess);
87
+    }
88
+
89
+    public LuPromise<T> then(LuConsumer<T> onSuccess)
90
+    {
91
+        _onSuccess = onSuccess;
92
+        if (_status == LuPromiseStatus.Resolved) {
93
+            _onSuccess.execute(_data);
94
+        }
95
+        return this;
96
+    }
97
+
98
+    public void resolve(T data)
99
+    {
100
+        if (_status == LuPromiseStatus.Running) {
101
+            _data = data;
102
+            _error = null;
103
+            _status = LuPromiseStatus.Resolved;
104
+            _onSuccess.execute(_data);
105
+        }
106
+    }
107
+
108
+    public void reject(LuPromiseError error)
109
+    {
110
+        if (_status == LuPromiseStatus.Running) {
111
+            _data = null;
112
+            _error = error;
113
+            _status = LuPromiseStatus.Failed;
114
+            _onFailed.execute(_error);
115
+        }
116
+    }
117
+
118
+    public <T2> LuPromise<T2> map(final LuConverter<T, T2> converter)
119
+    {
120
+        final LuPromise<T2> promise = new LuPromise<>();
121
+        then(new LuConsumer<T>() {
122
+            @Override
123
+            public void execute(T data) {
124
+                promise.resolve(converter.convert(data));
125
+            }
126
+        }, new LuConsumer<LuPromiseError>() {
127
+            @Override
128
+            public void execute(LuPromiseError error) {
129
+                promise.reject(error);
130
+            }
131
+        });
132
+        return promise;
133
+    }
134
+
135
+    public LuConsumer<LuPromiseError> rejectConsumer()
136
+    {
137
+        return new LuConsumer<LuPromiseError>() {
138
+            @Override
139
+            public void execute(LuPromiseError error) {
140
+                reject(error);
141
+            }
142
+        };
143
+    }
144
+
145
+    public LuPromiseStatus getStatus()
146
+    {
147
+        return _status;
148
+    }
149
+}

+ 146
- 0
app/src/main/java/com/rthoni/stssaguenay/dataaccess/LuRequest.java View File

@@ -0,0 +1,146 @@
1
+package com.rthoni.stssaguenay.dataaccess;
2
+
3
+import android.content.Context;
4
+import android.net.Uri;
5
+
6
+import com.android.volley.Request;
7
+import com.android.volley.RequestQueue;
8
+import com.android.volley.Response;
9
+import com.android.volley.VolleyError;
10
+import com.android.volley.toolbox.StringRequest;
11
+import com.android.volley.toolbox.Volley;
12
+import com.rthoni.stssaguenay.dbo.LuDataAccessConfigDbo;
13
+import com.rthoni.stssaguenay.dbo.LuDbo;
14
+
15
+import org.json.JSONObject;
16
+
17
+import java.util.HashMap;
18
+import java.util.Map;
19
+
20
+/**
21
+ *
22
+ * Created by robin on 11/27/15.
23
+ */
24
+public class LuRequest {
25
+
26
+    private static RequestQueue _requestQueue = null;
27
+
28
+    public static void init(Context ctx)
29
+    {
30
+        _requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
31
+    }
32
+
33
+    protected static <T extends LuDbo> Response.Listener<String> getListener(final Class<T> type, final LuPromise<T> promise)
34
+    {
35
+        return new Response.Listener<String>()
36
+        {
37
+            @Override
38
+            public void onResponse(String response) {
39
+                try {
40
+                    T dbo = type.newInstance();
41
+                    try {
42
+                        JSONObject json = new JSONObject(response);
43
+                        dbo.fromJson(json);
44
+                        promise.resolve(dbo);
45
+                    } catch (Exception e)
46
+                    {
47
+                        e.printStackTrace();
48
+                        promise.reject(new LuPromise.LuPromiseError("Failed to parse success server response", 200));
49
+                    }
50
+                } catch (Exception e) {
51
+                    e.printStackTrace();
52
+                    promise.reject(new LuPromise.LuPromiseError("Failed to initialize server response", 200));
53
+                }
54
+            }
55
+        };
56
+    }
57
+
58
+    protected static <T extends LuDbo> Response.ErrorListener getErrorListener(final LuPromise<T> promise)
59
+    {
60
+        return new Response.ErrorListener() {
61
+            @Override
62
+            public void onErrorResponse(VolleyError error) {
63
+                int code = 0;
64
+                if (error != null && error.networkResponse != null)
65
+                {
66
+                    code = error.networkResponse.statusCode;
67
+                }
68
+                try
69
+                {
70
+                    JSONObject data = new JSONObject(new String(error.networkResponse.data));
71
+                    promise.reject(new LuPromise.LuPromiseError(data.getString("messages"), code));//TODO messages is an array
72
+                } catch (Exception e)
73
+                {
74
+                    promise.reject(new LuPromise.LuPromiseError(e.getMessage(), code));
75
+                }
76
+                promise.reject(new LuPromise.LuPromiseError(error.toString(), code));
77
+            }
78
+        };
79
+    }
80
+
81
+    protected static <T extends LuDbo> LuPromise<T> request(final LuDataAccessConfigDbo config,
82
+                                                            int method, Class<T> type, String url,
83
+                                                            final HashMap<String, String> params)
84
+    {
85
+        LuPromise<T> promise = new LuPromise<>();
86
+        StringRequest request = new StringRequest(method, config.getBaseUrl() + url,
87
+                getListener(type, promise), getErrorListener(promise))
88
+        {
89
+            @Override
90
+            public String getBodyContentType() {
91
+                return "application/x-www-form-urlencoded; charset=UTF-8";
92
+            }
93
+
94
+            @Override
95
+            protected Map<String, String> getParams() {
96
+                return params;
97
+            }
98
+
99
+            @Override
100
+            public Map<String, String> getHeaders() {
101
+                return config.getHeaders();
102
+            }
103
+        };
104
+        _requestQueue.add(request);
105
+        return promise;
106
+    }
107
+
108
+    public static <T extends LuDbo> LuPromise<T> get(final LuDataAccessConfigDbo config, Class<T> type,
109
+                                                     String url, final HashMap<String, String> getParams)
110
+    {
111
+        Uri.Builder uri = Uri.parse(url).buildUpon();
112
+        for (String key : getParams.keySet())
113
+        {
114
+            uri.appendQueryParameter(key, getParams.get(key));
115
+        }
116
+        LuPromise<T> promise = new LuPromise<>();
117
+        StringRequest request = new StringRequest(Request.Method.GET, config.getBaseUrl() + uri.toString(),
118
+                getListener(type, promise), getErrorListener(promise))
119
+        {
120
+            @Override
121
+            public Map<String, String> getHeaders() {
122
+                return config.getHeaders();
123
+            }
124
+        };
125
+        _requestQueue.add(request);
126
+        return promise;
127
+    }
128
+
129
+    public static <T extends LuDbo> LuPromise<T> get(LuDataAccessConfigDbo config, Class<T> type,
130
+                                                     String url)
131
+    {
132
+        return get(config, type, url, new HashMap<String, String>());
133
+    }
134
+
135
+    public static <T extends LuDbo> LuPromise<T> post(LuDataAccessConfigDbo config, Class<T> type,
136
+                                                      String url, final HashMap<String, String> postParams)
137
+    {
138
+        return request(config, Request.Method.POST, type, url, postParams);
139
+    }
140
+
141
+    public static <T extends LuDbo> LuPromise<T> post(LuDataAccessConfigDbo config, Class<T> type,
142
+                                                      String url)
143
+    {
144
+        return post(config, type, url, new HashMap<String, String>());
145
+    }
146
+}

+ 74
- 0
app/src/main/java/com/rthoni/stssaguenay/dataaccess/StopsDataAccess.java View File

@@ -0,0 +1,74 @@
1
+package com.rthoni.stssaguenay.dataaccess;
2
+
3
+import android.util.Pair;
4
+
5
+import com.rthoni.stssaguenay.dbo.LuDataAccessConfigDbo;
6
+import com.rthoni.stssaguenay.dbo.LuDbo;
7
+import com.rthoni.stssaguenay.dbo.StopsDbo;
8
+
9
+import org.json.JSONArray;
10
+import org.json.JSONException;
11
+import org.json.JSONObject;
12
+
13
+import java.util.HashMap;
14
+import java.util.List;
15
+import java.util.Locale;
16
+import java.util.Vector;
17
+
18
+/**
19
+ * Created by robin on 9/29/16.
20
+ */
21
+public class StopsDataAccess {
22
+
23
+    public static class StopsDboRaw extends LuDbo {
24
+
25
+        protected List<StopsDbo> _stops;
26
+
27
+        @Override
28
+        public void fromJson(JSONObject json) throws JSONException {
29
+
30
+            _stops = new Vector<>();
31
+            JSONArray features = json.getJSONArray("features");
32
+            for (int i = 0; i < features.length(); ++i) {
33
+                JSONObject obj = features.getJSONObject(i);
34
+                JSONObject props = obj.getJSONObject("properties");
35
+
36
+                JSONArray routes = props.getJSONArray("route_ids");
37
+                List<String> routesStr = new Vector<>();
38
+                for (int j = 0; j < routes.length(); ++j) {
39
+                    routesStr.add(routes.getString(j));
40
+                }
41
+
42
+                JSONArray pos = obj.getJSONObject("geometry").getJSONArray("coordinates");
43
+
44
+                StopsDbo stop = new StopsDbo();
45
+                stop.setId(obj.getString("id"));
46
+                stop.setName(props.getString("name"));
47
+                stop.setRoutes(routesStr);
48
+                stop.setPosition(new Pair<Double, Double>(pos.getDouble(0), pos.getDouble(1)));
49
+                _stops.add(stop);
50
+            }
51
+        }
52
+
53
+        @Override
54
+        public HashMap<String, Object> toArray() {
55
+            return null;
56
+        }
57
+
58
+        public List<StopsDbo> getStops()
59
+        {
60
+            return _stops;
61
+        }
62
+    }
63
+
64
+    public static LuPromise<List<StopsDbo>> getAll(LuDataAccessConfigDbo config, int unknownParam)
65
+    {
66
+        return LuRequest.get(config, StopsDboRaw.class, String.format(Locale.getDefault(), "transit/%d/week/stops.json", unknownParam))
67
+        .map(new LuPromise.LuConverter<StopsDboRaw, List<StopsDbo>>() {
68
+            @Override
69
+            public List<StopsDbo> convert(StopsDboRaw data) {
70
+                return data.getStops();
71
+            }
72
+        });
73
+    }
74
+}

+ 27
- 0
app/src/main/java/com/rthoni/stssaguenay/dbo/LuDataAccessConfigDbo.java View File

@@ -0,0 +1,27 @@
1
+package com.rthoni.stssaguenay.dbo;
2
+
3
+import java.util.HashMap;
4
+import java.util.Map;
5
+
6
+/**
7
+ *
8
+ * Created by robin on 11/28/15.
9
+ */
10
+public class LuDataAccessConfigDbo {
11
+
12
+    private String _baseUrl;
13
+
14
+    public String getBaseUrl() {
15
+        return _baseUrl;
16
+    }
17
+
18
+    public void setBaseUrl(String baseUrl) {
19
+        _baseUrl = baseUrl;
20
+    }
21
+
22
+    public Map<String, String> getHeaders()
23
+    {
24
+        Map<String, String> map = new HashMap<>();
25
+        return map;
26
+    }
27
+}

+ 26
- 0
app/src/main/java/com/rthoni/stssaguenay/dbo/LuDbo.java View File

@@ -0,0 +1,26 @@
1
+package com.rthoni.stssaguenay.dbo;
2
+
3
+import org.json.JSONException;
4
+import org.json.JSONObject;
5
+
6
+import java.util.HashMap;
7
+
8
+/**
9
+ * Created by robin on 11/27/15.
10
+ */
11
+public abstract class LuDbo {
12
+
13
+    public abstract void fromJson(JSONObject json) throws JSONException;
14
+
15
+    public abstract HashMap<String, Object> toArray();
16
+
17
+    public JSONObject toJson()
18
+    {
19
+        return new JSONObject(toArray());
20
+    }
21
+
22
+    @Override
23
+    public String toString() {
24
+        return toJson().toString();
25
+    }
26
+}

+ 56
- 0
app/src/main/java/com/rthoni/stssaguenay/dbo/StopsDbo.java View File

@@ -0,0 +1,56 @@
1
+package com.rthoni.stssaguenay.dbo;
2
+
3
+import android.util.Pair;
4
+
5
+import java.util.List;
6
+
7
+/**
8
+ * Created by robin on 9/29/16.
9
+ */
10
+public class StopsDbo {
11
+
12
+    protected String _name;
13
+
14
+    protected List<String> _routes;
15
+
16
+    protected String _id;
17
+
18
+    protected Pair<Double, Double> _position;
19
+
20
+    public String getFullName()
21
+    {
22
+        return String.format("%s - %s", _id, _name);
23
+    }
24
+
25
+    public String getName() {
26
+        return _name;
27
+    }
28
+
29
+    public void setName(String name) {
30
+        _name = name;
31
+    }
32
+
33
+    public List<String> getRoutes() {
34
+        return _routes;
35
+    }
36
+
37
+    public void setRoutes(List<String> routes) {
38
+        _routes = routes;
39
+    }
40
+
41
+    public String getId() {
42
+        return _id;
43
+    }
44
+
45
+    public void setId(String id) {
46
+        _id = id;
47
+    }
48
+
49
+    public Pair<Double, Double> getPosition() {
50
+        return _position;
51
+    }
52
+
53
+    public void setPosition(Pair<Double, Double> position) {
54
+        _position = position;
55
+    }
56
+}

+ 87
- 0
app/src/main/java/com/rthoni/stssaguenay/ui/activities/MainActivity.java View File

@@ -0,0 +1,87 @@
1
+package com.rthoni.stssaguenay.ui.activities;
2
+
3
+import android.content.Intent;
4
+import android.os.Bundle;
5
+import android.support.design.widget.FloatingActionButton;
6
+import android.support.design.widget.Snackbar;
7
+import android.support.v7.app.AppCompatActivity;
8
+import android.support.v7.widget.Toolbar;
9
+import android.view.View;
10
+import android.view.Menu;
11
+import android.view.MenuItem;
12
+
13
+import com.rthoni.stssaguenay.R;
14
+import com.rthoni.stssaguenay.dataaccess.LuRequest;
15
+import com.rthoni.stssaguenay.ui.fragments.HomeFragment;
16
+import com.rthoni.stssaguenay.ui.fragments.StopPickerFragment;
17
+
18
+import butterknife.BindView;
19
+import butterknife.ButterKnife;
20
+
21
+public class MainActivity extends AppCompatActivity {
22
+
23
+    @BindView(R.id.fab)
24
+    FloatingActionButton _fab;
25
+
26
+    @Override
27
+    protected void onCreate(Bundle savedInstanceState) {
28
+        super.onCreate(savedInstanceState);
29
+        LuRequest.init(this);
30
+
31
+        setContentView(R.layout.activity_main);
32
+        ButterKnife.bind(this);
33
+
34
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
35
+        setSupportActionBar(toolbar);
36
+
37
+        _fab.setOnClickListener(new View.OnClickListener() {
38
+            @Override
39
+            public void onClick(View view) {
40
+                goToAddStop();
41
+            }
42
+        });
43
+//        _fab.hide();
44
+        goToHome();
45
+    }
46
+
47
+    public void goToHome()
48
+    {
49
+        _fab.show();
50
+        HomeFragment f = new HomeFragment();
51
+        getSupportFragmentManager().beginTransaction().replace(R.id.container, f).commit();
52
+    }
53
+
54
+    public void goToStop()
55
+    {
56
+        _fab.hide();
57
+
58
+    }
59
+
60
+    public void goToAddStop()
61
+    {
62
+        Intent intent = new Intent(this, StopPickerActivity.class);
63
+        startActivity(intent);
64
+    }
65
+
66
+//    @Override
67
+//    public boolean onCreateOptionsMenu(Menu menu) {
68
+//        // Inflate the menu; this adds items to the action bar if it is present.
69
+//        getMenuInflater().inflate(R.menu.menu_main, menu);
70
+//        return true;
71
+//    }
72
+
73
+//    @Override
74
+//    public boolean onOptionsItemSelected(MenuItem item) {
75
+//        // Handle action bar item clicks here. The action bar will
76
+//        // automatically handle clicks on the Home/Up button, so long
77
+//        // as you specify a parent activity in AndroidManifest.xml.
78
+//        int id = item.getItemId();
79
+//
80
+//        //noinspection SimplifiableIfStatement
81
+//        if (id == R.id.action_settings) {
82
+//            return true;
83
+//        }
84
+//
85
+//        return super.onOptionsItemSelected(item);
86
+//    }
87
+}

+ 36
- 0
app/src/main/java/com/rthoni/stssaguenay/ui/activities/StopPickerActivity.java View File

@@ -0,0 +1,36 @@
1
+package com.rthoni.stssaguenay.ui.activities;
2
+
3
+import android.os.Bundle;
4
+import android.app.Activity;
5
+import android.support.v7.app.AppCompatActivity;
6
+
7
+import com.rthoni.stssaguenay.R;
8
+import com.rthoni.stssaguenay.ui.fragments.StopPickerFragment;
9
+
10
+public class StopPickerActivity extends AppCompatActivity {
11
+
12
+    @Override
13
+    protected void onCreate(Bundle savedInstanceState) {
14
+        super.onCreate(savedInstanceState);
15
+        setContentView(R.layout.activity_stop_picker);
16
+        if (getSupportActionBar() != null) {
17
+            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
18
+        }
19
+        goToStops();
20
+    }
21
+
22
+    public void goToStops()
23
+    {
24
+        StopPickerFragment f = new StopPickerFragment();
25
+        getSupportFragmentManager()
26
+                .beginTransaction()
27
+                .replace(R.id.container, f)
28
+                .commit();
29
+    }
30
+
31
+    public void goToRoutes()
32
+    {
33
+
34
+    }
35
+
36
+}

+ 31
- 0
app/src/main/java/com/rthoni/stssaguenay/ui/fragments/HomeFragment.java View File

@@ -0,0 +1,31 @@
1
+package com.rthoni.stssaguenay.ui.fragments;
2
+
3
+import android.os.Bundle;
4
+import android.support.annotation.Nullable;
5
+import android.support.v4.app.Fragment;
6
+import android.support.v7.widget.RecyclerView;
7
+import android.view.LayoutInflater;
8
+import android.view.View;
9
+import android.view.ViewGroup;
10
+
11
+import com.rthoni.stssaguenay.R;
12
+
13
+import butterknife.BindView;
14
+import butterknife.ButterKnife;
15
+
16
+/**
17
+ * Created by robin on 9/29/16.
18
+ */
19
+public class HomeFragment extends Fragment {
20
+
21
+    @BindView(R.id.listFavouritesStops)
22
+    RecyclerView _favouritesStops;
23
+
24
+    @Nullable
25
+    @Override
26
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
27
+        View v = inflater.inflate(R.layout.fragment_home, container, false);
28
+        ButterKnife.bind(this, v);
29
+        return v;
30
+    }
31
+}

+ 195
- 0
app/src/main/java/com/rthoni/stssaguenay/ui/fragments/StopPickerFragment.java View File

@@ -0,0 +1,195 @@
1
+package com.rthoni.stssaguenay.ui.fragments;
2
+
3
+import android.app.ProgressDialog;
4
+import android.os.Bundle;
5
+import android.os.Handler;
6
+import android.os.Looper;
7
+import android.support.annotation.Nullable;
8
+import android.support.v4.app.Fragment;
9
+import android.support.v7.widget.LinearLayoutManager;
10
+import android.support.v7.widget.RecyclerView;
11
+import android.text.Editable;
12
+import android.text.TextWatcher;
13
+import android.view.LayoutInflater;
14
+import android.view.View;
15
+import android.view.ViewGroup;
16
+import android.widget.EditText;
17
+import android.widget.Filter;
18
+import android.widget.Filterable;
19
+import android.widget.TextView;
20
+import android.widget.Toast;
21
+
22
+import com.rthoni.stssaguenay.R;
23
+import com.rthoni.stssaguenay.business.STSBusiness;
24
+import com.rthoni.stssaguenay.business.StopsBusiness;
25
+import com.rthoni.stssaguenay.business.Utils;
26
+import com.rthoni.stssaguenay.dataaccess.LuPromise;
27
+import com.rthoni.stssaguenay.dbo.StopsDbo;
28
+
29
+import java.util.List;
30
+import java.util.TimerTask;
31
+import java.util.Vector;
32
+
33
+import butterknife.BindView;
34
+import butterknife.ButterKnife;
35
+
36
+/**
37
+ * Created by robin on 9/29/16.
38
+ */
39
+public class StopPickerFragment extends Fragment {
40
+
41
+    @BindView(R.id.listStops)
42
+    RecyclerView _listStops;
43
+
44
+    @BindView(R.id.textSearch)
45
+    EditText _searchText;
46
+
47
+    private StopsAdapter _stopsAdapter;
48
+
49
+    public static class ViewHolder extends RecyclerView.ViewHolder {
50
+        public TextView _textView;
51
+        public ViewHolder(TextView v) {
52
+            super(v);
53
+            _textView = v;
54
+        }
55
+    }
56
+
57
+    public class StopsAdapter extends RecyclerView.Adapter<ViewHolder> implements Filterable {
58
+
59
+        private List<StopsDbo> _allStops;
60
+
61
+        private List<StopsDbo> _filteredStops;
62
+
63
+        @Override
64
+        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
65
+            View v = LayoutInflater.from(parent.getContext())
66
+                    .inflate(R.layout.simple_recycler_view_item, parent, false);
67
+            ViewHolder vh = new ViewHolder((TextView)v);
68
+            return vh;
69
+        }
70
+
71
+        @Override
72
+        public void onBindViewHolder(ViewHolder holder, int position) {
73
+            final StopsDbo stopDbo = _filteredStops.get(position);
74
+            holder._textView.setText(stopDbo.getFullName());
75
+            holder._textView.setOnClickListener(new View.OnClickListener() {
76
+                @Override
77
+                public void onClick(View v) {
78
+                    onStopSelected(stopDbo);
79
+                }
80
+            });
81
+        }
82
+
83
+        @Override
84
+        public int getItemCount() {
85
+            return _filteredStops == null ? 0 : _filteredStops.size();
86
+        }
87
+
88
+        public void setStops(List<StopsDbo> stops, String query) {
89
+            _allStops = stops;
90
+            getFilter().filter(query);
91
+        }
92
+
93
+        @Override
94
+        public Filter getFilter() {
95
+            return new Filter() {
96
+
97
+                @Override
98
+                protected FilterResults performFiltering(CharSequence constraint) {
99
+
100
+                    List<StopsDbo> filteredStops = new Vector<>();
101
+                    final FilterResults results = new FilterResults();
102
+
103
+                    if (constraint.length() == 0) {
104
+                        filteredStops.addAll(_allStops);
105
+                    }
106
+                    else {
107
+                        for (StopsDbo stop : _allStops) {
108
+                            if (Utils.stringMatch(stop.getFullName(), constraint.toString())) {
109
+                                filteredStops.add(stop);
110
+                            }
111
+                        }
112
+                    }
113
+                    results.values = filteredStops;
114
+                    results.count = filteredStops.size();
115
+                    return results;
116
+                }
117
+
118
+                @Override
119
+                protected void publishResults(CharSequence constraint, FilterResults results) {
120
+                    _stopsAdapter._filteredStops = (List<StopsDbo>) results.values;
121
+                    _stopsAdapter.notifyDataSetChanged();
122
+                }
123
+            };
124
+        }
125
+    }
126
+
127
+    @Nullable
128
+    @Override
129
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
130
+        View v = inflater.inflate(R.layout.fragment_stop_picker, container, false);
131
+        ButterKnife.bind(this, v);
132
+
133
+        _stopsAdapter = new StopsAdapter();
134
+        _listStops.setAdapter(_stopsAdapter);
135
+        _listStops.setLayoutManager(new LinearLayoutManager(getContext()));
136
+
137
+        _searchText.addTextChangedListener(new TextWatcher() {
138
+            Handler handler = new Handler(Looper.getMainLooper() /*UI thread*/);
139
+            Runnable workRunnable;
140
+            @Override
141
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
142
+
143
+            }
144
+
145
+            @Override
146
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
147
+
148
+            }
149
+
150
+            @Override
151
+            public void afterTextChanged(final Editable s) {
152
+                handler.removeCallbacks(workRunnable);
153
+                workRunnable = new TimerTask() {
154
+                    @Override
155
+                    public void run() {
156
+                        _stopsAdapter.getFilter().filter(s.toString());
157
+                    }
158
+                };
159
+                handler.postDelayed(workRunnable, 250);
160
+            }
161
+        });
162
+
163
+        loadStops();
164
+
165
+        return v;
166
+    }
167
+
168
+    public void loadStops()
169
+    {
170
+        final ProgressDialog progressDialog = new ProgressDialog(getContext());
171
+        progressDialog.setIndeterminate(true);
172
+        progressDialog.show();
173
+
174
+        StopsBusiness.getAll(STSBusiness.getConfig(), STSBusiness.UNKNOWN_PARAM)
175
+                .then(new LuPromise.LuConsumer<List<StopsDbo>>() {
176
+                    @Override
177
+                    public void execute(List<StopsDbo> data) {
178
+                        progressDialog.dismiss();
179
+                        _stopsAdapter.setStops(data, _searchText.getText().toString());
180
+                    }
181
+                }, new LuPromise.LuConsumer<LuPromise.LuPromiseError>() {
182
+                    @Override
183
+                    public void execute(LuPromise.LuPromiseError data) {
184
+                        progressDialog.dismiss();
185
+                        _stopsAdapter.setStops(new Vector<StopsDbo>(), _searchText.getText().toString());
186
+                        Toast.makeText(getContext(), data.getError(), Toast.LENGTH_LONG).show();
187
+                    }
188
+                });
189
+    }
190
+
191
+    public void onStopSelected(StopsDbo stopsDbo)
192
+    {
193
+
194
+    }
195
+}

+ 20
- 0
app/src/main/java/com/rthoni/stssaguenay/ui/fragments/StopRoutePickerFragment.java View File

@@ -0,0 +1,20 @@
1
+package com.rthoni.stssaguenay.ui.fragments;
2
+
3
+import android.os.Bundle;
4
+import android.support.annotation.Nullable;
5
+import android.support.v4.app.Fragment;
6
+import android.view.LayoutInflater;
7
+import android.view.View;
8
+import android.view.ViewGroup;
9
+
10
+/**
11
+ * Created by robin on 9/29/16.
12
+ */
13
+public class StopRoutePickerFragment extends Fragment {
14
+
15
+    @Nullable
16
+    @Override
17
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
18
+        return super.onCreateView(inflater, container, savedInstanceState);
19
+    }
20
+}

+ 9
- 0
app/src/main/res/drawable/ic_add_black_24dp.xml View File

@@ -0,0 +1,9 @@
1
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+        android:width="24dp"
3
+        android:height="24dp"
4
+        android:viewportWidth="24.0"
5
+        android:viewportHeight="24.0">
6
+    <path
7
+        android:fillColor="#e9e9e9"
8
+        android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
9
+</vector>

+ 35
- 0
app/src/main/res/layout/activity_main.xml View File

@@ -0,0 +1,35 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<android.support.design.widget.CoordinatorLayout
3
+    xmlns:android="http://schemas.android.com/apk/res/android"
4
+    xmlns:app="http://schemas.android.com/apk/res-auto"
5
+    xmlns:tools="http://schemas.android.com/tools"
6
+    android:layout_width="match_parent"
7
+    android:layout_height="match_parent"
8
+    android:fitsSystemWindows="true"
9
+    tools:context=".ui.activities.MainActivity">
10
+
11
+    <android.support.design.widget.AppBarLayout
12
+        android:layout_width="match_parent"
13
+        android:layout_height="wrap_content"
14
+        android:theme="@style/AppTheme.AppBarOverlay">
15
+
16
+        <android.support.v7.widget.Toolbar
17
+            android:id="@+id/toolbar"
18
+            android:layout_width="match_parent"
19
+            android:layout_height="?attr/actionBarSize"
20
+            android:background="?attr/colorPrimary"
21
+            app:popupTheme="@style/AppTheme.PopupOverlay"/>
22
+
23
+    </android.support.design.widget.AppBarLayout>
24
+
25
+    <include layout="@layout/content_main"/>
26
+
27
+    <android.support.design.widget.FloatingActionButton
28
+        android:id="@+id/fab"
29
+        android:layout_width="wrap_content"
30
+        android:layout_height="wrap_content"
31
+        android:layout_gravity="bottom|end"
32
+        android:layout_margin="@dimen/fab_margin"
33
+        android:src="@drawable/ic_add_black_24dp"/>
34
+
35
+</android.support.design.widget.CoordinatorLayout>

+ 19
- 0
app/src/main/res/layout/activity_stop_picker.xml View File

@@ -0,0 +1,19 @@
1
+<RelativeLayout
2
+    xmlns:android="http://schemas.android.com/apk/res/android"
3
+    xmlns:app="http://schemas.android.com/apk/res-auto"
4
+    xmlns:tools="http://schemas.android.com/tools"
5
+    android:layout_width="match_parent"
6
+    android:layout_height="match_parent"
7
+    android:paddingBottom="@dimen/activity_vertical_margin"
8
+    android:paddingLeft="@dimen/activity_horizontal_margin"
9
+    android:paddingRight="@dimen/activity_horizontal_margin"
10
+    android:paddingTop="@dimen/activity_vertical_margin"
11
+    app:layout_behavior="@string/appbar_scrolling_view_behavior"
12
+    tools:context=".ui.activities.StopPickerActivity">
13
+
14
+    <FrameLayout
15
+        android:id="@+id/container"
16
+        android:layout_width="match_parent"
17
+        android:layout_height="match_parent">
18
+    </FrameLayout>
19
+</RelativeLayout>

+ 21
- 0
app/src/main/res/layout/content_main.xml View File

@@ -0,0 +1,21 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<RelativeLayout
3
+    xmlns:android="http://schemas.android.com/apk/res/android"
4
+    xmlns:app="http://schemas.android.com/apk/res-auto"
5
+    xmlns:tools="http://schemas.android.com/tools"
6
+    android:layout_width="match_parent"
7
+    android:layout_height="match_parent"
8
+    android:paddingBottom="@dimen/activity_vertical_margin"
9
+    android:paddingLeft="@dimen/activity_horizontal_margin"
10
+    android:paddingRight="@dimen/activity_horizontal_margin"
11
+    android:paddingTop="@dimen/activity_vertical_margin"
12
+    app:layout_behavior="@string/appbar_scrolling_view_behavior"
13
+    tools:context=".ui.activities.MainActivity"
14
+    tools:showIn="@layout/activity_main">
15
+
16
+    <FrameLayout
17
+        android:id="@+id/container"
18
+        android:layout_width="match_parent"
19
+        android:layout_height="match_parent">
20
+    </FrameLayout>
21
+</RelativeLayout>

+ 28
- 0
app/src/main/res/layout/fragment_home.xml View File

@@ -0,0 +1,28 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+                android:layout_width="match_parent"
4
+                android:layout_height="match_parent">
5
+
6
+    <TextView
7
+        android:layout_width="wrap_content"
8
+        android:layout_height="wrap_content"
9
+        android:textAppearance="?android:attr/textAppearanceLarge"
10
+        android:text="@string/favourites_stops"
11
+        android:id="@+id/textView"
12
+        android:layout_alignParentTop="true"
13
+        android:layout_alignParentLeft="true"
14
+        android:layout_alignParentStart="true"
15
+        android:layout_alignParentRight="true"
16
+        android:layout_alignParentEnd="true"/>
17
+
18
+    <android.support.v7.widget.RecyclerView
19
+        android:layout_width="wrap_content"
20
+        android:layout_height="wrap_content"
21
+        android:id="@+id/listFavouritesStops"
22
+        android:layout_below="@+id/textView"
23
+        android:layout_alignParentLeft="true"
24
+        android:layout_alignParentStart="true"
25
+        android:layout_alignParentRight="true"
26
+        android:layout_alignParentEnd="true"
27
+        android:layout_alignParentBottom="true"/>
28
+</RelativeLayout>

+ 31
- 0
app/src/main/res/layout/fragment_stop_picker.xml View File

@@ -0,0 +1,31 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+                android:layout_width="match_parent"
4
+                android:layout_height="match_parent">
5
+
6
+    <EditText
7
+        android:layout_width="wrap_content"
8
+        android:layout_height="wrap_content"
9
+        android:id="@+id/textSearch"
10
+        android:hint="@string/search_stop"
11
+        android:layout_alignParentTop="true"
12
+        android:layout_alignParentLeft="true"
13
+        android:layout_alignParentStart="true"
14
+        android:layout_alignParentRight="true"
15
+        android:layout_alignParentEnd="true"
16
+        android:inputType="text"
17
+        android:imeOptions="actionSearch"/>
18
+
19
+    <android.support.v7.widget.RecyclerView
20
+        android:layout_width="wrap_content"
21
+        android:layout_height="wrap_content"
22
+        android:id="@+id/listStops"
23
+        android:scrollbars="vertical"
24
+        android:fadeScrollbars="true"
25
+        android:layout_below="@id/textSearch"
26
+        android:layout_alignParentLeft="true"
27
+        android:layout_alignParentStart="true"
28
+        android:layout_alignParentRight="true"
29
+        android:layout_alignParentEnd="true"
30
+        android:layout_alignParentBottom="true"/>
31
+</RelativeLayout>

+ 31
- 0
app/src/main/res/layout/fragment_stop_route_picker.xml View File

@@ -0,0 +1,31 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+                android:layout_width="match_parent"
4
+                android:layout_height="match_parent">
5
+
6
+    <EditText
7
+        android:layout_width="wrap_content"
8
+        android:layout_height="wrap_content"
9
+        android:id="@+id/textSearch"
10
+        android:hint="@string/search_stop"
11
+        android:layout_alignParentTop="true"
12
+        android:layout_alignParentLeft="true"
13
+        android:layout_alignParentStart="true"
14
+        android:layout_alignParentRight="true"
15
+        android:layout_alignParentEnd="true"
16
+        android:inputType="text"
17
+        android:imeOptions="actionSearch"/>
18
+
19
+    <android.support.v7.widget.RecyclerView
20
+        android:layout_width="wrap_content"
21
+        android:layout_height="wrap_content"
22
+        android:id="@+id/listStops"
23
+        android:scrollbars="vertical"
24
+        android:fadeScrollbars="true"
25
+        android:layout_below="@id/textSearch"
26
+        android:layout_alignParentLeft="true"
27
+        android:layout_alignParentStart="true"
28
+        android:layout_alignParentRight="true"
29
+        android:layout_alignParentEnd="true"
30
+        android:layout_alignParentBottom="true"/>
31
+</RelativeLayout>

+ 13
- 0
app/src/main/res/layout/simple_recycler_view_item.xml View File

@@ -0,0 +1,13 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
3
+          android:id="@android:id/text1"
4
+          android:layout_width="match_parent"
5
+          android:layout_height="wrap_content"
6
+          android:textAppearance="?android:attr/textAppearanceListItemSmall"
7
+          android:gravity="center_vertical"
8
+          android:minHeight="?android:attr/listPreferredItemHeightSmall"
9
+          android:focusable="true"
10
+          android:clickable="true"
11
+          android:foreground="?android:attr/selectableItemBackground">
12
+
13
+</TextView>

+ 10
- 0
app/src/main/res/menu/menu_main.xml View File

@@ -0,0 +1,10 @@
1
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
2
+      xmlns:app="http://schemas.android.com/apk/res-auto"
3
+      xmlns:tools="http://schemas.android.com/tools"
4
+      tools:context=".ui.activities.MainActivity">
5
+    <item
6
+        android:id="@+id/action_settings"
7
+        android:orderInCategory="100"
8
+        android:title="@string/action_settings"
9
+        app:showAsAction="never"/>
10
+</menu>

+ 9
- 0
app/src/main/res/menu/menu_stop_picker.xml View File

@@ -0,0 +1,9 @@
1
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
2
+      xmlns:tools="http://schemas.android.com/tools"
3
+      tools:context="com.rthoni.stssaguenay.ui.activities.StopPickerActivity">
4
+    <item
5
+        android:id="@+id/action_settings"
6
+        android:orderInCategory="100"
7
+        android:showAsAction="never"
8
+        android:title="@string/action_settings"/>
9
+</menu>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png View File


+ 9
- 0
app/src/main/res/values-v21/styles.xml View File

@@ -0,0 +1,9 @@
1
+<resources>
2
+
3
+    <style name="AppTheme.NoActionBar">
4
+        <item name="windowActionBar">false</item>
5
+        <item name="windowNoTitle">true</item>
6
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
7
+        <item name="android:statusBarColor">@android:color/transparent</item>
8
+    </style>
9
+</resources>

+ 6
- 0
app/src/main/res/values-w820dp/dimens.xml View File

@@ -0,0 +1,6 @@
1
+<resources>
2
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
3
+         (such as screen margins) for screens with more than 820dp of available width. This
4
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
5
+    <dimen name="activity_horizontal_margin">64dp</dimen>
6
+</resources>

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

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+    <color name="colorPrimary">#3F51B5</color>
4
+    <color name="colorPrimaryDark">#303F9F</color>
5
+    <color name="colorAccent">#FF4081</color>
6
+</resources>

+ 6
- 0
app/src/main/res/values/dimens.xml View File

@@ -0,0 +1,6 @@
1
+<resources>
2
+    <!-- Default screen margins, per the Android Design guidelines. -->
3
+    <dimen name="activity_horizontal_margin">16dp</dimen>
4
+    <dimen name="activity_vertical_margin">16dp</dimen>
5
+    <dimen name="fab_margin">16dp</dimen>
6
+</resources>

+ 7
- 0
app/src/main/res/values/strings.xml View File

@@ -0,0 +1,7 @@
1
+<resources>
2
+    <string name="app_name">STS Saguenay</string>
3
+    <string name="action_settings">Settings</string>
4
+    <string name="favourites_stops">Favourites stops:</string>
5
+    <string name="search_stop">Search a stop</string>
6
+    <string name="title_activity_stop_picker">Pick a stop - STS Saguenay</string>
7
+</resources>

+ 20
- 0
app/src/main/res/values/styles.xml View File

@@ -0,0 +1,20 @@
1
+<resources>
2
+
3
+    <!-- Base application theme. -->
4
+    <style name="AppTheme" parent="Theme.AppCompat">
5
+        <!-- Customize your theme here. -->
6
+        <item name="colorPrimary">@color/colorPrimary</item>
7
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
8
+        <item name="colorAccent">@color/colorAccent</item>
9
+    </style>
10
+
11
+    <style name="AppTheme.NoActionBar">
12
+        <item name="windowActionBar">false</item>
13
+        <item name="windowNoTitle">true</item>
14
+    </style>
15
+
16
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
17
+
18
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat"/>
19
+
20
+</resources>

+ 15
- 0
app/src/test/java/com/rthoni/stssaguenay/ExampleUnitTest.java View File

@@ -0,0 +1,15 @@
1
+package com.rthoni.stssaguenay;
2
+
3
+import org.junit.Test;
4
+
5
+import static org.junit.Assert.*;
6
+
7
+/**
8
+ * To work on unit tests, switch the Test Artifact in the Build Variants view.
9
+ */
10
+public class ExampleUnitTest {
11
+    @Test
12
+    public void addition_isCorrect() throws Exception {
13
+        assertEquals(4, 2 + 2);
14
+    }
15
+}

+ 25
- 0
build.gradle View File

@@ -0,0 +1,25 @@
1
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
2
+
3
+buildscript {
4
+    repositories {
5
+        jcenter()
6
+        mavenCentral()
7
+    }
8
+    dependencies {
9
+        classpath 'com.android.tools.build:gradle:2.1.3'
10
+        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
11
+
12
+        // NOTE: Do not place your application dependencies here; they belong
13
+        // in the individual module build.gradle files
14
+    }
15
+}
16
+
17
+allprojects {
18
+    repositories {
19
+        jcenter()
20
+    }
21
+}
22
+
23
+task clean(type: Delete) {
24
+    delete rootProject.buildDir
25
+}

+ 18
- 0
gradle.properties View File

@@ -0,0 +1,18 @@
1
+# Project-wide Gradle settings.
2
+
3
+# IDE (e.g. Android Studio) users:
4
+# Gradle settings configured through the IDE *will override*
5
+# any settings specified in this file.
6
+
7
+# For more details on how to configure your build environment visit
8
+# http://www.gradle.org/docs/current/userguide/build_environment.html
9
+
10
+# Specifies the JVM arguments used for the daemon process.
11
+# The setting is particularly useful for tweaking memory settings.
12
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
13
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14
+
15
+# When configured, Gradle will run in incubating parallel mode.
16
+# This option should only be used with decoupled projects. More details, visit
17
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18
+# org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar View File


+ 6
- 0
gradle/wrapper/gradle-wrapper.properties View File

@@ -0,0 +1,6 @@
1
+#Thu Sep 29 16:53:12 EDT 2016
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-2.14.1-all.zip

+ 160
- 0
gradlew View File

@@ -0,0 +1,160 @@
1
+#!/usr/bin/env bash
2
+
3
+##############################################################################
4
+##
5
+##  Gradle start up script for UN*X
6
+##
7
+##############################################################################
8
+
9
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10
+DEFAULT_JVM_OPTS=""
11
+
12
+APP_NAME="Gradle"
13
+APP_BASE_NAME=`basename "$0"`
14
+
15
+# Use the maximum available, or set MAX_FD != -1 to use that value.
16
+MAX_FD="maximum"
17
+
18
+warn ( ) {
19
+    echo "$*"
20
+}
21
+
22
+die ( ) {
23
+    echo
24
+    echo "$*"
25
+    echo
26
+    exit 1
27
+}
28
+
29
+# OS specific support (must be 'true' or 'false').
30
+cygwin=false
31
+msys=false
32
+darwin=false
33
+case "`uname`" in
34
+  CYGWIN* )
35
+    cygwin=true
36
+    ;;
37
+  Darwin* )
38
+    darwin=true
39
+    ;;
40
+  MINGW* )
41
+    msys=true
42
+    ;;
43
+esac
44
+
45
+# Attempt to set APP_HOME
46
+# Resolve links: $0 may be a link
47
+PRG="$0"
48
+# Need this for relative symlinks.
49
+while [ -h "$PRG" ] ; do
50
+    ls=`ls -ld "$PRG"`
51
+    link=`expr "$ls" : '.*-> \(.*\)$'`
52
+    if expr "$link" : '/.*' > /dev/null; then
53
+        PRG="$link"
54
+    else
55
+        PRG=`dirname "$PRG"`"/$link"
56
+    fi
57
+done
58
+SAVED="`pwd`"
59
+cd "`dirname \"$PRG\"`/" >/dev/null
60
+APP_HOME="`pwd -P`"
61
+cd "$SAVED" >/dev/null
62
+
63
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64
+
65
+# Determine the Java command to use to start the JVM.
66
+if [ -n "$JAVA_HOME" ] ; then
67
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68
+        # IBM's JDK on AIX uses strange locations for the executables
69
+        JAVACMD="$JAVA_HOME/jre/sh/java"
70
+    else
71
+        JAVACMD="$JAVA_HOME/bin/java"
72
+    fi
73
+    if [ ! -x "$JAVACMD" ] ; then
74
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75
+
76
+Please set the JAVA_HOME variable in your environment to match the
77
+location of your Java installation."
78
+    fi
79
+else
80
+    JAVACMD="java"
81
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82
+
83
+Please set the JAVA_HOME variable in your environment to match the
84
+location of your Java installation."
85
+fi
86
+
87
+# Increase the maximum file descriptors if we can.
88
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89
+    MAX_FD_LIMIT=`ulimit -H -n`
90
+    if [ $? -eq 0 ] ; then
91
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92
+            MAX_FD="$MAX_FD_LIMIT"
93
+        fi
94
+        ulimit -n $MAX_FD
95
+        if [ $? -ne 0 ] ; then
96
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
97
+        fi
98
+    else
99
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100
+    fi
101
+fi
102
+
103
+# For Darwin, add options to specify how the application appears in the dock
104
+if $darwin; then
105
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106
+fi
107
+
108
+# For Cygwin, switch paths to Windows format before running java
109
+if $cygwin ; then
110
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112
+    JAVACMD=`cygpath --unix "$JAVACMD"`
113
+
114
+    # We build the pattern for arguments to be converted via cygpath
115
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116
+    SEP=""
117
+    for dir in $ROOTDIRSRAW ; do
118
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
119
+        SEP="|"
120
+    done
121
+    OURCYGPATTERN="(^($ROOTDIRS))"
122
+    # Add a user-defined pattern to the cygpath arguments
123
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125
+    fi
126
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
127
+    i=0
128
+    for arg in "$@" ; do
129
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
131
+
132
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
133
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134
+        else
135
+            eval `echo args$i`="\"$arg\""
136
+        fi
137
+        i=$((i+1))
138
+    done
139
+    case $i in
140
+        (0) set -- ;;
141
+        (1) set -- "$args0" ;;
142
+        (2) set -- "$args0" "$args1" ;;
143
+        (3) set -- "$args0" "$args1" "$args2" ;;
144
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150
+    esac
151
+fi
152
+
153
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154
+function splitJvmOpts() {
155
+    JVM_OPTS=("$@")
156
+}
157
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159
+
160
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

+ 90
- 0
gradlew.bat View File

@@ -0,0 +1,90 @@
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
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12
+set DEFAULT_JVM_OPTS=
13
+
14
+set DIRNAME=%~dp0
15
+if "%DIRNAME%" == "" set DIRNAME=.
16
+set APP_BASE_NAME=%~n0
17
+set APP_HOME=%DIRNAME%
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 Windowz variants
50
+
51
+if not "%OS%" == "Windows_NT" goto win9xME_args
52
+if "%@eval[2+2]" == "4" goto 4NT_args
53
+
54
+:win9xME_args
55
+@rem Slurp the command line arguments.
56
+set CMD_LINE_ARGS=
57
+set _SKIP=2
58
+
59
+:win9xME_args_slurp
60
+if "x%~1" == "x" goto execute
61
+
62
+set CMD_LINE_ARGS=%*
63
+goto execute
64
+
65
+:4NT_args
66
+@rem Get arguments from the 4NT Shell from JP Software
67
+set CMD_LINE_ARGS=%$
68
+
69
+:execute
70
+@rem Setup the command line
71
+
72
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73
+
74
+@rem Execute Gradle
75
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76
+
77
+:end
78
+@rem End local scope for the variables with windows NT shell
79
+if "%ERRORLEVEL%"=="0" goto mainEnd
80
+
81
+:fail
82
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83
+rem the _cmd.exe /c_ return code!
84
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85
+exit /b 1
86
+
87
+:mainEnd
88
+if "%OS%"=="Windows_NT" endlocal
89
+
90
+:omega

+ 1
- 0
settings.gradle View File

@@ -0,0 +1 @@
1
+include ':app'

Loading…
Cancel
Save