Skip to content

Commit

Permalink
Detect wether stations are online or not
Browse files Browse the repository at this point in the history
eviallet committed Nov 29, 2019
1 parent 35af5ee commit 1d265b1
Showing 26 changed files with 779 additions and 50 deletions.
4 changes: 2 additions & 2 deletions .idea/assetWizardSettings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file removed .idea/caches/build_file_checksums.ser
Binary file not shown.
137 changes: 112 additions & 25 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 16 additions & 2 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 13 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 28
compileSdkVersion 29
defaultConfig {
applicationId "com.gueg.velovwidget"
minSdkVersion 21
targetSdkVersion 28
targetSdkVersion 29
versionCode 3
versionName "1.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
renderscriptTargetApi 22
renderscriptSupportModeEnabled true
}
buildTypes {
release {
@@ -22,13 +26,19 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.google.code.gson:gson:2.8.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'org.osmdroid:osmdroid-android:6.0.2'
implementation 'fr.tvbarthel.blurdialogfragment:lib:2.2.0'
implementation 'com.android.volley:volley:1.1.1'

def room_version = "1.1.1"

implementation "android.arch.persistence.room:runtime:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:$room_version"
implementation "android.arch.persistence.room:rxjava2:$room_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

}
repositories {
mavenCentral()
}
21 changes: 19 additions & 2 deletions app/src/main/java/com/gueg/velovwidget/MainListActivity.java
Original file line number Diff line number Diff line change
@@ -11,7 +11,9 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.gueg.velovwidget.database_stations.JsonParser;
import com.gueg.velovwidget.map.PinsActivity;
@@ -33,6 +35,9 @@ public class MainListActivity extends AppCompatActivity {
SwipeRefreshLayout _swipe;
ProgressBar _progress;

ImageView _serverIcon;
TextView _serverText;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -41,6 +46,9 @@ public void onCreate(Bundle savedInstanceState) {

setContentView(R.layout.activity_list);

_serverIcon = findViewById(R.id.widget_list_servers_icon);
_serverText = findViewById(R.id.widget_list_servers_text);

_swipe = findViewById(R.id.widget_list_refresh);
_list = findViewById(R.id.widget_list_stations);
_progress = findViewById(R.id.widget_list_progress);
@@ -49,6 +57,8 @@ public void onCreate(Bundle savedInstanceState) {
_adapter.setListener(new MainListAdapter.RefreshListener() {
@Override public void onRefreshStarted() {
_swipe.setRefreshing(true);
_serverIcon.setImageDrawable(getApplicationContext().getResources().getDrawable(R.drawable.ic_server_loading));
_serverText.setText(getApplicationContext().getResources().getString(R.string.servers_loading));
}
@Override public void onProgressChanged(int progress, int max) {
if(_progress.getVisibility()!= View.VISIBLE)
@@ -62,6 +72,15 @@ public void onCreate(Bundle savedInstanceState) {
if(_progress.getProgress()==0)
startActivityForResult(new Intent(MainListActivity.this, PinsActivity.class), ACTIVITY_PINS);
}
@Override public void onServerResult(boolean err) {
if(err) {
_serverIcon.setImageDrawable(getApplicationContext().getResources().getDrawable(R.drawable.ic_server_offline));
_serverText.setText(getApplicationContext().getResources().getString(R.string.servers_offline));
} else {
_serverIcon.setImageDrawable(getApplicationContext().getResources().getDrawable(R.drawable.ic_server_online));
_serverText.setText(getApplicationContext().getResources().getString(R.string.servers_online));
}
}
});
_list.setAdapter(_adapter);
_list.setLayoutManager(new LinearLayoutManager(this));
@@ -95,8 +114,6 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
return;
switch(requestCode) {
case ACTIVITY_PINS:
_adapter.refresh();
break;
case ACTIVITY_SORT:
_adapter.refresh();
break;
56 changes: 52 additions & 4 deletions app/src/main/java/com/gueg/velovwidget/MainListAdapter.java
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@
import android.content.Context;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
@@ -16,6 +18,14 @@

import com.gueg.velovwidget.database_stations.JsonParser;
import com.gueg.velovwidget.database_stations.WidgetItemsDatabase;
import com.gueg.velovwidget.velov.TokenManager;
import com.gueg.velovwidget.velov.Velov;
import com.gueg.velovwidget.velov.VelovDialog;
import com.gueg.velovwidget.velov.VelovParser;
import com.gueg.velovwidget.velov.VelovRequest;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
@@ -29,7 +39,7 @@ public class MainListAdapter extends RecyclerView.Adapter<MainListAdapter.ViewHo

private ArrayList<Item> _list;
private Context c;

private FragmentManager fm;

static class ViewHolder extends RecyclerView.ViewHolder {
LinearLayout bkg, dynamicDataLayout;
@@ -48,8 +58,9 @@ static class ViewHolder extends RecyclerView.ViewHolder {
}
}

public MainListAdapter(Context c) {
this.c = c;
public MainListAdapter(AppCompatActivity a) {
this.c = a;
this.fm = a.getSupportFragmentManager();
_list = new ArrayList<>();
}

@@ -74,11 +85,22 @@ public void onBindViewHolder(@NonNull final MainListAdapter.ViewHolder holder, f
holder.dynamicDataLayout.setVisibility(View.GONE);
holder.title.setTextColor(c.getResources().getColor(R.color.colorTextWhite));
holder.bkg.setBackgroundColor(c.getResources().getColor(R.color.colorPrimary));

holder.bkg.setOnClickListener(null);
} else {
holder.dynamicDataLayout.setVisibility(View.VISIBLE);
holder.title.setTextColor(c.getResources().getColor(R.color.colorTextBlack));
holder.bkg.setBackgroundColor(c.getResources().getColor(R.color.colorTextWhite));

holder.bkg.setTag(R.id.tag_name, item.name);
holder.bkg.setTag(R.id.tag_number, item.number);

holder.bkg.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
new VelovDialog().setStationName((String)view.getTag(R.id.tag_name)).setStationNb((int)view.getTag(R.id.tag_number)).show(fm, null);
}
});

if(item.data == null) {
holder.loading.setVisibility(View.VISIBLE);
holder.title.setTextColor(c.getResources().getColor(R.color.colorTextBlack));
@@ -145,10 +167,35 @@ public void run() {
MainListAdapter.this.notifyDataSetChanged();
}
});
boolean hasServersBeenTested = false;
for(int i=0; i<_list.size(); i++) {
final int pos = i;
if(!_list.get(i).isSeparator())
if(!_list.get(i).isSeparator()) {
_list.get(i).setData(JsonParser.updateDynamicDataFromApi(_list.get(i)).data);
if(!hasServersBeenTested) {
final int stationId = _list.get(i).number;

TokenManager.Companion.getToken(c, new TokenManager.TokenManagerListener() {
@Override
public void onTokenParsed(@Nullable String token) {
if(token == null) {
_listener.onServerResult(true); // error
return;
}

VelovParser.Companion.parse(c, new VelovRequest(stationId, token), new VelovParser.VelovParserListener() {
@Override public void onParseComplete(@NotNull ArrayList<Velov> velovs) {
_listener.onServerResult(false); // no error
}
@Override public void onParseError() {
_listener.onServerResult(true); // error
}
});
}
});
hasServersBeenTested = true;
}
}
((MainListActivity)c).runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -184,5 +231,6 @@ public interface RefreshListener {
void onRefreshStarted();
void onProgressChanged(int progress, int max);
void onRefreshFinished();
void onServerResult(boolean err);
}
}
46 changes: 46 additions & 0 deletions app/src/main/java/com/gueg/velovwidget/velov/TokenManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.gueg.velovwidget.velov

import android.content.Context
import com.android.volley.Response
import com.android.volley.toolbox.Volley
import org.json.JSONObject

class TokenManager {
companion object {
private var token = ""

fun getToken(context: Context, listener: TokenManagerListener) {
if(token.isNotEmpty())
listener.onTokenParsed(token)
else {
val queue = Volley.newRequestQueue(context)
queue.add(
TokenRequestOptions.build(
Response.Listener {
queue.add(TokenRequest.build(
Response.Listener { tokenResponse ->
val tokenJsonResponse = JSONObject(tokenResponse)

token = tokenJsonResponse["accessToken"] as String

listener.onTokenParsed(token)
},
Response.ErrorListener { err ->
err.printStackTrace()
listener.onTokenParsed(null)
}))
},
Response.ErrorListener { err ->
err.printStackTrace()
listener.onTokenParsed(null)
}
)
)
}
}
}

interface TokenManagerListener {
fun onTokenParsed(token: String?)
}
}
56 changes: 56 additions & 0 deletions app/src/main/java/com/gueg/velovwidget/velov/TokenRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.gueg.velovwidget.velov

import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import java.util.*

class TokenRequest {

companion object {
@Suppress("PrivatePropertyName")
private val LINK = "https://api.cyclocity.fr/auth/environments/PRD/client_tokens"

fun build(responseListener: Response.Listener<String>, errorListener: Response.ErrorListener): StringRequest {
return object : StringRequest(
Method.POST,
LINK,
responseListener,
errorListener
) {
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers["Accept"] = "application/json, text/plain, */*"
headers["Accept-Language"] = "fr-FR,fr;en-US,en;q=0.8;q=0.6;q=0.4"
headers["Access-Control-Allow-Headers"] = "*"
headers["Access-Control-Allow-Origin"] = "*"
headers["Connection"] = "keep-alive"
headers["Content-Length"] = "100"
headers["Content-Type"] = "application/json"
headers["DNT"] = "1"
headers["Host"] = "api.cyclocity.fr"
headers["Origin"] = "https://velov.grandlyon.com"
headers["Referer"] = "https://velov.grandlyon.com/mapping"
headers["Sec-Fetch-Mode"] = "cors"
headers["Sec-Fetch-Site"] = "cross-site"
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36 OPR/64.0.3417.92"

headers["refreshToken"] = "c1108f14-714c-4ef9-8fc1-5cd8bc127ae6"

return headers
}

override fun getBody(): ByteArray {
val payload =
"{\"code\":\"vls.web.lyon:PRD\","+
"\"key\":\"c3d9f5c22a9157a7cc7fe0e38269573bdd2f13ec48f867360ecdcbd35b196f87\"}"

return payload.toByteArray()
}

override fun getBodyContentType(): String {
return "application/json"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.gueg.velovwidget.velov

import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import java.util.*

class TokenRequestOptions {

companion object {
@Suppress("PrivatePropertyName")
private val LINK = "https://api.cyclocity.fr/auth/environments/PRD/client_tokens"

fun build(responseListener: Response.Listener<String>, errorListener: Response.ErrorListener): StringRequest {
return object : StringRequest(
Method.OPTIONS,
LINK,
responseListener,
errorListener
) {
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers["Sec-Fetch-Mode"] = "cors"
headers["Sec-Fetch-Site"] = "cross-site"
headers["DNT"] = "1"
headers["Connection"] = "keep-alive"
headers["Content-Type"] = "application/json"
headers["Accept"] = "*/*"
headers["Host"] = "api.cyclocity.fr"
headers["Origin"] = "https://velov.grandlyon.com"
headers["Referer"] = "https://velov.grandlyon.com/mapping"
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36 OPR/64.0.3417.92"
headers["Access-Control-Request-Headers"] = "access-control-allow-headers,access-control-allow-origin,content-type"
headers["Access-Control-Request-Method"] = "POST"

return headers
}
}
}
}
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/gueg/velovwidget/velov/Velov.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.gueg.velovwidget.velov

import java.util.*

data class Velov(
val standNumber: Int,
val status: String,
val rating: Double,
val ratingCount: Int,
val ratingLastDate: Date,
val createdAt: Date,
val updatedAt: Date
)
28 changes: 28 additions & 0 deletions app/src/main/java/com/gueg/velovwidget/velov/VelovAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.gueg.velovwidget.velov

import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.gueg.velovwidget.R

class VelovAdapter(private val velovs: List<Velov>) : RecyclerView.Adapter<VelovAdapter.ViewHolder>() {

inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
var rating: TextView = v.findViewById(R.id.velov_rating)
var standNb: TextView = v.findViewById(R.id.velov_stand_nb)
}

override fun onBindViewHolder(holder: ViewHolder, pos: Int) {
val velov = velovs[pos]

holder.rating.text = velov.rating.toString()
holder.standNb.text = velov.standNumber.toString()
}

override fun onCreateViewHolder(p0: ViewGroup, p1: Int) =ViewHolder(LayoutInflater.from(p0.context).inflate(R.layout.row_velov, p0, false))

override fun getItemCount(): Int = velovs.size

}
88 changes: 88 additions & 0 deletions app/src/main/java/com/gueg/velovwidget/velov/VelovDialog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.gueg.velovwidget.velov

import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
import com.gueg.velovwidget.R
import fr.tvbarthel.lib.blurdialogfragment.SupportBlurDialogFragment

class VelovDialog : SupportBlurDialogFragment() {

private lateinit var rootView: View
private lateinit var title: TextView

private lateinit var list: RecyclerView
private lateinit var noVelov: TextView
private lateinit var progress: ProgressBar

private lateinit var stationName: String
private var stationNumber = 0

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
rootView = inflater.inflate(R.layout.dialog_velov, container, false)

title = rootView.findViewById(R.id.dialog_velov_stationname)
title.text = stationName

noVelov = rootView.findViewById(R.id.dialog_velov_novelov)
progress = rootView.findViewById(R.id.dialog_velov_loading)

list = rootView.findViewById(R.id.dialog_velov_stationlist)
list.layoutManager = LinearLayoutManager(context)

TokenManager.getToken(context!!, object: TokenManager.TokenManagerListener {
override fun onTokenParsed(token: String?) {
if(token == null) {
onError()
return
}

VelovParser.parse(context!!, VelovRequest(stationNumber, token), object: VelovParser.VelovParserListener {
override fun onParseComplete(velovs: ArrayList<Velov>) {
activity!!.runOnUiThread {
progress.visibility = GONE
if(velovs.size>0) {
list.visibility = VISIBLE

list.adapter = VelovAdapter(velovs.sortedWith(compareBy{ it.standNumber }))
} else {
noVelov.visibility = VISIBLE
}
}
}
override fun onParseError() {
onError()
}
})
}
})


return rootView
}

private fun onError() {
activity!!.runOnUiThread {
progress.visibility = GONE
noVelov.visibility = VISIBLE
noVelov.text = "Erreur de récupération des vélovs."
}
}

fun setStationName(stationName: String) : VelovDialog {
this.stationName = stationName
return this
}

fun setStationNb(stationNb: Int) : VelovDialog {
this.stationNumber = stationNb
return this
}
}
63 changes: 63 additions & 0 deletions app/src/main/java/com/gueg/velovwidget/velov/VelovParser.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.gueg.velovwidget.velov

import android.content.Context
import com.android.volley.Response
import com.android.volley.toolbox.Volley
import org.json.JSONArray
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList

class VelovParser {
companion object {
fun parse(context: Context, request: VelovRequest, listener: VelovParserListener) {
Thread {
val queue = Volley.newRequestQueue(context)

queue.add(request.build(
Response.Listener { response ->
val jsonResponse = JSONArray(response)
val velovs = ArrayList<Velov>()

if(jsonResponse.length()>0) {
for(i in 0 until jsonResponse.length()) {
val json = jsonResponse[i] as JSONObject
val rating = json["rating"] as JSONObject

val velov = Velov(
json["standNumber"] as Int,
json["status"] as String,
rating["value"] as Double,
rating["count"] as Int,
formatDate(rating["lastRatingDateTime"] as String),
formatDate(json["createdAt"] as String),
formatDate(json["updatedAt"] as String)
)

velovs.add(velov)
}
}

listener.onParseComplete(velovs)
},
Response.ErrorListener { err ->
err.printStackTrace()
listener.onParseError()
}
))

}.start()
}

// 2019-11-04T19:42:21.325
private fun formatDate(str: String): Date = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS").parse(str)!!

}


interface VelovParserListener {
fun onParseComplete(velovs: ArrayList<Velov>)
fun onParseError()
}
}
34 changes: 34 additions & 0 deletions app/src/main/java/com/gueg/velovwidget/velov/VelovRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.gueg.velovwidget.velov

import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import java.util.*

class VelovRequest(private var stationNb: Int, private val token: String) {

@Suppress("PrivatePropertyName")
private val LINK = "https://api.cyclocity.fr/contracts/lyon/bikes?stationNumber=#STANB#"

fun build(responseListener : Response.Listener<String>, errorListener : Response.ErrorListener) : StringRequest {
return object : StringRequest(
Method.GET,
LINK.replace("#STANB#", stationNb.toString()),
responseListener,
errorListener
) {
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers["Sec-Fetch-Mode"] = "cors"
headers["DNT"] = "1"
headers["Accept-Language"] = "fr"
headers["Authorization"] = "Taknv1 $token"
headers["Content-Type"] = "application/vnd.bikes.v2+json"
headers["Accept"] = "application/vnd.bikes.v2+json"
headers["Referer"] = "https://velov.grandlyon.com/mapping"
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36 OPR/64.0.3417.92"

return headers
}
}
}
}
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/ic_server_loading.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#B2B2B2"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/ic_server_offline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#931F2F"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M14.59,8L12,10.59 9.41,8 8,9.41 10.59,12 8,14.59 9.41,16 12,13.41 14.59,16 16,14.59 13.41,12 16,9.41 14.59,8zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/ic_server_online.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#1FA83B"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_star.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>
48 changes: 41 additions & 7 deletions app/src/main/res/layout/activity_list.xml
Original file line number Diff line number Diff line change
@@ -3,29 +3,63 @@
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:fab="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:id="@+id/widget_list_servers_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"

android:layout_marginTop="3dp"
android:layout_marginBottom="5dp">

<ImageView
android:id="@+id/widget_list_servers_icon"
android:layout_width="30dp"
android:layout_height="30dp"

android:src="@drawable/ic_server_loading"

android:layout_marginStart="60dp"
android:layout_gravity="center_vertical"/>
<TextView
android:id="@+id/widget_list_servers_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"

android:text="@string/servers_loading"
android:textColor="@color/colorTextBlack"
android:textSize="18sp"

android:layout_marginStart="20dp"
android:layout_gravity="center_vertical"/>

</LinearLayout>

<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/widget_list_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"

android:layout_below="@id/widget_list_servers_layout">
<android.support.v7.widget.RecyclerView
android:id="@+id/widget_list_stations"
android:layout_width="match_parent"
android:layout_height="match_parent"

android:background="@color/colorTextWhite" />
</android.support.v4.widget.SwipeRefreshLayout>

<ProgressBar
android:id="@+id/widget_list_progress"
style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
android:layout_width="match_parent"

android:layout_height="10dp"
android:layout_alignParentBottom="true"

android:progressTint="@color/colorPrimary"
android:scaleY="2"

style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
android:layout_marginBottom="-5dp"

android:layout_alignParentBottom="true"
android:layout_marginBottom="-5dp"/>
android:progressTint="@color/colorPrimary"
android:scaleY="2" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/widget_list_fab"
android:layout_width="wrap_content"
57 changes: 57 additions & 0 deletions app/src/main/res/layout/dialog_velov.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="350dp"
android:background="@android:color/transparent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="80dp"

android:background="@color/colorPrimary">

<TextView
android:id="@+id/dialog_velov_stationname"
android:layout_width="match_parent"
android:layout_height="wrap_content"

android:textColor="@color/colorTextWhite"
android:textSize="23sp"
android:textAlignment="center"

android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="250dp">
<android.support.v7.widget.RecyclerView
android:id="@+id/dialog_velov_stationlist"
android:layout_width="match_parent"
android:layout_height="match_parent"

android:visibility="gone"/>
<ProgressBar
android:id="@+id/dialog_velov_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"

android:layout_centerHorizontal="true"
android:layout_margin="70dp"/>
<TextView
android:id="@+id/dialog_velov_novelov"
android:layout_width="match_parent"
android:layout_height="match_parent"

android:textColor="@color/colorTextBlack"
android:textAlignment="center"
android:textSize="19sp"
android:text="Aucun vélov dans cette station."

android:visibility="gone"
android:layout_margin="15dp"/>
</RelativeLayout>


</LinearLayout>
57 changes: 57 additions & 0 deletions app/src/main/res/layout/row_velov.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/velov_bkg"
android:layout_width="match_parent"
android:layout_height="wrap_content"

android:orientation="horizontal"
android:background="@color/colorTextWhite">

<ImageView
android:id="@+id/velov_bikes_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

android:src="@drawable/ic_velo"

android:layout_margin="5dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/velov_stand_nb"
android:layout_width="35dp"
android:layout_height="wrap_content"

android:textColor="@color/colorTextBlack"
android:textSize="17sp"
android:textStyle="bold"

android:text="--"

android:layout_margin="5dp"
android:layout_weight="1"
/>
<ImageView
android:id="@+id/velov_bike_stands_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

android:src="@drawable/ic_star"

android:layout_margin="5dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/velov_rating"
android:layout_width="40dp"
android:layout_height="wrap_content"

android:textColor="@color/colorTextBlack"
android:textSize="17sp"
android:textStyle="bold"

android:text="--"

android:layout_margin="5dp"
android:layout_weight="1"/>
<View android:layout_height="0dp" android:layout_width="0dp"
android:layout_weight="4"/>
</LinearLayout>
7 changes: 7 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
<resources>
<item type="id" name="tag_name" />
<item type="id" name="tag_number" />

<string name="widget_title">Vélo\'v watcher</string>
<string name="widget_last_udpate_time">Dernière actualisation : </string>

<string name="servers_online">Serveurs en ligne</string>
<string name="servers_loading">Test des serveurs...</string>
<string name="servers_offline">Serveurs hors ligne</string>

<string name="menu_change_city">Changer de ville</string>
<string name="menu_refresh">Rafraichir</string>
<string name="menu_settings">Configurer</string>
8 changes: 5 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {

ext.kotlin_version = '1.3.60'

repositories {
mavenCentral()
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'

classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"


// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Thu Jul 26 16:47:40 CEST 2018
#Wed Nov 20 07:57:51 CET 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip

0 comments on commit 1d265b1

Please sign in to comment.