From a2796bfad9af3662d91826f189c2fccd23427dfd Mon Sep 17 00:00:00 2001 From: ex Date: Sat, 15 Oct 2016 02:01:43 +0200 Subject: [PATCH 001/197] Allow some Coins --- .../meteroid/controller/MoneyController.java | 3 +++ meteroid/src/main/res/drawable/euro_05.png | Bin 0 -> 18063 bytes meteroid/src/main/res/drawable/euro_1.png | Bin 0 -> 15551 bytes meteroid/src/main/res/drawable/euro_2.png | Bin 0 -> 17779 bytes 4 files changed, 3 insertions(+) create mode 100644 meteroid/src/main/res/drawable/euro_05.png create mode 100644 meteroid/src/main/res/drawable/euro_1.png create mode 100644 meteroid/src/main/res/drawable/euro_2.png diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MoneyController.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MoneyController.java index 83f59dd..f780680 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MoneyController.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MoneyController.java @@ -33,6 +33,9 @@ public class MoneyController { public static void addMoney(List itemList) { + itemList.add(new Money("50 Cent", "euro_05", -0.5)); + itemList.add(new Money("1 Euro", "euro_1", -1)); + itemList.add(new Money("2 Euro", "euro_2", -2)); itemList.add(new Money("5 Euro", "euro_5", -5)); itemList.add(new Money("10 Euro", "euro_10", -10)); itemList.add(new Money("20 Euro", "euro_20", -20)); diff --git a/meteroid/src/main/res/drawable/euro_05.png b/meteroid/src/main/res/drawable/euro_05.png new file mode 100644 index 0000000000000000000000000000000000000000..28afde72a720fa2e2ec489a14d6be93bcdd8b9fe GIT binary patch literal 18063 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

944*^XzIl#HHer-XRA-{5O=I?1CoPBO3`uAl# zJUktmtf@V9wYA#75|;fKe?Q|92v{IP9UTTCAlc3P{8>f+<;(A+7|4zJ`BLCp8HT~J zvZk(80Q7l&etwo*!O5P7NG=#dzOu6NnVgyuuc@h#fTlN25&^+_0(j76z+E_kFN$c* z&o_U2^Wc0G>q!>&hTDNwkcSvfD@jM++`^XWw^CquyNzkS^fz7^i*pR0o_|p>(W1RN znvH6Xv_ZQcGJ}U!vo{~GA}>0Szu60PHrMj2=8BK`qxT$he&_9AS2iRFPu{+=YI3o@ zx*t1rxNcunV4)!MFjt#eafPnUlnVce9rSgTL&rYR8wgI>a?HY=d#7^ z2zuS(fsn=4MZC(S_*Vhd*Tq0H&mO}^tcu#R+%3Sxlmcxk>2(;!Cd8if_rS}rh&tW4c} ic{Xl4 Date: Fri, 27 Jan 2017 19:44:13 +0100 Subject: [PATCH 002/197] Use Retrofit. --- meteroid/build.gradle | 2 + .../java/de/chaosdorf/meteroid/BuyDrink.java | 17 ++- .../de/chaosdorf/meteroid/PickUsername.java | 3 +- .../de/chaosdorf/meteroid/UserSettings.java | 13 +- .../longrunningio/LongRunningIOGet.java | 6 +- .../longrunningio/LongRunningIOPatch.java | 7 +- .../longrunningio/LongRunningIOPost.java | 7 +- .../java/de/chaosdorf/meteroid/util/API.java | 118 ++++++++++++++++++ .../de/chaosdorf/meteroid/util/Utility.java | 12 ++ 9 files changed, 162 insertions(+), 23 deletions(-) create mode 100644 meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 97947ea..b7a8f3b 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -38,6 +38,8 @@ dependencies { } compile 'org.jetbrains:annotations:13.0' compile 'com.squareup.okhttp3:okhttp:3.3.1' + compile 'com.squareup.retrofit2:retrofit:2.1.0' + compile 'com.squareup.retrofit2:converter-gson:2.1.0' } //see https://stackoverflow.com/a/22183825/2192464 diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index cb643f0..a001f05 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -64,6 +64,7 @@ import de.chaosdorf.meteroid.model.BuyableItem; import de.chaosdorf.meteroid.model.User; import de.chaosdorf.meteroid.model.Drink; +import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.MenuUtility; import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -86,6 +87,8 @@ public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnI private boolean useGridView; private boolean multiUserMode; + + private API api; @Override protected void onCreate(final Bundle savedInstanceState) @@ -141,9 +144,11 @@ public void onClick(View view) backButton.setVisibility(View.GONE); editButton.setVisibility(View.GONE); } + + api = Utility.initializeRetrofit(hostname); - new LongRunningIOGet(this, LongRunningIOTask.GET_USER, hostname + "users/" + userID + ".json"); - new LongRunningIOGet(this, LongRunningIOTask.GET_DRINKS, hostname + "drinks.json"); + new LongRunningIOGet(this, LongRunningIOTask.GET_USER, api.getUser(userID)); + new LongRunningIOGet(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } @Override @@ -314,7 +319,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) break; } } - new LongRunningIOGet(this, LongRunningIOTask.UPDATE_USER, hostname + "users/" + userID + ".json"); + new LongRunningIOGet(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); break; } @@ -338,7 +343,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); } } - new LongRunningIOGet(this, LongRunningIOTask.UPDATE_USER, hostname + "users/" + userID + ".json"); + new LongRunningIOGet(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); break; } } @@ -362,11 +367,11 @@ public void onItemClick(final AdapterView adapterView, final View view, final setProgressBarIndeterminateVisibility(true); if(buyableItem.isDrink()) { - new LongRunningIOGet(this, LongRunningIOTask.BUY_DRINK, hostname + "users/" + userID + "/buy.json?drink=" + ((Drink)buyableItem).getId()); + new LongRunningIOGet(this, LongRunningIOTask.BUY_DRINK, api.buy(userID, ((Drink)buyableItem).getId())); } else { - new LongRunningIOGet(this, LongRunningIOTask.ADD_MONEY, hostname + "users/" + userID + "/deposit.json?amount=" + (-buyableItem.getDonationRecommendation())); + new LongRunningIOGet(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getDonationRecommendation())); } } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 4ca81d8..1dbda5e 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -55,6 +55,7 @@ import de.chaosdorf.meteroid.longrunningio.LongRunningIOGet; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; +import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.MenuUtility; import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -109,7 +110,7 @@ public void onClick(View view) backButton.setVisibility(View.GONE); } - new LongRunningIOGet(this, LongRunningIOTask.GET_USERS, hostname + "users.json"); + new LongRunningIOGet(this, LongRunningIOTask.GET_USERS, Utility.initializeRetrofit(hostname).listUsers()); } @Override diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index c5f0812..0d088f4 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -51,6 +51,7 @@ import de.chaosdorf.meteroid.longrunningio.LongRunningIOGet; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; +import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -65,6 +66,8 @@ public class UserSettings extends MeteroidNetworkActivity private SharedPreferences prefs; private int userID; private String hostname = null; + + private API api; @Override protected void onCreate(final Bundle savedInstanceState) @@ -110,11 +113,13 @@ public void onClick(View view) saveButton.setVisibility(View.GONE); } } + + api = Utility.initializeRetrofit(hostname); if(userID != 0) //existing user { makeReadOnly(); - new LongRunningIOGet(this, LongRunningIOTask.GET_USER, hostname + "users/" + userID + ".json"); + new LongRunningIOGet(this, LongRunningIOTask.GET_USER, api.getUser(userID)); } } @@ -230,8 +235,7 @@ private void saveUser() new LongRunningIOPost( this, LongRunningIOTask.ADD_USER, - hostname + "users.json", - UserController.userToJSONPostParams(user) + api.createUser(user.getName(), user.getEmail(), user.getBalance(), null) ); } else @@ -239,8 +243,7 @@ private void saveUser() new LongRunningIOPatch( this, LongRunningIOTask.EDIT_USER, - hostname + "users/" + user.getId() + ".json", - UserController.userToJSONPostParams(user) + api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), null) ); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java index fabf1a0..a73edef 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java @@ -29,17 +29,17 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Callback; -import okhttp3.Call; +import retrofit2.Call; import okhttp3.Response; import de.chaosdorf.meteroid.MeteroidNetworkActivity; public class LongRunningIOGet extends LongRunningIOBase { - public LongRunningIOGet(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final String url) + public LongRunningIOGet(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) { super(); - Request req = new Request.Builder().url(url).build(); + Request req = call.request(); client.newCall(req).enqueue(newCallback(callback, id)); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java index 3d84d57..fd15116 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java @@ -31,7 +31,7 @@ import okhttp3.RequestBody; import okhttp3.Request; import okhttp3.Callback; -import okhttp3.Call; +import retrofit2.Call; import okhttp3.Response; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -39,11 +39,10 @@ public class LongRunningIOPatch extends LongRunningIOBase { public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - public LongRunningIOPatch(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final String url, final String patchData) + public LongRunningIOPatch(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) { super(); - RequestBody reqbody = RequestBody.create(JSON, patchData); - Request req = new Request.Builder().url(url).patch(reqbody).build(); + Request req = call.request(); client.newCall(req).enqueue(newCallback(callback, id)); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java index 5c55eb7..33129c7 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java @@ -31,7 +31,7 @@ import okhttp3.RequestBody; import okhttp3.Request; import okhttp3.Callback; -import okhttp3.Call; +import retrofit2.Call; import okhttp3.Response; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -39,11 +39,10 @@ public class LongRunningIOPost extends LongRunningIOBase { public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - public LongRunningIOPost(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final String url, final String postData) + public LongRunningIOPost(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) { super(); - RequestBody reqbody = RequestBody.create(JSON, postData); - Request req = new Request.Builder().url(url).post(reqbody).build(); + Request req = call.request(); client.newCall(req).enqueue(newCallback(callback, id)); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java new file mode 100644 index 0000000..335a3ba --- /dev/null +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Chaosdorf e.V. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +package de.chaosdorf.meteroid.util; + +import retrofit2.http.*; +import retrofit2.Call; + +import java.util.List; + +import de.chaosdorf.meteroid.model.*; + +public interface API +{ + + /*// list (some) audits + @GET("audits.json") + Call> listAudits( + @Query("start_date[year]") int fromYear, + @Query("start_date[month]") int fromMonth, + @Query("start_date[day]") int fromDay, + @Query("end_date[year]") int toYear, + @Query("end_date[month]") int toMonth, + @Query("end_date[day]") int toDay + );*/ + + // list all drinks + @GET("drinks.json") + Call> listDrinks(); + + // retrieves information about a drinks + @GET("drinks/{did}.json") + Call getDrink(@Path("did") int did); + + // TODO: create and modify a drink + + // deletes a drink + @DELETE("drinks/{did}.json") + Call deleteDrink(@Path("did") int did); + + // lists all users + @GET("users.json") + Call> listUsers(); + + // retrieves information about a user + @GET("users/{uid}.json") + Call getUser(@Path("uid") int uid); + + // creates a new user + @POST("users.json") + Call createUser( + @Query("user[name]") String name, + @Query("user[email]") String email, + @Query("user[balance]") Double balance, + @Query("user[active]") Boolean active + ); + + // modifys an existing user + @PATCH("users/{uid}.json") + Call editUser( + @Path("uid") int uid, + @Query("user[name]") String name, + @Query("user[email]") String email, + @Query("user[balance]") Double balance, + @Query("user[active]") Boolean active + ); + + // deletes an existing user + @DELETE("users/{uid}.json") + Call deleteUser(@Path("uid") int uid); + + // deposits money + @GET("users/{uid}/deposit.json") + Call deposit( + @Path("uid") int uid, + @Query("amount") double amount + ); + + // removes money from the balance + @GET("users/{uid}/pay.json") + Call pay( + @Path("uid") int uid, + @Query("amount") double amount + ); + + // buys a drink + @GET("users/{uid}/buy.json") + Call buy( + @Path("uid") int uid, + @Query("drink") int did + ); + + /*// retrieves various statistics + @GET("users/stats.json") + Call getUsersStats();*/ + +} \ No newline at end of file diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index 295a65b..9958367 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -43,6 +43,9 @@ import de.chaosdorf.meteroid.model.BuyableItem; import de.chaosdorf.meteroid.model.User; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + public class Utility { public static void displayToastMessage(final Activity activity, final String message) @@ -152,4 +155,13 @@ private static String md5Hex(final String message) } return null; } + + public static API initializeRetrofit(String url) + { + return new Retrofit.Builder() + .baseUrl(url) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(API.class); + } } From f31ba26e97a57e028c7c67b73499e202207ced11 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 27 Jan 2017 19:47:03 +0100 Subject: [PATCH 003/197] UserController: Remove userToJSONPostParams. --- .../meteroid/controller/UserController.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java index 8ebb7b3..f67add6 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java @@ -88,19 +88,4 @@ private static User parseUserFromJSONObject(final JSONObject jsonObject) return null; } } - - public static String userToJSONPostParams(final User user) - { - final JSONObject jo = new JSONObject(); - try - { - JSONObject ujo = new JSONObject(); - ujo.put("name", user.getName()); - ujo.put("email", user.getEmail()); - ujo.put("balance", String.valueOf(user.getBalance())); - jo.put("user", ujo); - } - catch (JSONException e){} - return jo.toString(); - } } From ee43366cdc489d337de6c80cefeb63719cdca22f Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 27 Jan 2017 19:54:14 +0100 Subject: [PATCH 004/197] longrunningio: Remove unused imports. --- .../meteroid/longrunningio/LongRunningIOBase.java | 1 - .../meteroid/longrunningio/LongRunningIOGet.java | 7 +------ .../meteroid/longrunningio/LongRunningIOPatch.java | 8 +------- .../meteroid/longrunningio/LongRunningIOPost.java | 8 +------- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOBase.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOBase.java index b4238b8..1348e7b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOBase.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOBase.java @@ -27,7 +27,6 @@ import java.io.IOException; import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.Callback; import okhttp3.Call; import okhttp3.Response; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java index a73edef..8edbb34 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java @@ -26,11 +26,7 @@ import java.io.IOException; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Callback; import retrofit2.Call; -import okhttp3.Response; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -39,7 +35,6 @@ public class LongRunningIOGet extends LongRunningIOBase public LongRunningIOGet(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) { super(); - Request req = call.request(); - client.newCall(req).enqueue(newCallback(callback, id)); + client.newCall(call.request()).enqueue(newCallback(callback, id)); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java index fd15116..10958b4 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java @@ -27,12 +27,7 @@ import java.io.IOException; import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.RequestBody; -import okhttp3.Request; -import okhttp3.Callback; import retrofit2.Call; -import okhttp3.Response; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -42,7 +37,6 @@ public class LongRunningIOPatch extends LongRunningIOBase public LongRunningIOPatch(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) { super(); - Request req = call.request(); - client.newCall(req).enqueue(newCallback(callback, id)); + client.newCall(call.request()).enqueue(newCallback(callback, id)); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java index 33129c7..a864414 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java @@ -27,12 +27,7 @@ import java.io.IOException; import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.RequestBody; -import okhttp3.Request; -import okhttp3.Callback; import retrofit2.Call; -import okhttp3.Response; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -42,7 +37,6 @@ public class LongRunningIOPost extends LongRunningIOBase public LongRunningIOPost(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) { super(); - Request req = call.request(); - client.newCall(req).enqueue(newCallback(callback, id)); + client.newCall(call.request()).enqueue(newCallback(callback, id)); } } From 7e23a750bd3dc00e1e147d28bfde45aa4f5eaab6 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 27 Jan 2017 20:19:13 +0100 Subject: [PATCH 005/197] Move more things into MeteroidNetworkActivity. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 17 ----------- .../meteroid/MeteroidNetworkActivity.java | 28 ++++++++++++++++++- .../de/chaosdorf/meteroid/PickUsername.java | 8 ------ .../de/chaosdorf/meteroid/UserSettings.java | 21 -------------- 4 files changed, 27 insertions(+), 47 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index a001f05..c7c827f 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -25,12 +25,9 @@ package de.chaosdorf.meteroid; import android.app.ActionBar; -import android.app.Activity; import android.content.Context; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Build; -import android.preference.PreferenceManager; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; @@ -49,7 +46,6 @@ import org.jetbrains.annotations.NotNull; -import java.text.DecimalFormat; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -64,37 +60,29 @@ import de.chaosdorf.meteroid.model.BuyableItem; import de.chaosdorf.meteroid.model.User; import de.chaosdorf.meteroid.model.Drink; -import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.MenuUtility; import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnItemClickListener { - private final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00 '\u20AC'"); - private final AtomicBoolean isBuying = new AtomicBoolean(true); private final AtomicReference buyingItem = new AtomicReference(null); - private Activity activity = null; private ProgressBar progressBar = null; private GridView gridView = null; private ListView listView = null; - private String hostname = null; - private int userID = 0; private User user; private boolean useGridView; private boolean multiUserMode; - private API api; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - activity = this; requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.activity_buy_drink); @@ -102,9 +90,6 @@ protected void onCreate(final Bundle savedInstanceState) gridView = (GridView) findViewById(R.id.grid_view); listView = (ListView) findViewById(R.id.list_view); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - hostname = prefs.getString("hostname", null); - userID = prefs.getInt("userid", 0); useGridView = prefs.getBoolean("use_grid_view", false); multiUserMode = prefs.getBoolean("multi_user_mode", false); @@ -145,8 +130,6 @@ public void onClick(View view) editButton.setVisibility(View.GONE); } - api = Utility.initializeRetrofit(hostname); - new LongRunningIOGet(this, LongRunningIOTask.GET_USER, api.getUser(userID)); new LongRunningIOGet(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java index 5fd6988..cc48f0a 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java @@ -25,9 +25,35 @@ package de.chaosdorf.meteroid; import android.app.Activity; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; + +import java.text.DecimalFormat; import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; +import de.chaosdorf.meteroid.util.API; +import de.chaosdorf.meteroid.util.Utility; public abstract class MeteroidNetworkActivity extends Activity implements LongRunningIOCallback -{} +{ + protected DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00 '\u20AC'"); + + protected Activity activity; + protected API api; + protected String hostname; + protected int userID; + protected SharedPreferences prefs; + + @Override + protected void onCreate(final Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + activity = this; + prefs = PreferenceManager.getDefaultSharedPreferences(this); + hostname = prefs.getString("hostname", null); + userID = prefs.getInt("userid", 0); + api = Utility.initializeRetrofit(hostname); + } +} diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 1dbda5e..bbbf418 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -25,9 +25,7 @@ package de.chaosdorf.meteroid; import android.app.ActionBar; -import android.app.Activity; import android.content.Context; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Build; import android.preference.PreferenceManager; @@ -55,7 +53,6 @@ import de.chaosdorf.meteroid.longrunningio.LongRunningIOGet; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; -import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.MenuUtility; import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; @@ -64,7 +61,6 @@ public class PickUsername extends MeteroidNetworkActivity implements AdapterView { private static final int NEW_USER_ID = -1; - private Activity activity = null; private ProgressBar progressBar = null; private GridView gridView = null; private boolean multiUserMode = false; @@ -74,14 +70,11 @@ public class PickUsername extends MeteroidNetworkActivity implements AdapterView protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - activity = this; setContentView(R.layout.activity_pick_username); progressBar = (ProgressBar) findViewById(R.id.progress_bar); gridView = (GridView) findViewById(R.id.grid_view); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - final String hostname = prefs.getString("hostname", null); multiUserMode = prefs.getBoolean("multi_user_mode", false); final ImageButton backButton = (ImageButton) findViewById(R.id.button_back); @@ -212,7 +205,6 @@ public void onItemClick(final AdapterView adapterView, final View view, final } else { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs.edit().putInt("userid", user.getId()).apply(); Utility.startActivity(this, BuyDrink.class); } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 0d088f4..38395bb 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -25,12 +25,9 @@ package de.chaosdorf.meteroid; import android.app.ActionBar; -import android.app.Activity; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Build; -import android.preference.PreferenceManager; import android.view.KeyEvent; import android.view.View; import android.view.Menu; @@ -41,7 +38,6 @@ import org.jetbrains.annotations.NotNull; -import java.text.DecimalFormat; import java.text.ParseException; import java.util.Date; @@ -51,38 +47,25 @@ import de.chaosdorf.meteroid.longrunningio.LongRunningIOGet; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; -import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; public class UserSettings extends MeteroidNetworkActivity { - private final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00"); - - private Activity activity = null; private TextView usernameText; private TextView emailText; private TextView balanceText; - private SharedPreferences prefs; - private int userID; - private String hostname = null; - - private API api; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - activity = this; requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.activity_user_settings); usernameText = (TextView) findViewById(R.id.username); emailText = (TextView) findViewById(R.id.email); balanceText = (TextView) findViewById(R.id.balance); - prefs = PreferenceManager.getDefaultSharedPreferences(this); - userID = prefs.getInt("userid", 0); - hostname = prefs.getString("hostname", null); final ImageButton backButton = (ImageButton) findViewById(R.id.button_back); backButton.setOnClickListener(new View.OnClickListener() @@ -114,8 +97,6 @@ public void onClick(View view) } } - api = Utility.initializeRetrofit(hostname); - if(userID != 0) //existing user { makeReadOnly(); @@ -228,8 +209,6 @@ private void saveUser() new Date() ); - final String hostname = prefs.getString("hostname", null); - if(userID == 0) //new user { new LongRunningIOPost( From 72e0bb751b37b528788bc7ae54fc7312a5dbe76e Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 2 Feb 2017 20:02:12 +0100 Subject: [PATCH 006/197] longrunningio: Merge the different HTTP methods. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 14 +++---- .../de/chaosdorf/meteroid/PickUsername.java | 4 +- .../de/chaosdorf/meteroid/UserSettings.java | 10 ++--- .../longrunningio/LongRunningIOGet.java | 40 ------------------ .../longrunningio/LongRunningIOPatch.java | 42 ------------------- .../longrunningio/LongRunningIOPost.java | 42 ------------------- ...gIOBase.java => LongRunningIORequest.java} | 7 ++-- 7 files changed, 16 insertions(+), 143 deletions(-) delete mode 100644 meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java delete mode 100644 meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java delete mode 100644 meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java rename meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/{LongRunningIOBase.java => LongRunningIORequest.java} (92%) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index c7c827f..a65bf7c 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -55,7 +55,7 @@ import de.chaosdorf.meteroid.controller.DrinkController; import de.chaosdorf.meteroid.controller.MoneyController; import de.chaosdorf.meteroid.controller.UserController; -import de.chaosdorf.meteroid.longrunningio.LongRunningIOGet; +import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.BuyableItem; import de.chaosdorf.meteroid.model.User; @@ -130,8 +130,8 @@ public void onClick(View view) editButton.setVisibility(View.GONE); } - new LongRunningIOGet(this, LongRunningIOTask.GET_USER, api.getUser(userID)); - new LongRunningIOGet(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); + new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } @Override @@ -302,7 +302,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) break; } } - new LongRunningIOGet(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); break; } @@ -326,7 +326,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); } } - new LongRunningIOGet(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); break; } } @@ -350,11 +350,11 @@ public void onItemClick(final AdapterView adapterView, final View view, final setProgressBarIndeterminateVisibility(true); if(buyableItem.isDrink()) { - new LongRunningIOGet(this, LongRunningIOTask.BUY_DRINK, api.buy(userID, ((Drink)buyableItem).getId())); + new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy(userID, ((Drink)buyableItem).getId())); } else { - new LongRunningIOGet(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getDonationRecommendation())); + new LongRunningIORequest(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getDonationRecommendation())); } } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index bbbf418..a28004c 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -50,7 +50,7 @@ import java.util.List; import de.chaosdorf.meteroid.controller.UserController; -import de.chaosdorf.meteroid.longrunningio.LongRunningIOGet; +import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; import de.chaosdorf.meteroid.util.MenuUtility; @@ -103,7 +103,7 @@ public void onClick(View view) backButton.setVisibility(View.GONE); } - new LongRunningIOGet(this, LongRunningIOTask.GET_USERS, Utility.initializeRetrofit(hostname).listUsers()); + new LongRunningIORequest(this, LongRunningIOTask.GET_USERS, Utility.initializeRetrofit(hostname).listUsers()); } @Override diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 38395bb..930638d 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -42,9 +42,7 @@ import java.util.Date; import de.chaosdorf.meteroid.controller.UserController; -import de.chaosdorf.meteroid.longrunningio.LongRunningIOPost; -import de.chaosdorf.meteroid.longrunningio.LongRunningIOPatch; -import de.chaosdorf.meteroid.longrunningio.LongRunningIOGet; +import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; import de.chaosdorf.meteroid.util.Utility; @@ -100,7 +98,7 @@ public void onClick(View view) if(userID != 0) //existing user { makeReadOnly(); - new LongRunningIOGet(this, LongRunningIOTask.GET_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); } } @@ -211,7 +209,7 @@ private void saveUser() if(userID == 0) //new user { - new LongRunningIOPost( + new LongRunningIORequest( this, LongRunningIOTask.ADD_USER, api.createUser(user.getName(), user.getEmail(), user.getBalance(), null) @@ -219,7 +217,7 @@ private void saveUser() } else { - new LongRunningIOPatch( + new LongRunningIORequest( this, LongRunningIOTask.EDIT_USER, api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), null) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java deleted file mode 100644 index 8edbb34..0000000 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOGet.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (c) 2013-2016 Chaosdorf e.V. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -package de.chaosdorf.meteroid.longrunningio; - -import java.io.IOException; - -import retrofit2.Call; - -import de.chaosdorf.meteroid.MeteroidNetworkActivity; - -public class LongRunningIOGet extends LongRunningIOBase -{ - public LongRunningIOGet(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) - { - super(); - client.newCall(call.request()).enqueue(newCallback(callback, id)); - } -} diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java deleted file mode 100644 index 10958b4..0000000 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPatch.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (c) 2013-2016 Chaosdorf e.V. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -package de.chaosdorf.meteroid.longrunningio; - -import java.io.IOException; - -import okhttp3.MediaType; -import retrofit2.Call; - -import de.chaosdorf.meteroid.MeteroidNetworkActivity; - -public class LongRunningIOPatch extends LongRunningIOBase -{ - public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - public LongRunningIOPatch(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) - { - super(); - client.newCall(call.request()).enqueue(newCallback(callback, id)); - } -} diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java deleted file mode 100644 index a864414..0000000 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOPost.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (c) 2013-2016 Chaosdorf e.V. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -package de.chaosdorf.meteroid.longrunningio; - -import java.io.IOException; - -import okhttp3.MediaType; -import retrofit2.Call; - -import de.chaosdorf.meteroid.MeteroidNetworkActivity; - -public class LongRunningIOPost extends LongRunningIOBase -{ - public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - public LongRunningIOPost(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) - { - super(); - client.newCall(call.request()).enqueue(newCallback(callback, id)); - } -} diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOBase.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java similarity index 92% rename from meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOBase.java rename to meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java index 1348e7b..f5ef22c 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOBase.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java @@ -33,13 +33,12 @@ import de.chaosdorf.meteroid.MeteroidNetworkActivity; -public class LongRunningIOBase +public class LongRunningIORequest { - protected OkHttpClient client; - public LongRunningIOBase() + public LongRunningIORequest(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final retrofit2.Call call) { - client = new OkHttpClient(); + new OkHttpClient().newCall(call.request()).enqueue(newCallback(callback, id)); } protected Callback newCallback(final MeteroidNetworkActivity callback, final LongRunningIOTask id) From d1cefbf055e5749d8e2a547e6dc9a74375ceaf46 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 09:11:21 +0100 Subject: [PATCH 007/197] Remove superflous != null checks --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 167 +++++++++--------- .../de/chaosdorf/meteroid/PickUsername.java | 2 +- .../de/chaosdorf/meteroid/UserSettings.java | 31 ++-- 3 files changed, 97 insertions(+), 103 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index a65bf7c..08ab2fc 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -229,106 +229,103 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa @Override public void processIOResult(final LongRunningIOTask task, final String json) { - if (json != null) + switch (task) { - switch (task) + // Parse user data + case GET_USER: + case UPDATE_USER: { - // Parse user data - case GET_USER: - case UPDATE_USER: + user = UserController.parseUserFromJSON(json); + if (task == LongRunningIOTask.GET_USER) { - user = UserController.parseUserFromJSON(json); - if (task == LongRunningIOTask.GET_USER) - { - final TextView label = (TextView) findViewById(R.id.username); - final ImageView icon = (ImageView) findViewById(R.id.icon); - label.setText(user.getName()); - Utility.loadGravatarImage(this, icon, user); - } - final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance())); - isBuying.set(false); - setProgressBarIndeterminateVisibility(false); - break; + final TextView label = (TextView) findViewById(R.id.username); + final ImageView icon = (ImageView) findViewById(R.id.icon); + label.setText(user.getName()); + Utility.loadGravatarImage(this, icon, user); } - - // Parse drinks - case GET_DRINKS: + final TextView balance = (TextView) findViewById(R.id.balance); + balance.setText(DECIMAL_FORMAT.format(user.getBalance())); + isBuying.set(false); + setProgressBarIndeterminateVisibility(false); + break; + } + + // Parse drinks + case GET_DRINKS: + { + final List buyableItemList = DrinkController.parseAllDrinksFromJSON(json, hostname); + MoneyController.addMoney(buyableItemList); + Collections.sort(buyableItemList, new BuyableComparator()); + + final BuyableItemAdapter buyableItemAdapter = new BuyableItemAdapter(buyableItemList); + if (useGridView) { - final List buyableItemList = DrinkController.parseAllDrinksFromJSON(json, hostname); - MoneyController.addMoney(buyableItemList); - Collections.sort(buyableItemList, new BuyableComparator()); - - final BuyableItemAdapter buyableItemAdapter = new BuyableItemAdapter(buyableItemList); - if (useGridView) + gridView.setAdapter(buyableItemAdapter); + gridView.setOnItemClickListener(this); + gridView.setVisibility(View.VISIBLE); + } + else + { + listView.setAdapter(buyableItemAdapter); + listView.setOnItemClickListener(this); + listView.setVisibility(View.VISIBLE); + } + progressBar.setVisibility(View.GONE); + break; + } + + // Bought drink + case BUY_DRINK: + { + final BuyableItem buyableItem = buyingItem.get(); + if (buyableItem != null) + { + buyingItem.set(null); + Utility.displayToastMessage(this, + String.format( + getResources().getString(R.string.buy_drink_bought_drink), + buyableItem.getName(), + DECIMAL_FORMAT.format(buyableItem.getDonationRecommendation()) + ) + ); + // Adjust the displayed balance to give an immediate user feedback + if (user != null) { - gridView.setAdapter(buyableItemAdapter); - gridView.setOnItemClickListener(this); - gridView.setVisibility(View.VISIBLE); + final TextView balance = (TextView) findViewById(R.id.balance); + balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); } - else + if (multiUserMode) { - listView.setAdapter(buyableItemAdapter); - listView.setOnItemClickListener(this); - listView.setVisibility(View.VISIBLE); + Utility.startActivity(this, PickUsername.class); + break; } - progressBar.setVisibility(View.GONE); - break; } - - // Bought drink - case BUY_DRINK: + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + break; + } + + // Added money + case ADD_MONEY: + { + final BuyableItem buyableItem = buyingItem.get(); + if (buyableItem != null) { - final BuyableItem buyableItem = buyingItem.get(); - if (buyableItem != null) - { - buyingItem.set(null); - Utility.displayToastMessage(this, + buyingItem.set(null); + Utility.displayToastMessage(this, String.format( - getResources().getString(R.string.buy_drink_bought_drink), - buyableItem.getName(), - DECIMAL_FORMAT.format(buyableItem.getDonationRecommendation()) - ) - ); - // Adjust the displayed balance to give an immediate user feedback - if (user != null) - { - final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); - } - if (multiUserMode) - { - Utility.startActivity(this, PickUsername.class); - break; - } - } - new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); - break; - } - - // Added money - case ADD_MONEY: - { - final BuyableItem buyableItem = buyingItem.get(); - if (buyableItem != null) + getResources().getString(R.string.buy_drink_added_money), + DECIMAL_FORMAT.format(-buyableItem.getDonationRecommendation()) + ) + ); + // Adjust the displayed balance to give an immediate user feedback + if (user != null) { - buyingItem.set(null); - Utility.displayToastMessage(this, - String.format( - getResources().getString(R.string.buy_drink_added_money), - DECIMAL_FORMAT.format(-buyableItem.getDonationRecommendation()) - ) - ); - // Adjust the displayed balance to give an immediate user feedback - if (user != null) - { - final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); - } + final TextView balance = (TextView) findViewById(R.id.balance); + balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); } - new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); - break; } + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + break; } } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index a28004c..b8bc431 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -177,7 +177,7 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa public void processIOResult(final LongRunningIOTask task, final String json) { final PickUsername pickusername = this; - if (task == LongRunningIOTask.GET_USERS && json != null) + if (task == LongRunningIOTask.GET_USERS) { final List itemList = UserController.parseAllUsersFromJSON(json); if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 930638d..ea864eb 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -236,24 +236,21 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa public void processIOResult(final LongRunningIOTask task, final String json) { final UserSettings usersettings = this; - if (json != null) + switch(task) { - switch(task) - { - case ADD_USER: - Utility.startActivity(usersettings, PickUsername.class); - break; - case EDIT_USER: - Utility.startActivity(usersettings, BuyDrink.class); - break; - case GET_USER: - User user = UserController.parseUserFromJSON(json); - usernameText.setText(user.getName()); - emailText.setText(user.getEmail()); - balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); - makeWritable(); - break; - } + case ADD_USER: + Utility.startActivity(usersettings, PickUsername.class); + break; + case EDIT_USER: + Utility.startActivity(usersettings, BuyDrink.class); + break; + case GET_USER: + User user = UserController.parseUserFromJSON(json); + usernameText.setText(user.getName()); + emailText.setText(user.getEmail()); + balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); + makeWritable(); + break; } } } From 67985ad57b8561251b77b7e3c99b86662e77ee77 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 09:53:34 +0100 Subject: [PATCH 008/197] Make Drink more similar to the stuff we get from Mete. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 4 +- .../meteroid/controller/DrinkController.java | 21 ++----- .../chaosdorf/meteroid/model/BuyableItem.java | 2 +- .../de/chaosdorf/meteroid/model/Drink.java | 55 +++++++------------ .../de/chaosdorf/meteroid/model/Money.java | 2 +- .../de/chaosdorf/meteroid/util/Utility.java | 6 +- 6 files changed, 32 insertions(+), 58 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 08ab2fc..1043588 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -253,7 +253,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) // Parse drinks case GET_DRINKS: { - final List buyableItemList = DrinkController.parseAllDrinksFromJSON(json, hostname); + final List buyableItemList = DrinkController.parseAllDrinksFromJSON(json); MoneyController.addMoney(buyableItemList); Collections.sort(buyableItemList, new BuyableComparator()); @@ -384,7 +384,7 @@ public View getView(final int position, final View convertView, final ViewGroup final BuyableItem buyableItem = drinkList.get(position); final ImageView icon = (ImageView) view.findViewById(R.id.icon); - Utility.loadBuyableItemImage(activity, icon, buyableItem); + Utility.loadBuyableItemImage(activity, icon, buyableItem, hostname); final TextView label = (TextView) view.findViewById(R.id.label); label.setText(createLabel(buyableItem, useGridView)); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java index ddb52e7..9f6b57f 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java @@ -28,10 +28,7 @@ import org.json.JSONException; import org.json.JSONObject; -import java.net.MalformedURLException; -import java.net.URL; import java.util.ArrayList; -import java.util.Date; import java.util.List; import de.chaosdorf.meteroid.model.BuyableItem; @@ -39,16 +36,15 @@ public class DrinkController { - public static List parseAllDrinksFromJSON(final String json, final String hostname) + public static List parseAllDrinksFromJSON(final String json) { final List list = new ArrayList(); try { - final URL baseUrl = new URL(hostname); final JSONArray jsonArray = new JSONArray(json); for (int i = 0; i < jsonArray.length(); i++) { - final Drink drink = parseDrinkFromJSONObject(jsonArray.getJSONObject(i), baseUrl); + final Drink drink = parseDrinkFromJSONObject(jsonArray.getJSONObject(i)); if (drink != null) { list.add(drink); @@ -60,13 +56,9 @@ public static List parseAllDrinksFromJSON(final String json, final { return null; } - catch (MalformedURLException ignored) - { - return null; - } } - private static Drink parseDrinkFromJSONObject(final JSONObject jsonObject, final URL baseURL) + private static Drink parseDrinkFromJSONObject(final JSONObject jsonObject) { try { @@ -76,11 +68,8 @@ private static Drink parseDrinkFromJSONObject(final JSONObject jsonObject, final jsonObject.getString("logo_url"), jsonObject.getDouble("bottle_size"), jsonObject.getString("caffeine"), - jsonObject.getDouble("donation_recommendation"), - new Date(), - new Date(), - baseURL - ); + jsonObject.getDouble("donation_recommendation") + ); } catch (JSONException ignored) { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java index c6f9f35..3562435 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java @@ -28,7 +28,7 @@ public interface BuyableItem { public String getName(); - public String getLogoUrl(); + public String getLogoUrl(String hostname); public double getDonationRecommendation(); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java index d64afef..fec3330 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java @@ -32,25 +32,20 @@ public class Drink implements BuyableItem { private final int id; private final String name; - private final String logoUrl; + private final String logo_url; - private final double bottleSize; + private final double bottle_size; private final String caffeine; - private final double donationRecommendation; + private final double donation_recommendation; - private final Date createdAt; - private final Date updatedAt; - - public Drink(final int id, final String name, final String logoUrl, final double bottleSize, final String caffeine, final double donationRecommendation, final Date created_at, final Date updated_at, final URL baseURL) + public Drink(final int id, final String name, final String logo_url, final double bottle_size, final String caffeine, final double donation_recommendation) { this.id = id; this.name = name; - this.logoUrl = createLogoURL(logoUrl, baseURL); - this.bottleSize = bottleSize; + this.logo_url = logo_url; + this.bottle_size = bottle_size; this.caffeine = caffeine; - this.donationRecommendation = donationRecommendation; - this.createdAt = created_at; - this.updatedAt = updated_at; + this.donation_recommendation = donation_recommendation; } public int getId() @@ -63,14 +58,21 @@ public String getName() return name; } - public String getLogoUrl() + public String getLogoUrl(String hostname) { - return logoUrl; + try + { + return createLogoURL(logo_url, new URL(hostname)); + } + catch (MalformedURLException ignored) + { + return null; + } } public double getBottleSize() { - return bottleSize; + return bottle_size; } public String getCaffeine() @@ -80,17 +82,7 @@ public String getCaffeine() public double getDonationRecommendation() { - return donationRecommendation; - } - - public Date getCreatedAt() - { - return createdAt; - } - - public Date getUpdatedAt() - { - return updatedAt; + return donation_recommendation; } public boolean isDrink() @@ -98,19 +90,12 @@ public boolean isDrink() return true; } - private String createLogoURL(final String logoUrl, final URL baseURL) + private String createLogoURL(final String logoUrl, final URL baseURL) throws MalformedURLException { if (logoUrl.isEmpty()) { return null; } - try - { - return new URL(baseURL, logoUrl).toString(); - } - catch (MalformedURLException ignored) - { - } - return null; + return new URL(baseURL, logoUrl).toString(); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java index 9eb4262..302aa63 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java @@ -45,7 +45,7 @@ public String getName() } @Override - public String getLogoUrl() + public String getLogoUrl(String hostname) { return logoUrl; } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index 9958367..6ebacb9 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -110,7 +110,7 @@ public static void loadGravatarImage(final Activity activity, final ImageView ic icon.setImageBitmap(ImageLoaderSingleton.getUserDefaultImage()); } - public static void loadBuyableItemImage(final Activity activity, final ImageView icon, final BuyableItem buyableItem) + public static void loadBuyableItemImage(final Activity activity, final ImageView icon, final BuyableItem buyableItem, final String hostname) { icon.setContentDescription(buyableItem.getName()); if (buyableItem.isDrink()) @@ -118,7 +118,7 @@ public static void loadBuyableItemImage(final Activity activity, final ImageView final URL url; try { - url = new URL(buyableItem.getLogoUrl()); + url = new URL(buyableItem.getLogoUrl(hostname)); ImageLoaderSingleton.getInstance(activity).displayImage(url, icon, ImageLoaderSingleton.getDrinkDefaultImage()); } catch (MalformedURLException ignored) @@ -127,7 +127,7 @@ public static void loadBuyableItemImage(final Activity activity, final ImageView } return; } - final int iconID = activity.getResources().getIdentifier(buyableItem.getLogoUrl(), "drawable", activity.getPackageName()); + final int iconID = activity.getResources().getIdentifier(buyableItem.getLogoUrl(hostname), "drawable", activity.getPackageName()); icon.setImageResource(iconID > 0 ? iconID : R.drawable.euro_5); } From 57c42f34a982057be8ce73233c43da73c582be29 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 10:48:55 +0100 Subject: [PATCH 009/197] Make User more similar to the stuff we get from Mete. --- .../de/chaosdorf/meteroid/PickUsername.java | 2 +- .../de/chaosdorf/meteroid/UserSettings.java | 4 +--- .../meteroid/controller/UserController.java | 5 +---- .../java/de/chaosdorf/meteroid/model/User.java | 18 +----------------- 4 files changed, 4 insertions(+), 25 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index b8bc431..fe7b5f0 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -182,7 +182,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) final List itemList = UserController.parseAllUsersFromJSON(json); if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0, new Date(), new Date())); + itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0)); } final UserAdapter userAdapter = new UserAdapter(itemList); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index ea864eb..7dc19fa 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -202,9 +202,7 @@ private void saveUser() final User user = new User(userID, username.toString(), emailValue, - balanceValue, - new Date(), - new Date() + balanceValue ); if(userID == 0) //new user diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java index f67add6..aa2462b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java @@ -29,7 +29,6 @@ import org.json.JSONObject; import java.util.ArrayList; -import java.util.Date; import java.util.List; import de.chaosdorf.meteroid.model.User; @@ -78,9 +77,7 @@ private static User parseUserFromJSONObject(final JSONObject jsonObject) jsonObject.getInt("id"), jsonObject.getString("name"), jsonObject.getString("email"), - jsonObject.getDouble("balance"), - new Date(), - new Date() + jsonObject.getDouble("balance") ); } catch (JSONException ignored) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java index a29feeb..35d8af1 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java @@ -24,25 +24,19 @@ package de.chaosdorf.meteroid.model; -import java.util.Date; - public class User { private final int id; private final String name; private final String email; private final double balance; - private final Date createdAt; - private final Date updatedAt; - public User(final int id, final String name, final String email, final double balance, final Date createdAt, final Date updated_at) + public User(final int id, final String name, final String email, final double balance) { this.id = id; this.name = name; this.email = email; this.balance = balance; - this.createdAt = createdAt; - this.updatedAt = updated_at; } public int getId() @@ -64,14 +58,4 @@ public double getBalance() { return balance; } - - public Date getCreatedAt() - { - return createdAt; - } - - public Date getUpdatedAt() - { - return updatedAt; - } } From 491510aa469c658a96064108a2c997447fa5ca36 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 10:54:35 +0100 Subject: [PATCH 010/197] PickUsername: Use already created api of MeteroidNetworkActivity. --- meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index fe7b5f0..2e599cf 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -103,7 +103,7 @@ public void onClick(View view) backButton.setVisibility(View.GONE); } - new LongRunningIORequest(this, LongRunningIOTask.GET_USERS, Utility.initializeRetrofit(hostname).listUsers()); + new LongRunningIORequest(this, LongRunningIOTask.GET_USERS, api.listUsers()); } @Override From 7d5dec77602ce66a4f3b5b7592a7fbcee66f467e Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 10:57:36 +0100 Subject: [PATCH 011/197] Move initializeRetrofit from Utility to MeteroidNetworkActivity. --- .../meteroid/MeteroidNetworkActivity.java | 14 +++++++++++++- .../java/de/chaosdorf/meteroid/util/Utility.java | 12 ------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java index cc48f0a..8fbc443 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java @@ -31,6 +31,9 @@ import java.text.DecimalFormat; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.Utility; @@ -54,6 +57,15 @@ protected void onCreate(final Bundle savedInstanceState) prefs = PreferenceManager.getDefaultSharedPreferences(this); hostname = prefs.getString("hostname", null); userID = prefs.getInt("userid", 0); - api = Utility.initializeRetrofit(hostname); + api = initializeRetrofit(hostname); + } + + private API initializeRetrofit(String url) + { + return new Retrofit.Builder() + .baseUrl(url) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(API.class); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index 6ebacb9..a79052e 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -43,9 +43,6 @@ import de.chaosdorf.meteroid.model.BuyableItem; import de.chaosdorf.meteroid.model.User; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - public class Utility { public static void displayToastMessage(final Activity activity, final String message) @@ -155,13 +152,4 @@ private static String md5Hex(final String message) } return null; } - - public static API initializeRetrofit(String url) - { - return new Retrofit.Builder() - .baseUrl(url) - .addConverterFactory(GsonConverterFactory.create()) - .build() - .create(API.class); - } } From 180dfe4c12eae9db0d7080aeb80a4a832c62d86f Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 11:07:49 +0100 Subject: [PATCH 012/197] LongRunningIO: Add logging. --- .../meteroid/longrunningio/LongRunningIORequest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java index f5ef22c..c2c1361 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java @@ -31,13 +31,17 @@ import okhttp3.Call; import okhttp3.Response; +import android.util.Log; + import de.chaosdorf.meteroid.MeteroidNetworkActivity; public class LongRunningIORequest { + private final static String TAG = "LongRunningIO"; public LongRunningIORequest(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final retrofit2.Call call) { + Log.d(TAG, "Initiating call: " + call.request()); new OkHttpClient().newCall(call.request()).enqueue(newCallback(callback, id)); } @@ -48,6 +52,7 @@ protected Callback newCallback(final MeteroidNetworkActivity callback, final Lon @Override public void onFailure(final Call call, final IOException e) { + Log.d(TAG, "Handling failure: " + call.request()); callback.runOnUiThread(new Runnable() { @Override @@ -61,6 +66,7 @@ public void run() @Override public void onResponse(final Call call, final Response resp) { + Log.d(TAG, "Handling response: " + call.request()); if(resp.isSuccessful()) { try From 5e15c790152d54847407d448eba6c13f8f5ea402 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 11:12:16 +0100 Subject: [PATCH 013/197] Make more use of Retrofit and GSON. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 8 ++--- .../de/chaosdorf/meteroid/PickUsername.java | 4 +-- .../de/chaosdorf/meteroid/UserSettings.java | 4 +-- .../longrunningio/LongRunningIOCallback.java | 2 +- .../longrunningio/LongRunningIORequest.java | 31 +++++++++---------- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 1043588..6079763 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -227,7 +227,7 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa } @Override - public void processIOResult(final LongRunningIOTask task, final String json) + public void processIOResult(final LongRunningIOTask task, final Object result) { switch (task) { @@ -235,7 +235,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) case GET_USER: case UPDATE_USER: { - user = UserController.parseUserFromJSON(json); + user = (User)result; if (task == LongRunningIOTask.GET_USER) { final TextView label = (TextView) findViewById(R.id.username); @@ -253,10 +253,10 @@ public void processIOResult(final LongRunningIOTask task, final String json) // Parse drinks case GET_DRINKS: { - final List buyableItemList = DrinkController.parseAllDrinksFromJSON(json); + final List buyableItemList = (List)result; MoneyController.addMoney(buyableItemList); Collections.sort(buyableItemList, new BuyableComparator()); - + final BuyableItemAdapter buyableItemAdapter = new BuyableItemAdapter(buyableItemList); if (useGridView) { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 2e599cf..c640d03 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -174,12 +174,12 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa } @Override - public void processIOResult(final LongRunningIOTask task, final String json) + public void processIOResult(final LongRunningIOTask task, final Object result) { final PickUsername pickusername = this; if (task == LongRunningIOTask.GET_USERS) { - final List itemList = UserController.parseAllUsersFromJSON(json); + final List itemList = (List)result; if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0)); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 7dc19fa..5179de4 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -231,7 +231,7 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa } @Override - public void processIOResult(final LongRunningIOTask task, final String json) + public void processIOResult(final LongRunningIOTask task, final Object result) { final UserSettings usersettings = this; switch(task) @@ -243,7 +243,7 @@ public void processIOResult(final LongRunningIOTask task, final String json) Utility.startActivity(usersettings, BuyDrink.class); break; case GET_USER: - User user = UserController.parseUserFromJSON(json); + User user = (User)result; usernameText.setText(user.getName()); emailText.setText(user.getEmail()); balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java index ae302d1..6a51b21 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java @@ -28,5 +28,5 @@ public interface LongRunningIOCallback { public void displayErrorMessage(final LongRunningIOTask task, final String message); - public void processIOResult(final LongRunningIOTask task, final String json); + public void processIOResult(final LongRunningIOTask task, final Object response); } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java index c2c1361..a9c8689 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java @@ -26,31 +26,30 @@ import java.io.IOException; -import okhttp3.OkHttpClient; -import okhttp3.Callback; -import okhttp3.Call; -import okhttp3.Response; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; import android.util.Log; import de.chaosdorf.meteroid.MeteroidNetworkActivity; -public class LongRunningIORequest +public class LongRunningIORequest { private final static String TAG = "LongRunningIO"; - public LongRunningIORequest(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final retrofit2.Call call) + public LongRunningIORequest(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) { Log.d(TAG, "Initiating call: " + call.request()); - new OkHttpClient().newCall(call.request()).enqueue(newCallback(callback, id)); + call.enqueue(newCallback(callback, id)); } - - protected Callback newCallback(final MeteroidNetworkActivity callback, final LongRunningIOTask id) + + protected Callback newCallback(final MeteroidNetworkActivity callback, final LongRunningIOTask id) { - return new Callback() + return new Callback() { @Override - public void onFailure(final Call call, final IOException e) + public void onFailure(final Call call, final Throwable t) { Log.d(TAG, "Handling failure: " + call.request()); callback.runOnUiThread(new Runnable() @@ -58,20 +57,20 @@ public void onFailure(final Call call, final IOException e) @Override public void run() { - callback.displayErrorMessage(id, e.getLocalizedMessage()); + callback.displayErrorMessage(id, t.getLocalizedMessage()); } }); } @Override - public void onResponse(final Call call, final Response resp) + public void onResponse(final Call call, final Response resp) { Log.d(TAG, "Handling response: " + call.request()); if(resp.isSuccessful()) { try { - final String response = resp.body().string(); + final T response = resp.body(); callback.runOnUiThread(new Runnable() { @Override @@ -81,14 +80,14 @@ public void run() } }); } - catch(final IOException e) + catch(final Throwable t) { callback.runOnUiThread(new Runnable() { @Override public void run() { - callback.displayErrorMessage(id, e.getLocalizedMessage()); + callback.displayErrorMessage(id, t.getLocalizedMessage()); } }); } From 26ef48caa556227503ea25ca366ba73619d1a37e Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 11:19:58 +0100 Subject: [PATCH 014/197] Delete unused controllers. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 2 - .../de/chaosdorf/meteroid/PickUsername.java | 1 - .../de/chaosdorf/meteroid/UserSettings.java | 1 - .../meteroid/controller/DrinkController.java | 79 ----------------- .../meteroid/controller/UserController.java | 88 ------------------- 5 files changed, 171 deletions(-) delete mode 100644 meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java delete mode 100644 meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 6079763..c707dcd 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -52,9 +52,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import de.chaosdorf.meteroid.controller.DrinkController; import de.chaosdorf.meteroid.controller.MoneyController; -import de.chaosdorf.meteroid.controller.UserController; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.BuyableItem; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index c640d03..3d3e227 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -49,7 +49,6 @@ import java.util.Date; import java.util.List; -import de.chaosdorf.meteroid.controller.UserController; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 5179de4..039242f 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -41,7 +41,6 @@ import java.text.ParseException; import java.util.Date; -import de.chaosdorf.meteroid.controller.UserController; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java deleted file mode 100644 index 9f6b57f..0000000 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/DrinkController.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (c) 2013-2016 Chaosdorf e.V. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -package de.chaosdorf.meteroid.controller; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -import de.chaosdorf.meteroid.model.BuyableItem; -import de.chaosdorf.meteroid.model.Drink; - -public class DrinkController -{ - public static List parseAllDrinksFromJSON(final String json) - { - final List list = new ArrayList(); - try - { - final JSONArray jsonArray = new JSONArray(json); - for (int i = 0; i < jsonArray.length(); i++) - { - final Drink drink = parseDrinkFromJSONObject(jsonArray.getJSONObject(i)); - if (drink != null) - { - list.add(drink); - } - } - return list; - } - catch (JSONException ignored) - { - return null; - } - } - - private static Drink parseDrinkFromJSONObject(final JSONObject jsonObject) - { - try - { - return new Drink( - jsonObject.getInt("id"), - jsonObject.getString("name"), - jsonObject.getString("logo_url"), - jsonObject.getDouble("bottle_size"), - jsonObject.getString("caffeine"), - jsonObject.getDouble("donation_recommendation") - ); - } - catch (JSONException ignored) - { - return null; - } - } -} diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java deleted file mode 100644 index aa2462b..0000000 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/UserController.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (c) 2013-2016 Chaosdorf e.V. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -package de.chaosdorf.meteroid.controller; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -import de.chaosdorf.meteroid.model.User; - -public class UserController -{ - public static List parseAllUsersFromJSON(final String json) - { - final List list = new ArrayList(); - try - { - final JSONArray jsonArray = new JSONArray(json); - for (int i = 0; i < jsonArray.length(); i++) - { - final User user = parseUserFromJSONObject(jsonArray.getJSONObject(i)); - if (user != null) - { - list.add(user); - } - } - return list; - } - catch (JSONException ignored) - { - return null; - } - } - - public static User parseUserFromJSON(final String json) - { - try - { - return parseUserFromJSONObject(new JSONObject(json)); - } - catch (JSONException e) - { - return null; - } - } - - private static User parseUserFromJSONObject(final JSONObject jsonObject) - { - try - { - return new User( - jsonObject.getInt("id"), - jsonObject.getString("name"), - jsonObject.getString("email"), - jsonObject.getDouble("balance") - ); - } - catch (JSONException ignored) - { - return null; - } - } -} From 6da2547699aa6c37b332cf871c282ea0e59c7f19 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 11:25:47 +0100 Subject: [PATCH 015/197] Add "-Xlint:unchecked" to compiler args. --- meteroid/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index b7a8f3b..8352b6c 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -46,6 +46,7 @@ dependencies { gradle.projectsEvaluated { tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:deprecation" + options.compilerArgs << "-Xlint:unchecked" } } From ee587b9005d932c0c41221383b63214db2026e95 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 11:31:04 +0100 Subject: [PATCH 016/197] Specify more types for LongRunningIORequest. --- .../main/java/de/chaosdorf/meteroid/BuyDrink.java | 12 ++++++------ .../java/de/chaosdorf/meteroid/PickUsername.java | 2 +- .../java/de/chaosdorf/meteroid/UserSettings.java | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index c707dcd..4b0ac18 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -128,8 +128,8 @@ public void onClick(View view) editButton.setVisibility(View.GONE); } - new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); - new LongRunningIORequest(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); + new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); + new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } @Override @@ -298,7 +298,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) break; } } - new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); break; } @@ -322,7 +322,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); } } - new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); break; } } @@ -345,11 +345,11 @@ public void onItemClick(final AdapterView adapterView, final View view, final setProgressBarIndeterminateVisibility(true); if(buyableItem.isDrink()) { - new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy(userID, ((Drink)buyableItem).getId())); + new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy(userID, ((Drink)buyableItem).getId())); } else { - new LongRunningIORequest(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getDonationRecommendation())); + new LongRunningIORequest(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getDonationRecommendation())); } } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 3d3e227..4c106c6 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -102,7 +102,7 @@ public void onClick(View view) backButton.setVisibility(View.GONE); } - new LongRunningIORequest(this, LongRunningIOTask.GET_USERS, api.listUsers()); + new LongRunningIORequest>(this, LongRunningIOTask.GET_USERS, api.listUsers()); } @Override diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 039242f..b738492 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -97,7 +97,7 @@ public void onClick(View view) if(userID != 0) //existing user { makeReadOnly(); - new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); } } @@ -206,7 +206,7 @@ private void saveUser() if(userID == 0) //new user { - new LongRunningIORequest( + new LongRunningIORequest( this, LongRunningIOTask.ADD_USER, api.createUser(user.getName(), user.getEmail(), user.getBalance(), null) @@ -214,7 +214,7 @@ private void saveUser() } else { - new LongRunningIORequest( + new LongRunningIORequest( this, LongRunningIOTask.EDIT_USER, api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), null) From 6aec78f71a1ae1b056bf805afe4822607bcf9312 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 11:45:02 +0100 Subject: [PATCH 017/197] Specify types for LongRunningIOCallback. --- .../meteroid/longrunningio/LongRunningIOCallback.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java index 6a51b21..ed7b31d 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOCallback.java @@ -24,9 +24,9 @@ package de.chaosdorf.meteroid.longrunningio; -public interface LongRunningIOCallback +public interface LongRunningIOCallback { public void displayErrorMessage(final LongRunningIOTask task, final String message); - public void processIOResult(final LongRunningIOTask task, final Object response); + public void processIOResult(final LongRunningIOTask task, final T response); } From 5a869b2985a8ddd86f557fd397dded076aa1287b Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 12:01:27 +0100 Subject: [PATCH 018/197] LongRunningIORequest: Remove runOnUiThread. This isn't needed anymore, because Retrofit executes the callbacks automagically on the thread that created the request. --- .../longrunningio/LongRunningIORequest.java | 36 +++---------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java index a9c8689..a68fce9 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java @@ -52,14 +52,7 @@ protected Callback newCallback(final MeteroidNetworkActivity callback, final public void onFailure(final Call call, final Throwable t) { Log.d(TAG, "Handling failure: " + call.request()); - callback.runOnUiThread(new Runnable() - { - @Override - public void run() - { - callback.displayErrorMessage(id, t.getLocalizedMessage()); - } - }); + callback.displayErrorMessage(id, t.getLocalizedMessage()); } @Override @@ -71,37 +64,16 @@ public void onResponse(final Call call, final Response resp) try { final T response = resp.body(); - callback.runOnUiThread(new Runnable() - { - @Override - public void run() - { - callback.processIOResult(id, response); - } - }); + callback.processIOResult(id, response); } catch(final Throwable t) { - callback.runOnUiThread(new Runnable() - { - @Override - public void run() - { - callback.displayErrorMessage(id, t.getLocalizedMessage()); - } - }); + callback.displayErrorMessage(id, t.getLocalizedMessage()); } } else { - callback.runOnUiThread(new Runnable() - { - @Override - public void run() - { - callback.displayErrorMessage(id, resp.message()); - } - }); + callback.displayErrorMessage(id, resp.message()); } } }; From 2f642cb94f86b8806876a6d7c84d5f07fd72d9a5 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 12:09:27 +0100 Subject: [PATCH 019/197] Make LongRunningIOCallback the interface to implement. (instead of inheriting MeteroidNetworkActivity) --- meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 3 ++- .../java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java | 3 +-- .../src/main/java/de/chaosdorf/meteroid/PickUsername.java | 3 ++- .../src/main/java/de/chaosdorf/meteroid/UserSettings.java | 3 ++- .../meteroid/longrunningio/LongRunningIORequest.java | 6 ++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 4b0ac18..2d603a4 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -53,6 +53,7 @@ import java.util.concurrent.atomic.AtomicReference; import de.chaosdorf.meteroid.controller.MoneyController; +import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.BuyableItem; @@ -62,7 +63,7 @@ import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; -public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnItemClickListener +public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnItemClickListener, LongRunningIOCallback { private final AtomicBoolean isBuying = new AtomicBoolean(true); private final AtomicReference buyingItem = new AtomicReference(null); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java index 8fbc443..04b8872 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java @@ -34,12 +34,11 @@ import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; -import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.util.API; import de.chaosdorf.meteroid.util.Utility; -public abstract class MeteroidNetworkActivity extends Activity implements LongRunningIOCallback +public abstract class MeteroidNetworkActivity extends Activity { protected DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00 '\u20AC'"); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 4c106c6..baec363 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -49,6 +49,7 @@ import java.util.Date; import java.util.List; +import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; @@ -56,7 +57,7 @@ import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; -public class PickUsername extends MeteroidNetworkActivity implements AdapterView.OnItemClickListener +public class PickUsername extends MeteroidNetworkActivity implements AdapterView.OnItemClickListener, LongRunningIOCallback { private static final int NEW_USER_ID = -1; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index b738492..53512f2 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -41,13 +41,14 @@ import java.text.ParseException; import java.util.Date; +import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; import de.chaosdorf.meteroid.model.User; import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; -public class UserSettings extends MeteroidNetworkActivity +public class UserSettings extends MeteroidNetworkActivity implements LongRunningIOCallback { private TextView usernameText; private TextView emailText; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java index a68fce9..fe96d46 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java @@ -32,19 +32,17 @@ import android.util.Log; -import de.chaosdorf.meteroid.MeteroidNetworkActivity; - public class LongRunningIORequest { private final static String TAG = "LongRunningIO"; - public LongRunningIORequest(final MeteroidNetworkActivity callback, final LongRunningIOTask id, final Call call) + public LongRunningIORequest(final LongRunningIOCallback callback, final LongRunningIOTask id, final Call call) { Log.d(TAG, "Initiating call: " + call.request()); call.enqueue(newCallback(callback, id)); } - protected Callback newCallback(final MeteroidNetworkActivity callback, final LongRunningIOTask id) + protected Callback newCallback(final LongRunningIOCallback callback, final LongRunningIOTask id) { return new Callback() { From 21486fcab1986e8cfd5df031284d9003979bd5c1 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 12:30:58 +0100 Subject: [PATCH 020/197] Specify more types in LongRunningIORequest. --- .../meteroid/longrunningio/LongRunningIORequest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java index fe96d46..f5cb531 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIORequest.java @@ -36,13 +36,13 @@ public class LongRunningIORequest { private final static String TAG = "LongRunningIO"; - public LongRunningIORequest(final LongRunningIOCallback callback, final LongRunningIOTask id, final Call call) + public LongRunningIORequest(final LongRunningIOCallback callback, final LongRunningIOTask id, final Call call) { Log.d(TAG, "Initiating call: " + call.request()); call.enqueue(newCallback(callback, id)); } - protected Callback newCallback(final LongRunningIOCallback callback, final LongRunningIOTask id) + protected Callback newCallback(final LongRunningIOCallback callback, final LongRunningIOTask id) { return new Callback() { @@ -61,8 +61,7 @@ public void onResponse(final Call call, final Response resp) { try { - final T response = resp.body(); - callback.processIOResult(id, response); + callback.processIOResult(id, resp.body()); } catch(final Throwable t) { From 6f7d8b26d4668c9eb36e33a8d8f6ee52a7e1f1b1 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 12:35:43 +0100 Subject: [PATCH 021/197] PickUsername: Specify types for LongRunningIOCallback more explicitly. --- .../src/main/java/de/chaosdorf/meteroid/PickUsername.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index baec363..f45d1c5 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -57,7 +57,7 @@ import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; -public class PickUsername extends MeteroidNetworkActivity implements AdapterView.OnItemClickListener, LongRunningIOCallback +public class PickUsername extends MeteroidNetworkActivity implements AdapterView.OnItemClickListener, LongRunningIOCallback> { private static final int NEW_USER_ID = -1; @@ -174,12 +174,12 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa } @Override - public void processIOResult(final LongRunningIOTask task, final Object result) + public void processIOResult(final LongRunningIOTask task, final List result) { final PickUsername pickusername = this; if (task == LongRunningIOTask.GET_USERS) { - final List itemList = (List)result; + final List itemList = result; if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0)); From 752c6f2de68a06ecc6fafa7a793c3d2930096d0d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 12:40:28 +0100 Subject: [PATCH 022/197] Some ` = this` are no longer needed. --- .../src/main/java/de/chaosdorf/meteroid/PickUsername.java | 3 +-- .../src/main/java/de/chaosdorf/meteroid/UserSettings.java | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index f45d1c5..726b573 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -176,7 +176,6 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa @Override public void processIOResult(final LongRunningIOTask task, final List result) { - final PickUsername pickusername = this; if (task == LongRunningIOTask.GET_USERS) { final List itemList = result; @@ -187,7 +186,7 @@ public void processIOResult(final LongRunningIOTask task, final List resul final UserAdapter userAdapter = new UserAdapter(itemList); gridView.setAdapter(userAdapter); - gridView.setOnItemClickListener(pickusername); + gridView.setOnItemClickListener(this); progressBar.setVisibility(View.GONE); gridView.setVisibility(View.VISIBLE); } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 53512f2..a7519b7 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -233,14 +233,13 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa @Override public void processIOResult(final LongRunningIOTask task, final Object result) { - final UserSettings usersettings = this; switch(task) { case ADD_USER: - Utility.startActivity(usersettings, PickUsername.class); + Utility.startActivity(this, PickUsername.class); break; case EDIT_USER: - Utility.startActivity(usersettings, BuyDrink.class); + Utility.startActivity(this, BuyDrink.class); break; case GET_USER: User user = (User)result; From ca319f9fc113a8faa8161bf8995722885eb971b5 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 13:33:53 +0100 Subject: [PATCH 023/197] UserSettings: Split processIOResult. --- .../de/chaosdorf/meteroid/UserSettings.java | 73 ++++++++++++------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index a7519b7..a2843e8 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -48,7 +48,7 @@ import de.chaosdorf.meteroid.util.Utility; import de.chaosdorf.meteroid.MeteroidNetworkActivity; -public class UserSettings extends MeteroidNetworkActivity implements LongRunningIOCallback +public class UserSettings extends MeteroidNetworkActivity { private TextView usernameText; private TextView emailText; @@ -98,7 +98,23 @@ public void onClick(View view) if(userID != 0) //existing user { makeReadOnly(); - new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); + final UserSettings userSettings = this; + new LongRunningIORequest(new LongRunningIOCallback() { + @Override + public void displayErrorMessage(LongRunningIOTask task, String message) + { + userSettings.displayErrorMessage(task, message); + } + + @Override + public void processIOResult(LongRunningIOTask task, User user) + { + usernameText.setText(user.getName()); + emailText.setText(user.getEmail()); + balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); + makeWritable(); + } + }, LongRunningIOTask.GET_USER, api.getUser(userID)); } } @@ -205,49 +221,50 @@ private void saveUser() balanceValue ); + final UserSettings userSettings = this; if(userID == 0) //new user { - new LongRunningIORequest( - this, + new LongRunningIORequest(new LongRunningIOCallback() { + @Override + public void displayErrorMessage(LongRunningIOTask task, String message) + { + userSettings.displayErrorMessage(task, message); + } + + @Override + public void processIOResult(LongRunningIOTask task, User result) + { + Utility.startActivity(userSettings, PickUsername.class); + } + }, LongRunningIOTask.ADD_USER, api.createUser(user.getName(), user.getEmail(), user.getBalance(), null) ); } else { - new LongRunningIORequest( - this, + new LongRunningIORequest(new LongRunningIOCallback() { + @Override + public void displayErrorMessage(LongRunningIOTask task, String message) + { + userSettings.displayErrorMessage(task, message); + } + + @Override + public void processIOResult(LongRunningIOTask task, Void result) + { + Utility.startActivity(userSettings, BuyDrink.class); + } + }, LongRunningIOTask.EDIT_USER, api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), null) ); } } - @Override public void displayErrorMessage(final LongRunningIOTask task, final String message) { makeWritable(); Utility.displayToastMessage(this, message); } - - @Override - public void processIOResult(final LongRunningIOTask task, final Object result) - { - switch(task) - { - case ADD_USER: - Utility.startActivity(this, PickUsername.class); - break; - case EDIT_USER: - Utility.startActivity(this, BuyDrink.class); - break; - case GET_USER: - User user = (User)result; - usernameText.setText(user.getName()); - emailText.setText(user.getEmail()); - balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); - makeWritable(); - break; - } - } } From 1824d15313484a1197ea28f02e34fa398bc1b03d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 14:01:22 +0100 Subject: [PATCH 024/197] Replace getResources().getDrawable() with Context.getDrawable(). The former one was deprecated with Marshmallow. --- .../main/java/de/chaosdorf/meteroid/PickUsername.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 726b573..8946dda 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -244,7 +244,15 @@ public View getView(final int position, final View convertView, final ViewGroup if (user.getId() == NEW_USER_ID) { - icon.setImageDrawable(getResources().getDrawable(R.drawable.add_user)); + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + { + icon.setImageDrawable(getDrawable(R.drawable.add_user)); + } + else + { + // This is only called on KitKat and lower. + icon.setImageDrawable(getResources().getDrawable(R.drawable.add_user)); + } } return view; From 9c4efbb4cc37ff17e86730cf44a79d1e31095627 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 16:01:02 +0100 Subject: [PATCH 025/197] Add the possibility to delete a user. --- .../de/chaosdorf/meteroid/UserSettings.java | 61 +++++++++++++++++++ .../longrunningio/LongRunningIOTask.java | 3 +- .../res/layout/activity_user_settings.xml | 7 +++ meteroid/src/main/res/menu/settings.xml | 6 ++ meteroid/src/main/res/values-de/strings.xml | 4 ++ meteroid/src/main/res/values/strings.xml | 4 ++ 6 files changed, 84 insertions(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index a2843e8..d1a7d67 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -25,6 +25,8 @@ package de.chaosdorf.meteroid; import android.app.ActionBar; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Build; @@ -73,6 +75,16 @@ public void onClick(View view) goBack(); } }); + + final ImageButton deleteButton = (ImageButton) findViewById(R.id.button_delete); + deleteButton.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View view) + { + deleteUser(); + } + }); final ImageButton saveButton = (ImageButton) findViewById(R.id.button_save); saveButton.setOnClickListener(new View.OnClickListener() @@ -91,6 +103,7 @@ public void onClick(View view) { actionBar.setDisplayHomeAsUpEnabled(true); backButton.setVisibility(View.GONE); + deleteButton.setVisibility(View.GONE); saveButton.setVisibility(View.GONE); } } @@ -130,6 +143,9 @@ public boolean onOptionsItemSelected(final MenuItem item) case R.id.action_save: saveUser(); break; + case R.id.action_delete: + deleteUser(); + break; } return super.onOptionsItemSelected(item); } @@ -179,6 +195,51 @@ private void goBack() Utility.startActivity(this, BuyDrink.class); } } + + private void deleteUser() + { + if(userID == 0) //new user + { + new AlertDialog.Builder(this) + .setMessage(R.string.user_settings_cant_delete_non_existing_user) + .setPositiveButton(android.R.string.ok, null) // Do nothing on click. + .create().show(); + } + else + { + final UserSettings userSettings = this; + new AlertDialog.Builder(this) + .setMessage(R.string.user_settings_confirm_delete_user) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int id) + { + // really delete the user + makeReadOnly(); + new LongRunningIORequest(new LongRunningIOCallback() { + @Override + public void displayErrorMessage(LongRunningIOTask task, String message) + { + userSettings.displayErrorMessage(task, message); + } + + @Override + public void processIOResult(LongRunningIOTask task, Void result) + { + makeWritable(); + Utility.displayToastMessage(userSettings, getResources().getString(R.string.user_settings_deleted_user)); + Utility.startActivity(userSettings, PickUsername.class); + } + }, + LongRunningIOTask.DELETE_USER, + api.deleteUser(userID)); + } + }) + .setNegativeButton(android.R.string.cancel, null) // Do nothing on click. + .create().show(); + } + } private void saveUser() { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOTask.java b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOTask.java index ccdf7d8..556b1e5 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOTask.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/longrunningio/LongRunningIOTask.java @@ -33,5 +33,6 @@ public enum LongRunningIOTask ADD_MONEY, ADD_USER, UPDATE_USER, - EDIT_USER + EDIT_USER, + DELETE_USER } diff --git a/meteroid/src/main/res/layout/activity_user_settings.xml b/meteroid/src/main/res/layout/activity_user_settings.xml index c0cf314..19da13a 100644 --- a/meteroid/src/main/res/layout/activity_user_settings.xml +++ b/meteroid/src/main/res/layout/activity_user_settings.xml @@ -70,6 +70,13 @@ android:layout_gravity="right" android:src="@drawable/button_back" android:contentDescription="@string/button_back"/> + +

+ + Guthaben Bitte Benutzername eingeben Bitte Guthaben als Zahl eingeben + Kann keinen noch nicht erstellten Benutzer löschen. + Diesen Benutzer wirklich löschen? + Benutzer gelöscht. Getränk kaufen @@ -60,6 +63,7 @@ Zurück Neu laden + Löschen Speichern diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index 566dd30..0fd4742 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -48,6 +48,9 @@ Balance Please enter a username Please enter a number as a balance + Can\'t delete a not yet existing user. + Delete this user? + Deleted the user. Buy drink @@ -60,6 +63,7 @@ Back Reload + Delete Save From 5faf76db35225e37846edf9b885eb694284d9cbe Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 16:30:14 +0100 Subject: [PATCH 026/197] Reset saved userID after deletion of a user. --- meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java | 1 + 1 file changed, 1 insertion(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index d1a7d67..708f6f7 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -227,6 +227,7 @@ public void displayErrorMessage(LongRunningIOTask task, String message) @Override public void processIOResult(LongRunningIOTask task, Void result) { + Utility.resetUsername(userSettings); makeWritable(); Utility.displayToastMessage(userSettings, getResources().getString(R.string.user_settings_deleted_user)); Utility.startActivity(userSettings, PickUsername.class); From a193e00aec009fd762d58740005ead769bfba68b Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 5 Feb 2017 17:34:51 +0100 Subject: [PATCH 027/197] Remove dependency on okhttp3. --- meteroid/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 8352b6c..b86af49 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -37,7 +37,6 @@ dependencies { maven { url 'http://repo1.maven.org/maven2' } } compile 'org.jetbrains:annotations:13.0' - compile 'com.squareup.okhttp3:okhttp:3.3.1' compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' } From 9d55e2a0dd7aa4b082cda07550f2690312a6d9c9 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 6 Feb 2017 09:38:04 +0100 Subject: [PATCH 028/197] Release v2.3.0. --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 0569ca1..3ce17fc 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="24" + android:versionName="2.3.0"> Date: Wed, 1 Mar 2017 20:04:13 +0100 Subject: [PATCH 029/197] Replace donationRecommendation with price. --- .../main/java/de/chaosdorf/meteroid/BuyDrink.java | 14 +++++++------- .../de/chaosdorf/meteroid/model/BuyableItem.java | 2 +- .../java/de/chaosdorf/meteroid/model/Drink.java | 10 +++++----- .../java/de/chaosdorf/meteroid/model/Money.java | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 2d603a4..d0abda0 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -284,14 +284,14 @@ public void processIOResult(final LongRunningIOTask task, final Object result) String.format( getResources().getString(R.string.buy_drink_bought_drink), buyableItem.getName(), - DECIMAL_FORMAT.format(buyableItem.getDonationRecommendation()) + DECIMAL_FORMAT.format(buyableItem.getPrice()) ) ); // Adjust the displayed balance to give an immediate user feedback if (user != null) { final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); + balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getPrice())); } if (multiUserMode) { @@ -313,14 +313,14 @@ public void processIOResult(final LongRunningIOTask task, final Object result) Utility.displayToastMessage(this, String.format( getResources().getString(R.string.buy_drink_added_money), - DECIMAL_FORMAT.format(-buyableItem.getDonationRecommendation()) + DECIMAL_FORMAT.format(-buyableItem.getPrice()) ) ); // Adjust the displayed balance to give an immediate user feedback if (user != null) { final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getDonationRecommendation())); + balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getPrice())); } } new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); @@ -350,7 +350,7 @@ public void onItemClick(final AdapterView adapterView, final View view, final } else { - new LongRunningIORequest(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getDonationRecommendation())); + new LongRunningIORequest(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getPrice())); } } } @@ -398,7 +398,7 @@ private String createLabel(final BuyableItem buyableItem, final boolean useGridV { label.append("+"); } - label.append(DECIMAL_FORMAT.format(-buyableItem.getDonationRecommendation())); + label.append(DECIMAL_FORMAT.format(-buyableItem.getPrice())); if (buyableItem.isDrink()) { if (useGridView) @@ -416,7 +416,7 @@ private class BuyableComparator implements Comparator @Override public int compare(final BuyableItem buyableItem, final BuyableItem buyableItem2) { - return (int) Math.round(buyableItem2.getDonationRecommendation() * 100 - buyableItem.getDonationRecommendation() * 100); + return (int) Math.round(buyableItem2.getPrice() * 100 - buyableItem.getPrice() * 100); } } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java index 3562435..32a07ca 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java @@ -30,7 +30,7 @@ public interface BuyableItem public String getLogoUrl(String hostname); - public double getDonationRecommendation(); + public double getPrice(); public boolean isDrink(); } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java index fec3330..817b34b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java @@ -36,16 +36,16 @@ public class Drink implements BuyableItem private final double bottle_size; private final String caffeine; - private final double donation_recommendation; + private final double price; - public Drink(final int id, final String name, final String logo_url, final double bottle_size, final String caffeine, final double donation_recommendation) + public Drink(final int id, final String name, final String logo_url, final double bottle_size, final String caffeine, final double price) { this.id = id; this.name = name; this.logo_url = logo_url; this.bottle_size = bottle_size; this.caffeine = caffeine; - this.donation_recommendation = donation_recommendation; + this.price = price; } public int getId() @@ -80,9 +80,9 @@ public String getCaffeine() return caffeine; } - public double getDonationRecommendation() + public double getPrice() { - return donation_recommendation; + return price; } public boolean isDrink() diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java index 302aa63..e34ba22 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java @@ -29,13 +29,13 @@ public class Money implements BuyableItem private final String name; private final String logoUrl; - private final double donationRecommendation; + private final double price; - public Money(String name, String logoUrl, double donationRecommendation) + public Money(String name, String logoUrl, double price) { this.name = name; this.logoUrl = logoUrl; - this.donationRecommendation = donationRecommendation; + this.price = price; } @Override @@ -51,9 +51,9 @@ public String getLogoUrl(String hostname) } @Override - public double getDonationRecommendation() + public double getPrice() { - return donationRecommendation; + return price; } @Override From 0197d8dd46c79482921692af0cefd6705c54821d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Wed, 1 Mar 2017 20:53:27 +0100 Subject: [PATCH 030/197] Support accounts being inactive. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 2 +- .../de/chaosdorf/meteroid/PickUsername.java | 4 ++-- .../de/chaosdorf/meteroid/UserSettings.java | 17 ++++++++++++++--- .../java/de/chaosdorf/meteroid/model/User.java | 9 ++++++++- .../de/chaosdorf/meteroid/util/Utility.java | 13 ++++++++++++- .../main/res/layout/activity_user_settings.xml | 6 ++++++ meteroid/src/main/res/values-de/strings.xml | 1 + meteroid/src/main/res/values/strings.xml | 1 + 8 files changed, 45 insertions(+), 8 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index d0abda0..40f0efb 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -240,7 +240,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) final TextView label = (TextView) findViewById(R.id.username); final ImageView icon = (ImageView) findViewById(R.id.icon); label.setText(user.getName()); - Utility.loadGravatarImage(this, icon, user); + Utility.loadUserImage(this, icon, user); } final TextView balance = (TextView) findViewById(R.id.balance); balance.setText(DECIMAL_FORMAT.format(user.getBalance())); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 8946dda..7b338a6 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -181,7 +181,7 @@ public void processIOResult(final LongRunningIOTask task, final List resul final List itemList = result; if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0)); + itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0, true)); } final UserAdapter userAdapter = new UserAdapter(itemList); @@ -238,7 +238,7 @@ public View getView(final int position, final View convertView, final ViewGroup final ImageView icon = (ImageView) view.findViewById(R.id.icon); final TextView label = (TextView) view.findViewById(R.id.label); - Utility.loadGravatarImage(activity, icon, user); + Utility.loadUserImage(activity, icon, user); icon.setContentDescription(user.getName()); label.setText(user.getName()); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 708f6f7..db18563 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -35,6 +35,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.Window; +import android.widget.CheckBox; import android.widget.ImageButton; import android.widget.TextView; @@ -55,6 +56,7 @@ public class UserSettings extends MeteroidNetworkActivity private TextView usernameText; private TextView emailText; private TextView balanceText; + private CheckBox activeCheck; @Override protected void onCreate(final Bundle savedInstanceState) @@ -66,6 +68,7 @@ protected void onCreate(final Bundle savedInstanceState) usernameText = (TextView) findViewById(R.id.username); emailText = (TextView) findViewById(R.id.email); balanceText = (TextView) findViewById(R.id.balance); + activeCheck = (CheckBox) findViewById(R.id.active); final ImageButton backButton = (ImageButton) findViewById(R.id.button_back); backButton.setOnClickListener(new View.OnClickListener() @@ -125,10 +128,15 @@ public void processIOResult(LongRunningIOTask task, User user) usernameText.setText(user.getName()); emailText.setText(user.getEmail()); balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); + activeCheck.setChecked(user.getActive()); makeWritable(); } }, LongRunningIOTask.GET_USER, api.getUser(userID)); } + else + { + activeCheck.setChecked(true); + } } @@ -276,11 +284,14 @@ private void saveUser() return; } } + + boolean activeValue = activeCheck.isChecked(); final User user = new User(userID, username.toString(), emailValue, - balanceValue + balanceValue, + activeValue ); final UserSettings userSettings = this; @@ -300,7 +311,7 @@ public void processIOResult(LongRunningIOTask task, User result) } }, LongRunningIOTask.ADD_USER, - api.createUser(user.getName(), user.getEmail(), user.getBalance(), null) + api.createUser(user.getName(), user.getEmail(), user.getBalance(), activeValue) ); } else @@ -319,7 +330,7 @@ public void processIOResult(LongRunningIOTask task, Void result) } }, LongRunningIOTask.EDIT_USER, - api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), null) + api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), activeValue) ); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java index 35d8af1..5915e0b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java @@ -30,13 +30,15 @@ public class User private final String name; private final String email; private final double balance; + private final boolean active; - public User(final int id, final String name, final String email, final double balance) + public User(final int id, final String name, final String email, final double balance, final boolean active) { this.id = id; this.name = name; this.email = email; this.balance = balance; + this.active = active; } public int getId() @@ -58,4 +60,9 @@ public double getBalance() { return balance; } + + public boolean getActive() + { + return active; + } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index a79052e..38a0116 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -27,6 +27,8 @@ import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; +import android.graphics.Color; +import android.graphics.PorterDuff; import android.preference.PreferenceManager; import android.widget.ImageView; import android.widget.Toast; @@ -80,8 +82,17 @@ private static boolean toogleBooleanSharedPreference(final Activity activity, fi displayToastMessage(activity, activity.getResources().getString(newState ? enabledMessageID : disabledMessageID)); return newState; } + + public static void loadUserImage(final Activity activity, final ImageView icon, final User user) + { + loadGravatarImage(activity, icon, user); + if(!user.getActive()) + { + icon.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY); + } + } - public static void loadGravatarImage(final Activity activity, final ImageView icon, final User user) + private static void loadGravatarImage(final Activity activity, final ImageView icon, final User user) { String email = null; if (user != null) diff --git a/meteroid/src/main/res/layout/activity_user_settings.xml b/meteroid/src/main/res/layout/activity_user_settings.xml index 19da13a..5f5a00f 100644 --- a/meteroid/src/main/res/layout/activity_user_settings.xml +++ b/meteroid/src/main/res/layout/activity_user_settings.xml @@ -55,6 +55,12 @@ android:layout_height="wrap_content" android:layout_width="fill_parent" android:inputType="numberDecimal"/> + + Benutzername Email Guthaben + Aktiv? Bitte Benutzername eingeben Bitte Guthaben als Zahl eingeben Kann keinen noch nicht erstellten Benutzer löschen. diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index 0fd4742..2a1a0a8 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -46,6 +46,7 @@ Username Email Balance + Active? Please enter a username Please enter a number as a balance Can\'t delete a not yet existing user. From ccda1b39df3f1b90597478db5c46e7d1ac5541c0 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 2 Mar 2017 12:22:39 +0100 Subject: [PATCH 031/197] Make User.active default to true. This is useful for old (not yet updated) instances of Mete. --- meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java index 5915e0b..8d4a0db 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java @@ -30,7 +30,7 @@ public class User private final String name; private final String email; private final double balance; - private final boolean active; + private boolean active = true; public User(final int id, final String name, final String email, final double balance, final boolean active) { From ab3cd0b6b88b85652045745846775e778d1dfb0d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 2 Mar 2017 14:07:55 +0100 Subject: [PATCH 032/197] Revert "Make User.active default to true." MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit ccda1b39df3f1b90597478db5c46e7d1ac5541c0. Well, this didn't work. ¯\_(ツ)_/¯ So, now there's an imcompatibility if you're using a current version of Meteroid with an instance of Mete before fe561e1 (i.e. not updated for about a year). To be clear: This will not mess up any data. But all accounts will be displayed as inactive and editing or creating new or existing users won't be possible until the Mete instance is upgraded. --- meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java index 8d4a0db..5915e0b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java @@ -30,7 +30,7 @@ public class User private final String name; private final String email; private final double balance; - private boolean active = true; + private final boolean active; public User(final int id, final String name, final String email, final double balance, final boolean active) { From dc179342d4300f75e1dff4f37d8ee8fc24a63aa4 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 2 Mar 2017 15:16:53 +0100 Subject: [PATCH 033/197] Supports drinks being inactive. --- .../src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 4 ++++ .../java/de/chaosdorf/meteroid/model/BuyableItem.java | 2 ++ .../src/main/java/de/chaosdorf/meteroid/model/Drink.java | 9 ++++++++- .../src/main/java/de/chaosdorf/meteroid/model/Money.java | 6 ++++++ .../main/java/de/chaosdorf/meteroid/util/Utility.java | 9 +++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 40f0efb..1943f78 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -300,6 +300,10 @@ public void processIOResult(final LongRunningIOTask task, final Object result) } } new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + if(!buyableItem.getActive()) + { + new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); + } break; } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java index 32a07ca..1395069 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/BuyableItem.java @@ -33,4 +33,6 @@ public interface BuyableItem public double getPrice(); public boolean isDrink(); + + public boolean getActive(); } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java index 817b34b..d405754 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java @@ -37,8 +37,9 @@ public class Drink implements BuyableItem private final double bottle_size; private final String caffeine; private final double price; + private final boolean active; - public Drink(final int id, final String name, final String logo_url, final double bottle_size, final String caffeine, final double price) + public Drink(final int id, final String name, final String logo_url, final double bottle_size, final String caffeine, final double price, final boolean active) { this.id = id; this.name = name; @@ -46,6 +47,7 @@ public Drink(final int id, final String name, final String logo_url, final doubl this.bottle_size = bottle_size; this.caffeine = caffeine; this.price = price; + this.active = active; } public int getId() @@ -89,6 +91,11 @@ public boolean isDrink() { return true; } + + public boolean getActive() + { + return active; + } private String createLogoURL(final String logoUrl, final URL baseURL) throws MalformedURLException { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java index e34ba22..298f647 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Money.java @@ -61,4 +61,10 @@ public boolean isDrink() { return false; } + + @Override + public boolean getActive() + { + return true; + } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index 38a0116..06502ac 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -119,6 +119,15 @@ private static void loadGravatarImage(final Activity activity, final ImageView i } public static void loadBuyableItemImage(final Activity activity, final ImageView icon, final BuyableItem buyableItem, final String hostname) + { + loadBuyableItemImage_(activity, icon, buyableItem, hostname); + if(!buyableItem.getActive()) + { + icon.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY); + } + } + + private static void loadBuyableItemImage_(final Activity activity, final ImageView icon, final BuyableItem buyableItem, final String hostname) { icon.setContentDescription(buyableItem.getName()); if (buyableItem.isDrink()) From a468f82cff880a73b38fa8def1b3a650d8852519 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 2 Mar 2017 17:40:08 +0100 Subject: [PATCH 034/197] Release v2.3.1 --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 3ce17fc..52663f1 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="25" + android:versionName="2.3.1"> Date: Sat, 25 Mar 2017 20:46:25 +0100 Subject: [PATCH 035/197] Support buying drinks by barcode (closes #13). --- meteroid/build.gradle | 1 + meteroid/src/main/button_barcode.eps | 41 ++++++++++++++++++ meteroid/src/main/button_barcode.png | Bin 0 -> 246 bytes meteroid/src/main/button_barcode.xcf | Bin 0 -> 37599 bytes .../java/de/chaosdorf/meteroid/BuyDrink.java | 33 ++++++++++++++ .../de/chaosdorf/meteroid/model/Drink.java | 9 +++- .../java/de/chaosdorf/meteroid/util/API.java | 7 +++ .../main/res/drawable-hdpi/button_barcode.png | Bin 0 -> 163 bytes .../main/res/drawable-mdpi/button_barcode.png | Bin 0 -> 161 bytes .../res/drawable-xhdpi/button_barcode.png | Bin 0 -> 167 bytes .../main/res/layout/activity_buy_drink.xml | 8 ++++ meteroid/src/main/res/menu/buydrink.xml | 5 +++ meteroid/src/main/res/values-de/strings.xml | 1 + meteroid/src/main/res/values/strings.xml | 1 + 14 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 meteroid/src/main/button_barcode.eps create mode 100644 meteroid/src/main/button_barcode.png create mode 100644 meteroid/src/main/button_barcode.xcf create mode 100644 meteroid/src/main/res/drawable-hdpi/button_barcode.png create mode 100644 meteroid/src/main/res/drawable-mdpi/button_barcode.png create mode 100644 meteroid/src/main/res/drawable-xhdpi/button_barcode.png diff --git a/meteroid/build.gradle b/meteroid/build.gradle index b86af49..d61894b 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -39,6 +39,7 @@ dependencies { compile 'org.jetbrains:annotations:13.0' compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' + compile 'com.google.zxing:android-integration:3.3.0' } //see https://stackoverflow.com/a/22183825/2192464 diff --git a/meteroid/src/main/button_barcode.eps b/meteroid/src/main/button_barcode.eps new file mode 100644 index 0000000..eb6a67a --- /dev/null +++ b/meteroid/src/main/button_barcode.eps @@ -0,0 +1,41 @@ +%!PS-Adobe-2.0 +%%Creator: "barcode", libbarcode sample frontend +%%DocumentPaperSizes: a4 +%%EndComments +%%EndProlog + +%%Page: 1 1 + +% Printing barcode for "MeTe", scaled 1.00, encoded using "code 128-B" +% The space/bar succession is represented by the following widths (space first): +% 02112141131231122142133111122143111412331112 +[ +% height xpos ypos width height xpos ypos width + [75.00 11.00 15.00 1.85] [75.00 13.50 15.00 0.85] + [75.00 16.50 15.00 0.85] [70.00 21.50 20.00 0.85] + [70.00 24.50 20.00 2.85] [70.00 28.00 20.00 1.85] + [70.00 32.50 20.00 0.85] [70.00 35.00 20.00 1.85] + [70.00 38.50 20.00 0.85] [70.00 44.00 20.00 1.85] + [70.00 47.50 20.00 2.85] [70.00 52.50 20.00 0.85] + [70.00 54.50 20.00 0.85] [70.00 57.00 20.00 1.85] + [70.00 60.50 20.00 0.85] [70.00 66.50 20.00 2.85] + [70.00 69.50 20.00 0.85] [70.00 73.00 20.00 3.85] + [75.00 77.00 15.00 1.85] [75.00 82.50 15.00 2.85] + [75.00 85.50 15.00 0.85] [75.00 88.00 15.00 1.85] + +] { {} forall setlinewidth moveto 0 exch rlineto stroke} bind forall +[ +% char xpos ypos fontsize + [(M) 21.00 10.00 12.00] + [(e) 32.00 10.00 0.00] + [(T) 43.00 10.00 0.00] + [(e) 54.00 10.00 0.00] +] { {} forall dup 0.00 ne { + /Helvetica findfont exch scalefont setfont + } {pop} ifelse + moveto show} bind forall +% End barcode for "MeTe" + +showpage +%%Trailer + diff --git a/meteroid/src/main/button_barcode.png b/meteroid/src/main/button_barcode.png new file mode 100644 index 0000000000000000000000000000000000000000..928d35160ab83574fa953f6ed2e7f0755e6ad293 GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0y~yV2lG{MrNSM_oq)IffQSSPlzj!{{R2~(wp<|0$GeD zL4Lsu4$p3+fjCLt?k)@+tg;?J4rhT!WHAGSo-znCRxGtI0}8U2c>21sKV+8V6fxw! z^JWoHDAUu$F(l*O+fxTQn;irg4v5PC-qM(G>qB}rd#2BZiJO~66xPLha2UVu1S)=z z`T5G~O})9c@rO;Xnk&EFod15YmQl1$a<23HO**HsqEGSZK%I5hc>l0_#~jR=ej3PQ N@O1TaS?83{1ORf=Rqg-) literal 0 HcmV?d00001 diff --git a/meteroid/src/main/button_barcode.xcf b/meteroid/src/main/button_barcode.xcf new file mode 100644 index 0000000000000000000000000000000000000000..baf9e0be91505dbecf6450d092a9b9b94f8d634b GIT binary patch literal 37599 zcmeI5J#5oJ7>2*IlO`bvX;uCtDv^Pq6%^6|u~IPsVgLytgoNa#X^3c=(zHMq!T^Z> zzX6FEAtV?W7#J8pLWqHpnSp_Ufq{X60nGc^4oaaQ#T}4xucfE=`Rt4B^PTM^Pp;Kk zeYSX}JXJhZDvgPVITj+0&VW_G@qHf&rU76ydk~~|-xX0XtpN$3E3AuRU2iScA41w+ z#fC;}b+1|(trAe$^hqCA8ZfS^oO)bi|Z$(4-|mw4{)CK!S-NH ze?b2?4xR(DxaMh^LYibA>wxWmeZh|F0p7uN!Gh~S23L7U za={azizmN4=UE?Y57zVtS2B3+ar|8H4CLazpXWU5gYChZ{^0uhxsPl5an*P5z8_Zv z&a*z)9<1pPg71M+xbyeps_)=kpX+Bh&-!3{u%pEZgi39W7A2emv7te5a=S)#iomHuZvF?neH`Rbemm# zy2x~|>7v{0;?qT@drcSJW*46>GF|L&Od@OCTe{{;U30p}bdT}-Te{bFy4Tc@<7>!) z#!U@5u7(^K+;oxYBGW~ti_CG6IW9EE#kO%=aJtBJk?A7SMW%~P7nv?HU1Yk*bdl-i z(#^Hk&9!Y@aJtBJk?A7SMYh?+q>D@!+2;077nv?HU1Yk*90!-<0MkXbbX;({$aInE zB3tWX(?zC>{6BT-Ze8T=$5CCO>$HL~%eo!!r~A+3yB|-W`}h1Yey`Z&GsW-Mpr!3m zL>>SS=yVX2f=FZp>4q>i$3zs#k1sS&d&j5iUh_mnmnFg#q%VqFNYhblkY=J7i41kb ztD{)g=?5;rvFo)Ee79J~SV!j;Cf?LWLfHJqf0hGH9?u>&y-~c!RJa8X81dqWJ@Dx1L zeQV+1{vdTuTJB!if&Y}%8?@YA(#pN`|C*YMGKiz?6?)~o#XSzRXup$QIj?b#BW^wR zO1aLqpmE%K?3HpWJ+G}C?iva7v45m1tE*P>k+k$a^gHf(y=~zh7NGIr2#vQy$WH_} BtBwEw literal 0 HcmV?d00001 diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 1943f78..7b6862b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -26,6 +26,7 @@ import android.app.ActionBar; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.os.Build; import android.view.KeyEvent; @@ -51,6 +52,8 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import com.google.zxing.integration.android.IntentIntegrator; +import com.google.zxing.integration.android.IntentResult; import de.chaosdorf.meteroid.controller.MoneyController; import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; @@ -77,6 +80,7 @@ public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnI private boolean useGridView; private boolean multiUserMode; + private IntentIntegrator barcodeIntegrator; @Override protected void onCreate(final Bundle savedInstanceState) @@ -85,6 +89,8 @@ protected void onCreate(final Bundle savedInstanceState) requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.activity_buy_drink); + barcodeIntegrator = new IntentIntegrator(this); + progressBar = (ProgressBar) findViewById(R.id.progress_bar); gridView = (GridView) findViewById(R.id.grid_view); listView = (ListView) findViewById(R.id.list_view); @@ -119,6 +125,15 @@ public void onClick(View view) Utility.startActivity(activity, UserSettings.class); } }); + + final ImageButton barcodeButton = (ImageButton) findViewById(R.id.button_barcode); + barcodeButton.setOnClickListener(new View.OnClickListener() + { + public void onClick(View view) + { + barcodeIntegrator.initiateScan(); + } + }); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { @@ -127,6 +142,7 @@ public void onClick(View view) reloadButton.setVisibility(View.GONE); backButton.setVisibility(View.GONE); editButton.setVisibility(View.GONE); + barcodeButton.setVisibility(View.GONE); } new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); @@ -157,6 +173,9 @@ public boolean onOptionsItemSelected(final MenuItem item) case R.id.action_edit: Utility.startActivity(this, UserSettings.class); break; + case R.id.action_barcode: + barcodeIntegrator.initiateScan(); + break; case R.id.edit_hostname: Utility.startActivity(this, SetHostname.class); break; @@ -414,6 +433,20 @@ private String createLabel(final BuyableItem buyableItem, final boolean useGridV return label.toString(); } } + + // the barcode scan result + public void onActivityResult(int requestCode, int resultCode, Intent intent) + { + IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); + if(scanResult != null) + { + if(scanResult.getContents() != null) + { + System.err.println("Scanned barcode: " + scanResult.toString()); + new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy_barcode(userID, scanResult.getContents())); + } + } + } private class BuyableComparator implements Comparator { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java index d405754..b460540 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/Drink.java @@ -35,16 +35,18 @@ public class Drink implements BuyableItem private final String logo_url; private final double bottle_size; + private final String barcode; private final String caffeine; private final double price; private final boolean active; - public Drink(final int id, final String name, final String logo_url, final double bottle_size, final String caffeine, final double price, final boolean active) + public Drink(final int id, final String name, final String logo_url, final double bottle_size, final String barcode, final String caffeine, final double price, final boolean active) { this.id = id; this.name = name; this.logo_url = logo_url; this.bottle_size = bottle_size; + this.barcode = barcode; this.caffeine = caffeine; this.price = price; this.active = active; @@ -76,6 +78,11 @@ public double getBottleSize() { return bottle_size; } + + public String getBarcode() + { + return barcode; + } public String getCaffeine() { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java index 335a3ba..8c4ab74 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java @@ -111,6 +111,13 @@ Call buy( @Query("drink") int did ); + // buys a drink by barcode + @POST("users/{uid}/buy_barcode.json") + Call buy_barcode( + @Path("uid") int uid, + @Query("barcode") String barcode + ); + /*// retrieves various statistics @GET("users/stats.json") Call getUsersStats();*/ diff --git a/meteroid/src/main/res/drawable-hdpi/button_barcode.png b/meteroid/src/main/res/drawable-hdpi/button_barcode.png new file mode 100644 index 0000000000000000000000000000000000000000..61503f942061b6206670df680b39b8e3312d367b GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDH3?y^UWFG-iYymzYu0Z<#|Nl#G&c6#}F_r}R z1v5B2yO9RsBze2LFm$lWdH^|`1s;*b3=De8Ak0{?)V>TT$X?><>&pI+S&~ysYjeN* z8K97ur;B5V#O36K1!@o8-`ueE;emj~D>xZ^wL=;=s~lMiRKeis>gTe~DWM4fobxSG literal 0 HcmV?d00001 diff --git a/meteroid/src/main/res/drawable-mdpi/button_barcode.png b/meteroid/src/main/res/drawable-mdpi/button_barcode.png new file mode 100644 index 0000000000000000000000000000000000000000..9e96ff29fc4e5d339bfbd96aedc84280b31f4094 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;*aCb)T!Hle|NocXoPQU{Vk`;r z3ubV5b|VeMN%D4gVd!9$^#F1>3p^r=85s1GL71^(seKtxkiEpy*OmPtvm~b&OMavm v$Y>Ey7sn8e>&XcUJQmOH3NGYzlwe?ZnI_X~{P+4^pge=8tDnm{r-UW|ti~un literal 0 HcmV?d00001 diff --git a/meteroid/src/main/res/drawable-xhdpi/button_barcode.png b/meteroid/src/main/res/drawable-xhdpi/button_barcode.png new file mode 100644 index 0000000000000000000000000000000000000000..74c4e4300a0400980eb959a4186c6e7192651239 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRu?6^qxB}__|Nk$&IsYz@#aI&L z7tG-B>_!@hljQC0!qCAg>jC6&7I;J!Gcf2WgD_*oQu{KXAbW|YuPggQW=T$Q;ja__ zwE~5tJY5_^G|nd{NCYTUy}Z~w+4YRnVxCWu%v=md*e1!^emwjGsEWbU)z4*}Q$iB} DZOtv{ literal 0 HcmV?d00001 diff --git a/meteroid/src/main/res/layout/activity_buy_drink.xml b/meteroid/src/main/res/layout/activity_buy_drink.xml index 0e41a88..b2ee808 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink.xml @@ -88,6 +88,14 @@ android:layout_gravity="right" android:src="@drawable/button_back" android:contentDescription="@string/button_back"/> + + + Neu laden Löschen Speichern + Barcode scannen Hostname ändern diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index 2a1a0a8..52ca9b8 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -66,6 +66,7 @@ Reload Delete Save + Scan a barcode Edit hostname From 9fcb3ba6fbf686c63bc1c9cd6e55bea9bd9ed713 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 25 Mar 2017 20:50:53 +0100 Subject: [PATCH 036/197] "Clarify" error message in BuyDrink. --- meteroid/src/main/res/values-de/strings.xml | 2 +- meteroid/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/res/values-de/strings.xml b/meteroid/src/main/res/values-de/strings.xml index 884ddcc..f27c6a8 100644 --- a/meteroid/src/main/res/values-de/strings.xml +++ b/meteroid/src/main/res/values-de/strings.xml @@ -58,7 +58,7 @@ Bitte warten bis aktueller Vorgang abgeschlossen ist… %1$s für %2$s gekauft Erfolgreich %1$s aufgeladen - Daten konnte nicht von mete geladen werden. Bitte Netzwerkverbindung überprüfen oder Hostname/Benutzername ändern um fortzufahren. + Ups, das hat nicht geklappt. Bitte Eingaben und Netzwerkverbindung überprüfen und erneut versuchen oder Hostname/Benutzername ändern um fortzufahren. Benutzer bearbeiten diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index 52ca9b8..8c1d98c 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -58,7 +58,7 @@ Please wait for current transaction… Bought %1$s for %2$s Successfully added %1$s - Could not load data from mete. Please check network connection or reset hostname/username to proceed. + Well, this didn\'t succeed. Please check your inputs and network connection and try again or reset hostname/username to proceed. Edit user From 4bc247fd9bf26c4f2718f17c5d3ce9234b95f2c1 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 25 Mar 2017 20:58:54 +0100 Subject: [PATCH 037/197] Move raw ressources into a folder. --- meteroid/src/main/{ => res_raw}/button_barcode.eps | 0 meteroid/src/main/{ => res_raw}/button_barcode.png | Bin meteroid/src/main/{ => res_raw}/button_barcode.xcf | Bin meteroid/src/main/{ => res_raw}/ic_launcher-web.png | Bin 4 files changed, 0 insertions(+), 0 deletions(-) rename meteroid/src/main/{ => res_raw}/button_barcode.eps (100%) rename meteroid/src/main/{ => res_raw}/button_barcode.png (100%) rename meteroid/src/main/{ => res_raw}/button_barcode.xcf (100%) rename meteroid/src/main/{ => res_raw}/ic_launcher-web.png (100%) diff --git a/meteroid/src/main/button_barcode.eps b/meteroid/src/main/res_raw/button_barcode.eps similarity index 100% rename from meteroid/src/main/button_barcode.eps rename to meteroid/src/main/res_raw/button_barcode.eps diff --git a/meteroid/src/main/button_barcode.png b/meteroid/src/main/res_raw/button_barcode.png similarity index 100% rename from meteroid/src/main/button_barcode.png rename to meteroid/src/main/res_raw/button_barcode.png diff --git a/meteroid/src/main/button_barcode.xcf b/meteroid/src/main/res_raw/button_barcode.xcf similarity index 100% rename from meteroid/src/main/button_barcode.xcf rename to meteroid/src/main/res_raw/button_barcode.xcf diff --git a/meteroid/src/main/ic_launcher-web.png b/meteroid/src/main/res_raw/ic_launcher-web.png similarity index 100% rename from meteroid/src/main/ic_launcher-web.png rename to meteroid/src/main/res_raw/ic_launcher-web.png From d35cb322895846115a022d9102b5a35753ebcad0 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 25 Mar 2017 21:12:24 +0100 Subject: [PATCH 038/197] Resize the user avatar (fixes #11). --- meteroid/src/main/res/layout/activity_buy_drink.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/res/layout/activity_buy_drink.xml b/meteroid/src/main/res/layout/activity_buy_drink.xml index b2ee808..5fbab3c 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink.xml @@ -55,8 +55,8 @@ Date: Sun, 26 Mar 2017 10:09:35 +0200 Subject: [PATCH 039/197] Display negative account balances in red (closes #12). --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 7b6862b..bf72316 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -27,6 +27,7 @@ import android.app.ActionBar; import android.content.Context; import android.content.Intent; +import android.graphics.Color; import android.os.Bundle; import android.os.Build; import android.view.KeyEvent; @@ -261,8 +262,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) label.setText(user.getName()); Utility.loadUserImage(this, icon, user); } - final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance())); + updateBalance(user.getBalance()); isBuying.set(false); setProgressBarIndeterminateVisibility(false); break; @@ -309,8 +309,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) // Adjust the displayed balance to give an immediate user feedback if (user != null) { - final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getPrice())); + updateBalance(user.getBalance() - buyableItem.getPrice()); } if (multiUserMode) { @@ -342,8 +341,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) // Adjust the displayed balance to give an immediate user feedback if (user != null) { - final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(user.getBalance() - buyableItem.getPrice())); + updateBalance(user.getBalance() - buyableItem.getPrice()); } } new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); @@ -447,6 +445,13 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) } } } + + private void updateBalance(double amount) + { + final TextView balance = (TextView) findViewById(R.id.balance); + balance.setText(DECIMAL_FORMAT.format(amount)); + balance.setTextColor(amount >= 0 ? Color.LTGRAY : Color.RED); + } private class BuyableComparator implements Comparator { From b6f9baf4c9824e5c6826f0952a17670248761007 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Tue, 28 Mar 2017 14:38:00 +0200 Subject: [PATCH 040/197] Release v2.3.2 --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 52663f1..4874ca3 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="26" + android:versionName="2.3.2"> Date: Sun, 2 Apr 2017 15:27:21 +0200 Subject: [PATCH 041/197] Add a floating action button for adding a user. --- meteroid/build.gradle | 1 + .../de/chaosdorf/meteroid/PickUsername.java | 18 ++++++++ .../res/layout/activity_pick_username.xml | 11 +++++ .../src/main/res/menu-v21/pickusername.xml | 43 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 meteroid/src/main/res/menu-v21/pickusername.xml diff --git a/meteroid/build.gradle b/meteroid/build.gradle index d61894b..d3e7a26 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -40,6 +40,7 @@ dependencies { compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.google.zxing:android-integration:3.3.0' + compile 'com.melnykov:floatingactionbutton:1.3.0' } //see https://stackoverflow.com/a/22183825/2192464 diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 7b338a6..c5462d6 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -44,6 +44,8 @@ import android.widget.ProgressBar; import android.widget.TextView; +import com.melnykov.fab.FloatingActionButton; + import org.jetbrains.annotations.NotNull; import java.util.Date; @@ -102,6 +104,22 @@ public void onClick(View view) reloadButton.setVisibility(View.GONE); backButton.setVisibility(View.GONE); } + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + { + FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); + fab.hide(false); + fab.attachToListView(gridView); + fab.setOnClickListener(new View.OnClickListener() + { + public void onClick(View view) + { + Utility.startActivity(activity, UserSettings.class); + } + }); + fab.setVisibility(View.VISIBLE); + fab.show(); + } new LongRunningIORequest>(this, LongRunningIOTask.GET_USERS, api.listUsers()); } diff --git a/meteroid/src/main/res/layout/activity_pick_username.xml b/meteroid/src/main/res/layout/activity_pick_username.xml index 16315cc..940c9c1 100644 --- a/meteroid/src/main/res/layout/activity_pick_username.xml +++ b/meteroid/src/main/res/layout/activity_pick_username.xml @@ -25,6 +25,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> + + diff --git a/meteroid/src/main/res/menu-v21/pickusername.xml b/meteroid/src/main/res/menu-v21/pickusername.xml new file mode 100644 index 0000000..1f53035 --- /dev/null +++ b/meteroid/src/main/res/menu-v21/pickusername.xml @@ -0,0 +1,43 @@ + + + + + + + From bd50f1487e28c935d0245b74b5a56ff17fddb33d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 2 Apr 2017 16:29:33 +0200 Subject: [PATCH 042/197] Add a floating action button for scanning a barcode. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 22 +++++++ .../main/res/layout/activity_buy_drink.xml | 12 ++++ meteroid/src/main/res/menu-v21/buydrink.xml | 60 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 meteroid/src/main/res/menu-v21/buydrink.xml diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index bf72316..5d50b5e 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -46,6 +46,8 @@ import android.widget.ProgressBar; import android.widget.TextView; +import com.melnykov.fab.FloatingActionButton; + import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -75,6 +77,7 @@ public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnI private ProgressBar progressBar = null; private GridView gridView = null; private ListView listView = null; + private FloatingActionButton fab = null; private User user; @@ -146,6 +149,20 @@ public void onClick(View view) barcodeButton.setVisibility(View.GONE); } + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + { + fab = (FloatingActionButton) findViewById(R.id.fab); + fab.hide(false); + fab.setOnClickListener(new View.OnClickListener() + { + public void onClick(View view) + { + barcodeIntegrator.initiateScan(); + } + }); + fab.setVisibility(View.VISIBLE); + } + new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } @@ -289,6 +306,11 @@ public void processIOResult(final LongRunningIOTask task, final Object result) listView.setVisibility(View.VISIBLE); } progressBar.setVisibility(View.GONE); + if(fab != null) + { + fab.attachToListView(useGridView? gridView : listView); + fab.show(); + } break; } diff --git a/meteroid/src/main/res/layout/activity_buy_drink.xml b/meteroid/src/main/res/layout/activity_buy_drink.xml index 5fbab3c..df31118 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink.xml @@ -25,6 +25,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> + + + diff --git a/meteroid/src/main/res/menu-v21/buydrink.xml b/meteroid/src/main/res/menu-v21/buydrink.xml new file mode 100644 index 0000000..6ff1fe4 --- /dev/null +++ b/meteroid/src/main/res/menu-v21/buydrink.xml @@ -0,0 +1,60 @@ + + + + + + + + + + From 7fd481659bb890a9ebe35f851f2a0862680c0299 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Wed, 5 Apr 2017 15:06:13 +0200 Subject: [PATCH 043/197] Make BuyDrink fit on small screens on Gingerbread. --- .../main/res/layout/activity_buy_drink.xml | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/meteroid/src/main/res/layout/activity_buy_drink.xml b/meteroid/src/main/res/layout/activity_buy_drink.xml index df31118..82c8608 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink.xml @@ -47,6 +47,43 @@ android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> + + + + + + + + + + + + + - - - - - - - - Date: Wed, 5 Apr 2017 15:07:09 +0200 Subject: [PATCH 044/197] Release v2.3.3 --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 4874ca3..f37c0b3 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="27" + android:versionName="2.3.3"> Date: Thu, 13 Apr 2017 11:51:38 +0200 Subject: [PATCH 045/197] Show less menu entries on Gingerbread. --- meteroid/src/main/res/menu-v11/buydrink.xml | 65 +++++++++++++++++++ .../src/main/res/menu-v11/pickusername.xml | 48 ++++++++++++++ meteroid/src/main/res/menu-v11/settings.xml | 37 +++++++++++ meteroid/src/main/res/menu/buydrink.xml | 15 ----- meteroid/src/main/res/menu/pickusername.xml | 10 --- meteroid/src/main/res/menu/settings.xml | 11 ---- 6 files changed, 150 insertions(+), 36 deletions(-) create mode 100644 meteroid/src/main/res/menu-v11/buydrink.xml create mode 100644 meteroid/src/main/res/menu-v11/pickusername.xml create mode 100644 meteroid/src/main/res/menu-v11/settings.xml diff --git a/meteroid/src/main/res/menu-v11/buydrink.xml b/meteroid/src/main/res/menu-v11/buydrink.xml new file mode 100644 index 0000000..8d03b14 --- /dev/null +++ b/meteroid/src/main/res/menu-v11/buydrink.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/meteroid/src/main/res/menu-v11/pickusername.xml b/meteroid/src/main/res/menu-v11/pickusername.xml new file mode 100644 index 0000000..36610c1 --- /dev/null +++ b/meteroid/src/main/res/menu-v11/pickusername.xml @@ -0,0 +1,48 @@ + + + + + + + + diff --git a/meteroid/src/main/res/menu-v11/settings.xml b/meteroid/src/main/res/menu-v11/settings.xml new file mode 100644 index 0000000..639a76a --- /dev/null +++ b/meteroid/src/main/res/menu-v11/settings.xml @@ -0,0 +1,37 @@ + + + + + + + diff --git a/meteroid/src/main/res/menu/buydrink.xml b/meteroid/src/main/res/menu/buydrink.xml index 8d03b14..59b03a0 100644 --- a/meteroid/src/main/res/menu/buydrink.xml +++ b/meteroid/src/main/res/menu/buydrink.xml @@ -23,21 +23,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - - - - - - - - From 04127e8d0e6a16e70a9b124ef1da16e9994b2e18 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 13 Apr 2017 14:17:03 +0200 Subject: [PATCH 046/197] PickUsername: Don't destroy the whole activity when reloading. --- .../main/java/de/chaosdorf/meteroid/PickUsername.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index c5462d6..94d5921 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -93,7 +93,7 @@ public void onClick(View view) { public void onClick(View view) { - Utility.startActivity(activity, PickUsername.class); + reload(); } }); @@ -121,6 +121,13 @@ public void onClick(View view) fab.show(); } + reload(); + } + + public void reload() + { + gridView.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); new LongRunningIORequest>(this, LongRunningIOTask.GET_USERS, api.listUsers()); } @@ -141,7 +148,7 @@ public boolean onOptionsItemSelected(final MenuItem item) Utility.startActivity(this, SetHostname.class); break; case R.id.action_reload: - Utility.startActivity(this, PickUsername.class); + reload(); break; case R.id.action_add: Utility.startActivity(this, UserSettings.class); From 8a7a22465a53433943b7e891af97b023fffc84bb Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 13 Apr 2017 14:23:52 +0200 Subject: [PATCH 047/197] BuyDrink: Don't destroy the whole activity when reloading. --- .../main/java/de/chaosdorf/meteroid/BuyDrink.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 5d50b5e..296f4fa 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -117,7 +117,7 @@ public void onClick(View view) { public void onClick(View view) { - Utility.startActivity(activity, BuyDrink.class); + reload(); } }); @@ -163,6 +163,14 @@ public void onClick(View view) fab.setVisibility(View.VISIBLE); } + reload(); + } + + public void reload() + { + gridView.setVisibility(View.GONE); + listView.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } @@ -186,7 +194,7 @@ public boolean onOptionsItemSelected(final MenuItem item) Utility.startActivity(this, PickUsername.class); break; case R.id.action_reload: - Utility.startActivity(this, BuyDrink.class); + reload(); break; case R.id.action_edit: Utility.startActivity(this, UserSettings.class); From 17b8427016d5cd8b0dbdf1b699b427297ae49b8f Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 13 Apr 2017 17:47:14 +0200 Subject: [PATCH 048/197] PickUsername: Bring back the reload function for Gingerbread. --- meteroid/src/main/res/menu/pickusername.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meteroid/src/main/res/menu/pickusername.xml b/meteroid/src/main/res/menu/pickusername.xml index e3c4fbd..1f53035 100644 --- a/meteroid/src/main/res/menu/pickusername.xml +++ b/meteroid/src/main/res/menu/pickusername.xml @@ -23,6 +23,11 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> + Date: Tue, 25 Apr 2017 19:10:04 +0200 Subject: [PATCH 049/197] Add SwipeRefreshLayout to PickUsername. --- meteroid/build.gradle | 1 + .../de/chaosdorf/meteroid/PickUsername.java | 25 +++++++++++++++++ .../res/layout/activity_pick_username.xml | 27 ++++++++++++------- .../src/main/res/menu-v21/pickusername.xml | 2 +- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index d3e7a26..10cf65e 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -41,6 +41,7 @@ dependencies { compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.google.zxing:android-integration:3.3.0' compile 'com.melnykov:floatingactionbutton:1.3.0' + compile 'com.android.support:support-v4:22.1.1@aar' } //see https://stackoverflow.com/a/22183825/2192464 diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 94d5921..83a883a 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -44,6 +44,8 @@ import android.widget.ProgressBar; import android.widget.TextView; +import android.support.v4.widget.SwipeRefreshLayout; + import com.melnykov.fab.FloatingActionButton; import org.jetbrains.annotations.NotNull; @@ -67,6 +69,7 @@ public class PickUsername extends MeteroidNetworkActivity implements AdapterView private GridView gridView = null; private boolean multiUserMode = false; private boolean editHostnameOnBackButton = false; + private SwipeRefreshLayout swipeRefreshLayout = null; @Override protected void onCreate(final Bundle savedInstanceState) @@ -107,6 +110,16 @@ public void onClick(View view) if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefresh); + swipeRefreshLayout.setEnabled(true); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() + { + @Override + public void onRefresh() + { + reload(); + } + }); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.hide(false); fab.attachToListView(gridView); @@ -128,6 +141,10 @@ public void reload() { gridView.setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE); + if(swipeRefreshLayout != null) + { + swipeRefreshLayout.setRefreshing(true); + } new LongRunningIORequest>(this, LongRunningIOTask.GET_USERS, api.listUsers()); } @@ -196,6 +213,10 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa gridView.setVisibility(View.GONE); editHostnameOnBackButton = true; progressBar.setVisibility(View.GONE); + if(swipeRefreshLayout != null) + { + swipeRefreshLayout.setRefreshing(false); + } } @Override @@ -214,6 +235,10 @@ public void processIOResult(final LongRunningIOTask task, final List resul gridView.setOnItemClickListener(this); progressBar.setVisibility(View.GONE); gridView.setVisibility(View.VISIBLE); + if(swipeRefreshLayout != null) + { + swipeRefreshLayout.setRefreshing(false); + } } } diff --git a/meteroid/src/main/res/layout/activity_pick_username.xml b/meteroid/src/main/res/layout/activity_pick_username.xml index 940c9c1..87d03d4 100644 --- a/meteroid/src/main/res/layout/activity_pick_username.xml +++ b/meteroid/src/main/res/layout/activity_pick_username.xml @@ -81,18 +81,27 @@ android:layout_centerInParent="true" style="@android:style/Widget.ProgressBar.Large"/> - + android:gravity="center" + android:enabled="false"> + + + + + android:showAsAction="never"/> Date: Tue, 25 Apr 2017 19:26:16 +0200 Subject: [PATCH 050/197] PickUsername: Hide the error message on reload. --- meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 83a883a..ce92f1e 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -139,6 +139,8 @@ public void onClick(View view) public void reload() { + final LinearLayout linearLayout = (LinearLayout) findViewById(R.id.pick_username_error); + linearLayout.setVisibility(View.GONE); gridView.setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE); if(swipeRefreshLayout != null) From b6e9e7cfbbfc899b56bc58df9648d11ee3f85a5c Mon Sep 17 00:00:00 2001 From: bullycamper Date: Fri, 25 Aug 2017 19:33:12 +0000 Subject: [PATCH 051/197] Changed buy/kaufen into donate/spenden to meet the legal base of mete. --- meteroid/src/main/res/values-de/strings.xml | 4 ++-- meteroid/src/main/res/values/strings.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/meteroid/src/main/res/values-de/strings.xml b/meteroid/src/main/res/values-de/strings.xml index f27c6a8..3e73340 100644 --- a/meteroid/src/main/res/values-de/strings.xml +++ b/meteroid/src/main/res/values-de/strings.xml @@ -54,9 +54,9 @@ Benutzer gelöscht. - Getränk kaufen + F\303\274r Getränk spenden Bitte warten bis aktueller Vorgang abgeschlossen ist… - %1$s für %2$s gekauft + %2$s für %1$s gespendet Erfolgreich %1$s aufgeladen Ups, das hat nicht geklappt. Bitte Eingaben und Netzwerkverbindung überprüfen und erneut versuchen oder Hostname/Benutzername ändern um fortzufahren. Benutzer bearbeiten diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index 8c1d98c..e6ba311 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -54,9 +54,9 @@ Deleted the user. - Buy drink + Donate for a drink Please wait for current transaction… - Bought %1$s for %2$s + Donated %2$s for %1$s Successfully added %1$s Well, this didn\'t succeed. Please check your inputs and network connection and try again or reset hostname/username to proceed. Edit user From a14719aeac6e82a60330bbac1a77b132d6232093 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 17 Sep 2017 15:25:32 +0200 Subject: [PATCH 052/197] =?UTF-8?q?Fix=20=C3=BC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meteroid/src/main/res/values-de/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/src/main/res/values-de/strings.xml b/meteroid/src/main/res/values-de/strings.xml index 3e73340..e47f671 100644 --- a/meteroid/src/main/res/values-de/strings.xml +++ b/meteroid/src/main/res/values-de/strings.xml @@ -54,7 +54,7 @@ Benutzer gelöscht. - F\303\274r Getränk spenden + Für Getränk spenden Bitte warten bis aktueller Vorgang abgeschlossen ist… %2$s für %1$s gespendet Erfolgreich %1$s aufgeladen From df1801d0a5d8afe6c89f46317095de9c25e9405f Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 6 Oct 2017 20:09:53 +0200 Subject: [PATCH 053/197] Update Android SDK. --- .travis.yml | 4 ++-- meteroid/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c1692c3..e773e7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,5 @@ android: components: - platform-tools - tools - - build-tools-23.0.3 - - android-23 + - build-tools-26.0.2 + - android-26 diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 10cf65e..8647ef9 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -53,8 +53,8 @@ gradle.projectsEvaluated { } android { - compileSdkVersion 23 - buildToolsVersion '23.0.3' + compileSdkVersion 26 + buildToolsVersion '26.0.2' signingConfigs {} lintOptions { abortOnError false From 378a0faa6744c42a6afa545228abe5fbc6dfa90f Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 6 Oct 2017 20:20:16 +0200 Subject: [PATCH 054/197] Update a few dependencies. --- meteroid/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 8647ef9..0dc78cd 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -36,9 +36,9 @@ dependencies { repositories { maven { url 'http://repo1.maven.org/maven2' } } - compile 'org.jetbrains:annotations:13.0' - compile 'com.squareup.retrofit2:retrofit:2.1.0' - compile 'com.squareup.retrofit2:converter-gson:2.1.0' + compile 'org.jetbrains:annotations:15.0' + compile 'com.squareup.retrofit2:retrofit:2.3.0' + compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.google.zxing:android-integration:3.3.0' compile 'com.melnykov:floatingactionbutton:1.3.0' compile 'com.android.support:support-v4:22.1.1@aar' From 806ddf42d0ef74e5e4a5b07621096705b244303b Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 6 Oct 2017 20:28:45 +0200 Subject: [PATCH 055/197] Retrieve defaults for new users when creating new users. --- .../de/chaosdorf/meteroid/UserSettings.java | 46 ++++++++----------- .../java/de/chaosdorf/meteroid/util/API.java | 4 ++ 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index db18563..5170ba5 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -111,33 +111,25 @@ public void onClick(View view) } } - if(userID != 0) //existing user - { - makeReadOnly(); - final UserSettings userSettings = this; - new LongRunningIORequest(new LongRunningIOCallback() { - @Override - public void displayErrorMessage(LongRunningIOTask task, String message) - { - userSettings.displayErrorMessage(task, message); - } - - @Override - public void processIOResult(LongRunningIOTask task, User user) - { - usernameText.setText(user.getName()); - emailText.setText(user.getEmail()); - balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); - activeCheck.setChecked(user.getActive()); - makeWritable(); - } - }, LongRunningIOTask.GET_USER, api.getUser(userID)); - } - else - { - activeCheck.setChecked(true); - } - + makeReadOnly(); + final UserSettings userSettings = this; + new LongRunningIORequest(new LongRunningIOCallback() { + @Override + public void displayErrorMessage(LongRunningIOTask task, String message) + { + userSettings.displayErrorMessage(task, message); + } + + @Override + public void processIOResult(LongRunningIOTask task, User user) + { + usernameText.setText(user.getName()); + emailText.setText(user.getEmail()); + balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); + activeCheck.setChecked(user.getActive()); + makeWritable(); + } + }, LongRunningIOTask.GET_USER, (userID != 0)? api.getUser(userID): api.getUserDefaults()); } @Override diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java index 8c4ab74..9926968 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java @@ -67,6 +67,10 @@ Call> listAudits( @GET("users/{uid}.json") Call getUser(@Path("uid") int uid); + // returns the defaults for creating new users + @GET("users/new.json") + Call getUserDefaults(); + // creates a new user @POST("users.json") Call createUser( From fe0720f64d48ac06336f2c8cd881249dca74e37b Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 6 Oct 2017 20:32:19 +0200 Subject: [PATCH 056/197] Remove gradle.properties. --- gradle.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b3c7a03..e69de29 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +0,0 @@ -org.gradle.jvmargs=-Xmx2048M From a58567ad87f68cf650ad3b9f3011b3ec99beeef9 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 6 Oct 2017 20:34:20 +0200 Subject: [PATCH 057/197] More compatibility with Java 7. --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 495c503..8a1b4bf 100644 --- a/build.gradle +++ b/build.gradle @@ -1 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. + +// Be compatible to Java 7. +tasks.withType(JavaCompile) { + sourceCompatibility = "1.7" + targetCompatibility = "1.7" +} From 087c1659369ca8c842b65bd19d316d3cd5792da1 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 6 Oct 2017 21:11:29 +0200 Subject: [PATCH 058/197] Correctly pass parameters in a POST. --- .../java/de/chaosdorf/meteroid/util/API.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java index 9926968..13657e7 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java @@ -72,22 +72,24 @@ Call> listAudits( Call getUserDefaults(); // creates a new user + @FormUrlEncoded @POST("users.json") Call createUser( - @Query("user[name]") String name, - @Query("user[email]") String email, - @Query("user[balance]") Double balance, - @Query("user[active]") Boolean active + @Field("user[name]") String name, + @Field("user[email]") String email, + @Field("user[balance]") Double balance, + @Field("user[active]") Boolean active ); // modifys an existing user + @FormUrlEncoded @PATCH("users/{uid}.json") Call editUser( @Path("uid") int uid, - @Query("user[name]") String name, - @Query("user[email]") String email, - @Query("user[balance]") Double balance, - @Query("user[active]") Boolean active + @Field("user[name]") String name, + @Field("user[email]") String email, + @Field("user[balance]") Double balance, + @Field("user[active]") Boolean active ); // deletes an existing user @@ -116,10 +118,11 @@ Call buy( ); // buys a drink by barcode + @FormUrlEncoded @POST("users/{uid}/buy_barcode.json") Call buy_barcode( @Path("uid") int uid, - @Query("barcode") String barcode + @Field("barcode") String barcode ); /*// retrieves various statistics From 600f4627d9ef19969f3513d2954304673580129f Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 10:39:24 +0200 Subject: [PATCH 059/197] Add audit and redirect as properties for users. --- .../de/chaosdorf/meteroid/PickUsername.java | 2 +- .../de/chaosdorf/meteroid/UserSettings.java | 22 ++++++++++++++++--- .../de/chaosdorf/meteroid/model/User.java | 16 +++++++++++++- .../java/de/chaosdorf/meteroid/util/API.java | 8 +++++-- .../res/layout/activity_user_settings.xml | 12 ++++++++++ meteroid/src/main/res/values-de/strings.xml | 2 ++ meteroid/src/main/res/values/strings.xml | 2 ++ 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index ce92f1e..bac08bb 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -229,7 +229,7 @@ public void processIOResult(final LongRunningIOTask task, final List resul final List itemList = result; if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0, true)); + itemList.add(new User(NEW_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0, true, false, true)); } final UserAdapter userAdapter = new UserAdapter(itemList); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 5170ba5..48ebeb1 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -57,6 +57,8 @@ public class UserSettings extends MeteroidNetworkActivity private TextView emailText; private TextView balanceText; private CheckBox activeCheck; + private CheckBox auditCheck; + private CheckBox redirectCheck; @Override protected void onCreate(final Bundle savedInstanceState) @@ -69,6 +71,8 @@ protected void onCreate(final Bundle savedInstanceState) emailText = (TextView) findViewById(R.id.email); balanceText = (TextView) findViewById(R.id.balance); activeCheck = (CheckBox) findViewById(R.id.active); + auditCheck = (CheckBox) findViewById(R.id.audit); + redirectCheck = (CheckBox) findViewById(R.id.redirect); final ImageButton backButton = (ImageButton) findViewById(R.id.button_back); backButton.setOnClickListener(new View.OnClickListener() @@ -127,6 +131,8 @@ public void processIOResult(LongRunningIOTask task, User user) emailText.setText(user.getEmail()); balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); activeCheck.setChecked(user.getActive()); + auditCheck.setChecked(user.getAudit()); + redirectCheck.setChecked(user.getRedirect()); makeWritable(); } }, LongRunningIOTask.GET_USER, (userID != 0)? api.getUser(userID): api.getUserDefaults()); @@ -173,6 +179,9 @@ private void makeReadOnly() usernameText.setEnabled(false); emailText.setEnabled(false); balanceText.setEnabled(false); + activeCheck.setEnabled(false); + auditCheck.setEnabled(false); + redirectCheck.setEnabled(false); setProgressBarIndeterminateVisibility(true); } @@ -182,6 +191,9 @@ private void makeWritable() usernameText.setEnabled(true); emailText.setEnabled(true); balanceText.setEnabled(true); + activeCheck.setEnabled(true); + auditCheck.setEnabled(true); + redirectCheck.setEnabled(true); } private void goBack() @@ -278,12 +290,16 @@ private void saveUser() } boolean activeValue = activeCheck.isChecked(); + boolean auditValue = auditCheck.isChecked(); + boolean redirectValue = redirectCheck.isChecked(); final User user = new User(userID, username.toString(), emailValue, balanceValue, - activeValue + activeValue, + auditValue, + redirectValue ); final UserSettings userSettings = this; @@ -303,7 +319,7 @@ public void processIOResult(LongRunningIOTask task, User result) } }, LongRunningIOTask.ADD_USER, - api.createUser(user.getName(), user.getEmail(), user.getBalance(), activeValue) + api.createUser(user.getName(), user.getEmail(), user.getBalance(), user.getActive(), user.getAudit(), user.getRedirect()) ); } else @@ -322,7 +338,7 @@ public void processIOResult(LongRunningIOTask task, Void result) } }, LongRunningIOTask.EDIT_USER, - api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), activeValue) + api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), user.getActive(), user.getAudit(), user.getRedirect()) ); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java index 5915e0b..7f061ab 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java @@ -31,14 +31,18 @@ public class User private final String email; private final double balance; private final boolean active; + private final boolean audit; + private final boolean redirect; - public User(final int id, final String name, final String email, final double balance, final boolean active) + public User(final int id, final String name, final String email, final double balance, final boolean active, final boolean audit, final boolean redirect) { this.id = id; this.name = name; this.email = email; this.balance = balance; this.active = active; + this.audit = audit; + this.redirect = redirect; } public int getId() @@ -65,4 +69,14 @@ public boolean getActive() { return active; } + + public boolean getAudit() + { + return audit; + } + + public boolean getRedirect() + { + return redirect; + } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java index 13657e7..2f5f5d4 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java @@ -78,7 +78,9 @@ Call createUser( @Field("user[name]") String name, @Field("user[email]") String email, @Field("user[balance]") Double balance, - @Field("user[active]") Boolean active + @Field("user[active]") Boolean active, + @Field("user[audit]") Boolean audit, + @Field("user[redirect]") Boolean redirect ); // modifys an existing user @@ -89,7 +91,9 @@ Call editUser( @Field("user[name]") String name, @Field("user[email]") String email, @Field("user[balance]") Double balance, - @Field("user[active]") Boolean active + @Field("user[active]") Boolean active, + @Field("user[audit]") Boolean audit, + @Field("user[redirect]") Boolean redirect ); // deletes an existing user diff --git a/meteroid/src/main/res/layout/activity_user_settings.xml b/meteroid/src/main/res/layout/activity_user_settings.xml index 5f5a00f..26d4646 100644 --- a/meteroid/src/main/res/layout/activity_user_settings.xml +++ b/meteroid/src/main/res/layout/activity_user_settings.xml @@ -61,6 +61,18 @@ android:text="@string/user_settings_active" android:layout_height="wrap_content" android:layout_width="fill_parent"/> + + + + Email Guthaben Aktiv? + Transaktionen loggen? + Umleiten nach einer Transaktion? Bitte Benutzername eingeben Bitte Guthaben als Zahl eingeben Kann keinen noch nicht erstellten Benutzer löschen. diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index e6ba311..7b3324d 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -47,6 +47,8 @@ Email Balance Active? + Log transactions? + Redirect after a transaction? Please enter a username Please enter a number as a balance Can\'t delete a not yet existing user. From e34ad3f985fc47029cab3cc38baded0c42feb738 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 11:37:31 +0200 Subject: [PATCH 060/197] When creating or modifying a user, send JSON in the POST body. --- .../java/de/chaosdorf/meteroid/UserSettings.java | 4 ++-- .../java/de/chaosdorf/meteroid/util/API.java | 16 ++-------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 48ebeb1..a76816d 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -319,7 +319,7 @@ public void processIOResult(LongRunningIOTask task, User result) } }, LongRunningIOTask.ADD_USER, - api.createUser(user.getName(), user.getEmail(), user.getBalance(), user.getActive(), user.getAudit(), user.getRedirect()) + api.createUser(user) ); } else @@ -338,7 +338,7 @@ public void processIOResult(LongRunningIOTask task, Void result) } }, LongRunningIOTask.EDIT_USER, - api.editUser(user.getId(), user.getName(), user.getEmail(), user.getBalance(), user.getActive(), user.getAudit(), user.getRedirect()) + api.editUser(user.getId(), user) ); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java index 2f5f5d4..b9663f2 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/API.java @@ -72,28 +72,16 @@ Call> listAudits( Call getUserDefaults(); // creates a new user - @FormUrlEncoded @POST("users.json") Call createUser( - @Field("user[name]") String name, - @Field("user[email]") String email, - @Field("user[balance]") Double balance, - @Field("user[active]") Boolean active, - @Field("user[audit]") Boolean audit, - @Field("user[redirect]") Boolean redirect + @Body User user ); // modifys an existing user - @FormUrlEncoded @PATCH("users/{uid}.json") Call editUser( @Path("uid") int uid, - @Field("user[name]") String name, - @Field("user[email]") String email, - @Field("user[balance]") Double balance, - @Field("user[active]") Boolean active, - @Field("user[audit]") Boolean audit, - @Field("user[redirect]") Boolean redirect + @Body User user ); // deletes an existing user From 54c689f605d0dc057b65dc3e42e8e02963755341 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 13:19:53 +0200 Subject: [PATCH 061/197] Add data binding to UserSettings. --- meteroid/build.gradle | 3 + .../de/chaosdorf/meteroid/UserSettings.java | 94 ++++------ .../de/chaosdorf/meteroid/model/User.java | 42 ++++- .../res/layout/activity_user_settings.xml | 172 ++++++++++-------- 4 files changed, 170 insertions(+), 141 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 0dc78cd..9f5851d 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -61,4 +61,7 @@ android { //ActionBar on Gingerbread disable 'UnusedAttribute' } + dataBinding { + enabled = true + } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index a76816d..6d8638a 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -26,6 +26,7 @@ import android.app.ActionBar; import android.app.AlertDialog; +import android.databinding.DataBindingUtil; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; @@ -44,6 +45,7 @@ import java.text.ParseException; import java.util.Date; +import de.chaosdorf.meteroid.databinding.ActivityUserSettingsBinding; import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; @@ -53,29 +55,19 @@ public class UserSettings extends MeteroidNetworkActivity { - private TextView usernameText; - private TextView emailText; - private TextView balanceText; - private CheckBox activeCheck; - private CheckBox auditCheck; - private CheckBox redirectCheck; + private User user; + private ActivityUserSettingsBinding binding; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - setContentView(R.layout.activity_user_settings); + binding = DataBindingUtil.setContentView(this, R.layout.activity_user_settings); + binding.setUser(user); + binding.setDECIMALFORMAT(DECIMAL_FORMAT); - usernameText = (TextView) findViewById(R.id.username); - emailText = (TextView) findViewById(R.id.email); - balanceText = (TextView) findViewById(R.id.balance); - activeCheck = (CheckBox) findViewById(R.id.active); - auditCheck = (CheckBox) findViewById(R.id.audit); - redirectCheck = (CheckBox) findViewById(R.id.redirect); - - final ImageButton backButton = (ImageButton) findViewById(R.id.button_back); - backButton.setOnClickListener(new View.OnClickListener() + binding.buttonBack.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -83,8 +75,7 @@ public void onClick(View view) } }); - final ImageButton deleteButton = (ImageButton) findViewById(R.id.button_delete); - deleteButton.setOnClickListener(new View.OnClickListener() + binding.buttonDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) @@ -93,8 +84,7 @@ public void onClick(View view) } }); - final ImageButton saveButton = (ImageButton) findViewById(R.id.button_save); - saveButton.setOnClickListener(new View.OnClickListener() + binding.buttonSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) @@ -109,9 +99,9 @@ public void onClick(View view) if(actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); - backButton.setVisibility(View.GONE); - deleteButton.setVisibility(View.GONE); - saveButton.setVisibility(View.GONE); + binding.buttonBack.setVisibility(View.GONE); + binding.buttonDelete.setVisibility(View.GONE); + binding.buttonSave.setVisibility(View.GONE); } } @@ -127,12 +117,8 @@ public void displayErrorMessage(LongRunningIOTask task, String message) @Override public void processIOResult(LongRunningIOTask task, User user) { - usernameText.setText(user.getName()); - emailText.setText(user.getEmail()); - balanceText.setText(DECIMAL_FORMAT.format(user.getBalance())); - activeCheck.setChecked(user.getActive()); - auditCheck.setChecked(user.getAudit()); - redirectCheck.setChecked(user.getRedirect()); + userSettings.user = user; + binding.setUser(user); makeWritable(); } }, LongRunningIOTask.GET_USER, (userID != 0)? api.getUser(userID): api.getUserDefaults()); @@ -176,24 +162,24 @@ public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) private void makeReadOnly() { - usernameText.setEnabled(false); - emailText.setEnabled(false); - balanceText.setEnabled(false); - activeCheck.setEnabled(false); - auditCheck.setEnabled(false); - redirectCheck.setEnabled(false); + binding.username.setEnabled(false); + binding.email.setEnabled(false); + binding.balance.setEnabled(false); + binding.active.setEnabled(false); + binding.audit.setEnabled(false); + binding.redirect.setEnabled(false); setProgressBarIndeterminateVisibility(true); } private void makeWritable() { setProgressBarIndeterminateVisibility(false); - usernameText.setEnabled(true); - emailText.setEnabled(true); - balanceText.setEnabled(true); - activeCheck.setEnabled(true); - auditCheck.setEnabled(true); - redirectCheck.setEnabled(true); + binding.username.setEnabled(true); + binding.email.setEnabled(true); + binding.balance.setEnabled(true); + binding.active.setEnabled(true); + binding.audit.setEnabled(true); + binding.redirect.setEnabled(true); } private void goBack() @@ -258,7 +244,7 @@ private void saveUser() { makeReadOnly(); - final CharSequence username = usernameText.getText(); + final CharSequence username = binding.username.getText(); if (username == null || username.length() == 0) { Utility.displayToastMessage(this, getResources().getString(R.string.user_settings_empty_username)); @@ -266,16 +252,9 @@ private void saveUser() return; } - final CharSequence email = emailText.getText(); - String emailValue = ""; - if (email != null && email.length() > 0) - { - emailValue = email.toString(); - } - double balanceValue = 0; - final CharSequence balance = balanceText.getText(); - if (balance != null && balance.length() > 0) + final CharSequence balance = binding.balance.getText(); + if (balance != null) { try { @@ -289,18 +268,7 @@ private void saveUser() } } - boolean activeValue = activeCheck.isChecked(); - boolean auditValue = auditCheck.isChecked(); - boolean redirectValue = redirectCheck.isChecked(); - - final User user = new User(userID, - username.toString(), - emailValue, - balanceValue, - activeValue, - auditValue, - redirectValue - ); + user.setBalance(balanceValue); final UserSettings userSettings = this; if(userID == 0) //new user diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java index 7f061ab..567bade 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/model/User.java @@ -27,12 +27,12 @@ public class User { private final int id; - private final String name; - private final String email; - private final double balance; - private final boolean active; - private final boolean audit; - private final boolean redirect; + private String name; + private String email; + private double balance; + private boolean active; + private boolean audit; + private boolean redirect; public User(final int id, final String name, final String email, final double balance, final boolean active, final boolean audit, final boolean redirect) { @@ -54,29 +54,59 @@ public String getName() { return name; } + + public void setName(String name) + { + this.name = name; + } public String getEmail() { return email; } + + public void setEmail(String email) + { + this.email = email; + } public double getBalance() { return balance; } + public void setBalance(double balance) + { + this.balance = balance; + } + public boolean getActive() { return active; } + public void setActive(boolean active) + { + this.active = active; + } + public boolean getAudit() { return audit; } + public void setAudit(boolean audit) + { + this.audit = audit; + } + public boolean getRedirect() { return redirect; } + + public void setRedirect(boolean redirect) + { + this.redirect = redirect; + } } diff --git a/meteroid/src/main/res/layout/activity_user_settings.xml b/meteroid/src/main/res/layout/activity_user_settings.xml index 26d4646..479698b 100644 --- a/meteroid/src/main/res/layout/activity_user_settings.xml +++ b/meteroid/src/main/res/layout/activity_user_settings.xml @@ -24,85 +24,113 @@ ~ THE SOFTWARE. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - + + + + + + + + - - - + - - - - - - - + - + + + + + + + - - - + android:layout_width="wrap_content" + android:orientation="horizontal" + android:layout_gravity="right" + > - + + + android:src="@android:drawable/ic_delete" + android:contentDescription="@string/button_delete"/> + + - + - + + From cf7230fe088bdafebd0d6fc43f53b1a589525cd4 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 14:41:23 +0200 Subject: [PATCH 062/197] UserSettings: setWritable --- .../java/de/chaosdorf/meteroid/UserSettings.java | 14 ++------------ .../src/main/res/layout/activity_user_settings.xml | 13 +++++++++++++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 6d8638a..a4df417 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -162,24 +162,14 @@ public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) private void makeReadOnly() { - binding.username.setEnabled(false); - binding.email.setEnabled(false); - binding.balance.setEnabled(false); - binding.active.setEnabled(false); - binding.audit.setEnabled(false); - binding.redirect.setEnabled(false); + binding.setWritable(false); setProgressBarIndeterminateVisibility(true); } private void makeWritable() { setProgressBarIndeterminateVisibility(false); - binding.username.setEnabled(true); - binding.email.setEnabled(true); - binding.balance.setEnabled(true); - binding.active.setEnabled(true); - binding.audit.setEnabled(true); - binding.redirect.setEnabled(true); + binding.setWritable(true); } private void goBack() diff --git a/meteroid/src/main/res/layout/activity_user_settings.xml b/meteroid/src/main/res/layout/activity_user_settings.xml index 479698b..fe073e2 100644 --- a/meteroid/src/main/res/layout/activity_user_settings.xml +++ b/meteroid/src/main/res/layout/activity_user_settings.xml @@ -39,6 +39,10 @@ name="DECIMAL_FORMAT" type="java.text.DecimalFormat" /> + From 6f8948834fe6a86a14a2302f6eba985ba5e29181 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 14:44:28 +0200 Subject: [PATCH 063/197] UserSettings: Remove unused imports. --- meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index a4df417..8a610e5 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -36,9 +36,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.Window; -import android.widget.CheckBox; -import android.widget.ImageButton; -import android.widget.TextView; import org.jetbrains.annotations.NotNull; From e2fac0b69d29e59b970c5d66c381b5a3e880fda5 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 15:37:12 +0200 Subject: [PATCH 064/197] Add data binding to BuyDrink. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 111 +++---- .../main/res/layout/activity_buy_drink.xml | 285 ++++++++++-------- 2 files changed, 196 insertions(+), 200 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 296f4fa..b576fdc 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -27,6 +27,7 @@ import android.app.ActionBar; import android.content.Context; import android.content.Intent; +import android.databinding.DataBindingUtil; import android.graphics.Color; import android.os.Bundle; import android.os.Build; @@ -39,11 +40,7 @@ import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.GridView; -import android.widget.ImageButton; import android.widget.ImageView; -import android.widget.ListView; -import android.widget.ProgressBar; import android.widget.TextView; import com.melnykov.fab.FloatingActionButton; @@ -59,6 +56,7 @@ import com.google.zxing.integration.android.IntentResult; import de.chaosdorf.meteroid.controller.MoneyController; +import de.chaosdorf.meteroid.databinding.ActivityBuyDrinkBinding; import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; @@ -74,12 +72,8 @@ public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnI private final AtomicBoolean isBuying = new AtomicBoolean(true); private final AtomicReference buyingItem = new AtomicReference(null); - private ProgressBar progressBar = null; - private GridView gridView = null; - private ListView listView = null; - private FloatingActionButton fab = null; - private User user; + private ActivityBuyDrinkBinding binding; private boolean useGridView; private boolean multiUserMode; @@ -91,19 +85,16 @@ protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - setContentView(R.layout.activity_buy_drink); + binding = DataBindingUtil.setContentView(this, R.layout.activity_buy_drink); + binding.setUser(user); + binding.setDECIMALFORMAT(DECIMAL_FORMAT); barcodeIntegrator = new IntentIntegrator(this); - progressBar = (ProgressBar) findViewById(R.id.progress_bar); - gridView = (GridView) findViewById(R.id.grid_view); - listView = (ListView) findViewById(R.id.list_view); - useGridView = prefs.getBoolean("use_grid_view", false); multiUserMode = prefs.getBoolean("multi_user_mode", false); - final ImageButton backButton = (ImageButton) findViewById(R.id.button_back); - backButton.setOnClickListener(new View.OnClickListener() + binding.buttonBack.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -112,8 +103,7 @@ public void onClick(View view) } }); - final ImageButton reloadButton = (ImageButton) findViewById(R.id.button_reload); - reloadButton.setOnClickListener(new View.OnClickListener() + binding.buttonReload.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -121,8 +111,7 @@ public void onClick(View view) } }); - final ImageButton editButton = (ImageButton) findViewById(R.id.button_edit); - editButton.setOnClickListener(new View.OnClickListener() + binding.buttonEdit.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -130,8 +119,7 @@ public void onClick(View view) } }); - final ImageButton barcodeButton = (ImageButton) findViewById(R.id.button_barcode); - barcodeButton.setOnClickListener(new View.OnClickListener() + binding.buttonBarcode.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -143,24 +131,23 @@ public void onClick(View view) { ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); - reloadButton.setVisibility(View.GONE); - backButton.setVisibility(View.GONE); - editButton.setVisibility(View.GONE); - barcodeButton.setVisibility(View.GONE); + binding.buttonReload.setVisibility(View.GONE); + binding.buttonBack.setVisibility(View.GONE); + binding.buttonEdit.setVisibility(View.GONE); + binding.buttonBarcode.setVisibility(View.GONE); } if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - fab = (FloatingActionButton) findViewById(R.id.fab); - fab.hide(false); - fab.setOnClickListener(new View.OnClickListener() + binding.fab.hide(false); + binding.fab.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { barcodeIntegrator.initiateScan(); } }); - fab.setVisibility(View.VISIBLE); + binding.fab.setVisibility(View.VISIBLE); } reload(); @@ -168,9 +155,9 @@ public void onClick(View view) public void reload() { - gridView.setVisibility(View.GONE); - listView.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); + binding.gridView.setVisibility(View.GONE); + binding.listView.setVisibility(View.GONE); + binding.progressBar.setVisibility(View.VISIBLE); new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } @@ -240,13 +227,13 @@ public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) public void onDestroy() { buyingItem.set(null); - if (gridView != null) + if (binding.gridView != null) { - gridView.setAdapter(null); + binding.gridView.setAdapter(null); } - if (listView != null) + if (binding.listView != null) { - listView.setAdapter(null); + binding.listView.setAdapter(null); } super.onDestroy(); } @@ -263,11 +250,10 @@ public void displayErrorMessage(final LongRunningIOTask task, final String messa { Utility.displayToastMessage(this, message); } - final TextView textView = (TextView) findViewById(R.id.buy_drink_error); - textView.setVisibility(View.VISIBLE); - gridView.setVisibility(View.GONE); - listView.setVisibility(View.GONE); - progressBar.setVisibility(View.GONE); + binding.buyDrinkError.setVisibility(View.VISIBLE); + binding.gridView.setVisibility(View.GONE); + binding.listView.setVisibility(View.GONE); + binding.progressBar.setVisibility(View.GONE); } @Override @@ -280,14 +266,12 @@ public void processIOResult(final LongRunningIOTask task, final Object result) case UPDATE_USER: { user = (User)result; + binding.setUser(user); + ((BuyDrink)activity).user = user; if (task == LongRunningIOTask.GET_USER) { - final TextView label = (TextView) findViewById(R.id.username); - final ImageView icon = (ImageView) findViewById(R.id.icon); - label.setText(user.getName()); - Utility.loadUserImage(this, icon, user); + Utility.loadUserImage(this, binding.icon, user); } - updateBalance(user.getBalance()); isBuying.set(false); setProgressBarIndeterminateVisibility(false); break; @@ -303,21 +287,21 @@ public void processIOResult(final LongRunningIOTask task, final Object result) final BuyableItemAdapter buyableItemAdapter = new BuyableItemAdapter(buyableItemList); if (useGridView) { - gridView.setAdapter(buyableItemAdapter); - gridView.setOnItemClickListener(this); - gridView.setVisibility(View.VISIBLE); + binding.gridView.setAdapter(buyableItemAdapter); + binding.gridView.setOnItemClickListener(this); + binding.gridView.setVisibility(View.VISIBLE); } else { - listView.setAdapter(buyableItemAdapter); - listView.setOnItemClickListener(this); - listView.setVisibility(View.VISIBLE); + binding.listView.setAdapter(buyableItemAdapter); + binding.listView.setOnItemClickListener(this); + binding.listView.setVisibility(View.VISIBLE); } - progressBar.setVisibility(View.GONE); - if(fab != null) + binding.progressBar.setVisibility(View.GONE); + if(binding.fab != null) { - fab.attachToListView(useGridView? gridView : listView); - fab.show(); + binding.fab.attachToListView(useGridView? binding.gridView : binding.listView); + binding.fab.show(); } break; } @@ -339,7 +323,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) // Adjust the displayed balance to give an immediate user feedback if (user != null) { - updateBalance(user.getBalance() - buyableItem.getPrice()); + user.setBalance(user.getBalance() - buyableItem.getPrice()); } if (multiUserMode) { @@ -371,7 +355,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) // Adjust the displayed balance to give an immediate user feedback if (user != null) { - updateBalance(user.getBalance() - buyableItem.getPrice()); + user.setBalance(user.getBalance() - buyableItem.getPrice()); } } new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); @@ -390,7 +374,7 @@ public void onItemClick(final AdapterView adapterView, final View view, final } if (isBuying.compareAndSet(false, true)) { - final BuyableItem buyableItem = (BuyableItem) (useGridView ? gridView.getItemAtPosition(index) : listView.getAdapter().getItem(index)); + final BuyableItem buyableItem = (BuyableItem) (useGridView ? binding.gridView.getItemAtPosition(index) : binding.listView.getAdapter().getItem(index)); if (buyableItem != null) { buyingItem.set(buyableItem); @@ -475,13 +459,6 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) } } } - - private void updateBalance(double amount) - { - final TextView balance = (TextView) findViewById(R.id.balance); - balance.setText(DECIMAL_FORMAT.format(amount)); - balance.setTextColor(amount >= 0 ? Color.LTGRAY : Color.RED); - } private class BuyableComparator implements Comparator { diff --git a/meteroid/src/main/res/layout/activity_buy_drink.xml b/meteroid/src/main/res/layout/activity_buy_drink.xml index 82c8608..5d47045 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink.xml @@ -24,142 +24,161 @@ ~ THE SOFTWARE. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - - - - - - - + + + + + + + + + + + + + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_alignParentBottom="true" + android:layout_alignParentRight="true" + android:layout_margin="16dip" + android:src="@drawable/button_barcode" /> + + + From 1c15bf29edc99905e21279155550c24252f694f3 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 16:56:59 +0200 Subject: [PATCH 065/197] Add util.Config. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 56 +++++++++--------- .../de/chaosdorf/meteroid/MainActivity.java | 11 ++-- .../meteroid/MeteroidNetworkActivity.java | 13 ++--- .../de/chaosdorf/meteroid/PickUsername.java | 6 +- .../de/chaosdorf/meteroid/SetHostname.java | 15 +++-- .../de/chaosdorf/meteroid/UserSettings.java | 13 +++-- .../de/chaosdorf/meteroid/util/Config.java | 57 +++++++++++++++++++ .../chaosdorf/meteroid/util/MenuUtility.java | 4 +- .../de/chaosdorf/meteroid/util/Utility.java | 6 -- 9 files changed, 112 insertions(+), 69 deletions(-) create mode 100644 meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index b576fdc..4f6f45a 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -75,9 +75,6 @@ public class BuyDrink extends MeteroidNetworkActivity implements AdapterView.OnI private User user; private ActivityBuyDrinkBinding binding; - private boolean useGridView; - private boolean multiUserMode; - private IntentIntegrator barcodeIntegrator; @Override @@ -91,14 +88,12 @@ protected void onCreate(final Bundle savedInstanceState) barcodeIntegrator = new IntentIntegrator(this); - useGridView = prefs.getBoolean("use_grid_view", false); - multiUserMode = prefs.getBoolean("multi_user_mode", false); - binding.buttonBack.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { - Utility.resetUsername(activity); + config.userID = 0; + config.save(); Utility.startActivity(activity, PickUsername.class); } }); @@ -158,7 +153,7 @@ public void reload() binding.gridView.setVisibility(View.GONE); binding.listView.setVisibility(View.GONE); binding.progressBar.setVisibility(View.VISIBLE); - new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.GET_USER, api.getUser(config.userID)); new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); } @@ -166,8 +161,8 @@ public void reload() public boolean onCreateOptionsMenu(final Menu menu) { getMenuInflater().inflate(R.menu.buydrink, menu); - MenuUtility.setChecked(menu, R.id.use_grid_view, useGridView); - MenuUtility.setChecked(menu, R.id.multi_user_mode, multiUserMode); + MenuUtility.setChecked(menu, R.id.use_grid_view, config.useGridView); + MenuUtility.setChecked(menu, R.id.multi_user_mode, config.multiUserMode); return true; } @@ -177,7 +172,8 @@ public boolean onOptionsItemSelected(final MenuItem item) switch (item.getItemId()) { case android.R.id.home: - Utility.resetUsername(this); + config.userID = 0; + config.save(); Utility.startActivity(this, PickUsername.class); break; case R.id.action_reload: @@ -193,16 +189,17 @@ public boolean onOptionsItemSelected(final MenuItem item) Utility.startActivity(this, SetHostname.class); break; case R.id.reset_username: - Utility.resetUsername(this); + config.userID = 0; + config.save(); Utility.startActivity(this, PickUsername.class); break; case R.id.use_grid_view: - useGridView = Utility.toggleUseGridView(this); - item.setChecked(useGridView); + config.useGridView = Utility.toggleUseGridView(this); + item.setChecked(config.useGridView); Utility.startActivity(this, BuyDrink.class); break; case R.id.multi_user_mode: - multiUserMode = MenuUtility.onClickMultiUserMode(this, item); + config.multiUserMode = MenuUtility.onClickMultiUserMode(this, item); break; } return super.onOptionsItemSelected(item); @@ -213,9 +210,10 @@ public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - if (multiUserMode) + if (config.multiUserMode) { - Utility.resetUsername(this); + config.userID = 0; + config.save(); Utility.startActivity(this, MainActivity.class); return true; } @@ -285,7 +283,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) Collections.sort(buyableItemList, new BuyableComparator()); final BuyableItemAdapter buyableItemAdapter = new BuyableItemAdapter(buyableItemList); - if (useGridView) + if (config.useGridView) { binding.gridView.setAdapter(buyableItemAdapter); binding.gridView.setOnItemClickListener(this); @@ -300,7 +298,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) binding.progressBar.setVisibility(View.GONE); if(binding.fab != null) { - binding.fab.attachToListView(useGridView? binding.gridView : binding.listView); + binding.fab.attachToListView(config.useGridView? binding.gridView : binding.listView); binding.fab.show(); } break; @@ -325,13 +323,13 @@ public void processIOResult(final LongRunningIOTask task, final Object result) { user.setBalance(user.getBalance() - buyableItem.getPrice()); } - if (multiUserMode) + if (config.multiUserMode) { Utility.startActivity(this, PickUsername.class); break; } } - new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(config.userID)); if(!buyableItem.getActive()) { new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, api.listDrinks()); @@ -358,7 +356,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) user.setBalance(user.getBalance() - buyableItem.getPrice()); } } - new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(userID)); + new LongRunningIORequest(this, LongRunningIOTask.UPDATE_USER, api.getUser(config.userID)); break; } } @@ -374,18 +372,18 @@ public void onItemClick(final AdapterView adapterView, final View view, final } if (isBuying.compareAndSet(false, true)) { - final BuyableItem buyableItem = (BuyableItem) (useGridView ? binding.gridView.getItemAtPosition(index) : binding.listView.getAdapter().getItem(index)); + final BuyableItem buyableItem = (BuyableItem) (config.useGridView ? binding.gridView.getItemAtPosition(index) : binding.listView.getAdapter().getItem(index)); if (buyableItem != null) { buyingItem.set(buyableItem); setProgressBarIndeterminateVisibility(true); if(buyableItem.isDrink()) { - new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy(userID, ((Drink)buyableItem).getId())); + new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy(config.userID, ((Drink)buyableItem).getId())); } else { - new LongRunningIORequest(this, LongRunningIOTask.ADD_MONEY, api.deposit(userID, -buyableItem.getPrice())); + new LongRunningIORequest(this, LongRunningIOTask.ADD_MONEY, api.deposit(config.userID, -buyableItem.getPrice())); } } } @@ -408,7 +406,7 @@ public View getView(final int position, final View convertView, final ViewGroup View view = convertView; if (view == null) { - view = inflater.inflate(useGridView ? R.layout.activity_buy_drink_item_gridview : R.layout.activity_buy_drink_item, parent, false); + view = inflater.inflate(config.useGridView ? R.layout.activity_buy_drink_item_gridview : R.layout.activity_buy_drink_item, parent, false); } if (view == null) { @@ -418,10 +416,10 @@ public View getView(final int position, final View convertView, final ViewGroup final BuyableItem buyableItem = drinkList.get(position); final ImageView icon = (ImageView) view.findViewById(R.id.icon); - Utility.loadBuyableItemImage(activity, icon, buyableItem, hostname); + Utility.loadBuyableItemImage(activity, icon, buyableItem, config.hostname); final TextView label = (TextView) view.findViewById(R.id.label); - label.setText(createLabel(buyableItem, useGridView)); + label.setText(createLabel(buyableItem, config.useGridView)); return view; } @@ -455,7 +453,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) if(scanResult.getContents() != null) { System.err.println("Scanned barcode: " + scanResult.toString()); - new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy_barcode(userID, scanResult.getContents())); + new LongRunningIORequest(this, LongRunningIOTask.BUY_DRINK, api.buy_barcode(config.userID, scanResult.getContents())); } } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java index 40fd2e2..097afb1 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java @@ -25,10 +25,9 @@ package de.chaosdorf.meteroid; import android.app.Activity; -import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; +import de.chaosdorf.meteroid.util.Config; import de.chaosdorf.meteroid.util.Utility; public class MainActivity extends Activity @@ -38,16 +37,14 @@ protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - final String hostname = prefs.getString("hostname", null); - final int userID = prefs.getInt("userid", 0); + final Config config = new Config(this); - if (hostname == null) + if (config.hostname == null) { // Set hostname if not done yet Utility.startActivity(this, SetHostname.class); } - else if (userID == 0) + else if (config.userID == 0) { // Pick username if not done yet Utility.startActivity(this, PickUsername.class); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java index 04b8872..2185e83 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MeteroidNetworkActivity.java @@ -25,9 +25,7 @@ package de.chaosdorf.meteroid; import android.app.Activity; -import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; import java.text.DecimalFormat; @@ -35,6 +33,7 @@ import retrofit2.converter.gson.GsonConverterFactory; import de.chaosdorf.meteroid.util.API; +import de.chaosdorf.meteroid.util.Config; import de.chaosdorf.meteroid.util.Utility; @@ -44,19 +43,15 @@ public abstract class MeteroidNetworkActivity extends Activity protected Activity activity; protected API api; - protected String hostname; - protected int userID; - protected SharedPreferences prefs; + protected Config config; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); activity = this; - prefs = PreferenceManager.getDefaultSharedPreferences(this); - hostname = prefs.getString("hostname", null); - userID = prefs.getInt("userid", 0); - api = initializeRetrofit(hostname); + config = new Config(this); + api = initializeRetrofit(config.hostname); } private API initializeRetrofit(String url) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index bac08bb..8a571ce 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -28,7 +28,6 @@ import android.content.Context; import android.os.Bundle; import android.os.Build; -import android.preference.PreferenceManager; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; @@ -80,7 +79,7 @@ protected void onCreate(final Bundle savedInstanceState) progressBar = (ProgressBar) findViewById(R.id.progress_bar); gridView = (GridView) findViewById(R.id.grid_view); - multiUserMode = prefs.getBoolean("multi_user_mode", false); + multiUserMode = config.multiUserMode; final ImageButton backButton = (ImageButton) findViewById(R.id.button_back); backButton.setOnClickListener(new View.OnClickListener() @@ -256,7 +255,8 @@ public void onItemClick(final AdapterView adapterView, final View view, final } else { - prefs.edit().putInt("userid", user.getId()).apply(); + config.userID = user.getId(); + config.save(); Utility.startActivity(this, BuyDrink.class); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java index d4ef3e5..ef4f4ab 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java @@ -26,10 +26,8 @@ import android.app.Activity; import android.app.ActionBar; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Build; -import android.preference.PreferenceManager; import android.text.Editable; import android.text.Selection; import android.view.View; @@ -39,12 +37,13 @@ import android.widget.Button; import android.widget.EditText; +import de.chaosdorf.meteroid.util.Config; import de.chaosdorf.meteroid.util.Utility; public class SetHostname extends Activity { private Activity activity = null; - private SharedPreferences prefs; + private Config config; private EditText editText; private Button saveButton; @@ -55,15 +54,14 @@ protected void onCreate(final Bundle savedInstanceState) activity = this; setContentView(R.layout.activity_set_hostname); - prefs = PreferenceManager.getDefaultSharedPreferences(this); - final String hostname = prefs.getString("hostname", null); + config = new Config(this); editText = (EditText) findViewById(R.id.hostname); if (editText != null) { - if (hostname != null) + if (config.hostname != null) { - editText.setText(hostname); + editText.setText(config.hostname); } final Editable editTextHostname = editText.getText(); if (editTextHostname != null) @@ -138,7 +136,8 @@ public void saveHostname() Utility.displayToastMessage(activity, getResources().getString(R.string.set_hostname_invalid)); return; } - prefs.edit().putString("hostname", newHostname).apply(); + config.hostname = newHostname; + config.save(); Utility.startActivity(activity, PickUsername.class); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 8a610e5..572c344 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -118,7 +118,7 @@ public void processIOResult(LongRunningIOTask task, User user) binding.setUser(user); makeWritable(); } - }, LongRunningIOTask.GET_USER, (userID != 0)? api.getUser(userID): api.getUserDefaults()); + }, LongRunningIOTask.GET_USER, (config.userID != 0)? api.getUser(config.userID): api.getUserDefaults()); } @Override @@ -171,7 +171,7 @@ private void makeWritable() private void goBack() { - if(userID == 0) //new user + if(config.userID == 0) //new user { Utility.startActivity(this, PickUsername.class); } @@ -183,7 +183,7 @@ private void goBack() private void deleteUser() { - if(userID == 0) //new user + if(config.userID == 0) //new user { new AlertDialog.Builder(this) .setMessage(R.string.user_settings_cant_delete_non_existing_user) @@ -212,14 +212,15 @@ public void displayErrorMessage(LongRunningIOTask task, String message) @Override public void processIOResult(LongRunningIOTask task, Void result) { - Utility.resetUsername(userSettings); + config.userID = 0; + config.save(); makeWritable(); Utility.displayToastMessage(userSettings, getResources().getString(R.string.user_settings_deleted_user)); Utility.startActivity(userSettings, PickUsername.class); } }, LongRunningIOTask.DELETE_USER, - api.deleteUser(userID)); + api.deleteUser(config.userID)); } }) .setNegativeButton(android.R.string.cancel, null) // Do nothing on click. @@ -258,7 +259,7 @@ private void saveUser() user.setBalance(balanceValue); final UserSettings userSettings = this; - if(userID == 0) //new user + if(config.userID == 0) //new user { new LongRunningIORequest(new LongRunningIOCallback() { @Override diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java new file mode 100644 index 0000000..7ede458 --- /dev/null +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Chaosdorf e.V. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +package de.chaosdorf.meteroid.util; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +public class Config +{ + private SharedPreferences prefs; + public String hostname; + public boolean multiUserMode; + public boolean useGridView; + public int userID; + + public Config(Activity activity) + { + prefs = PreferenceManager.getDefaultSharedPreferences(activity); + hostname = prefs.getString("hostname", null); + multiUserMode = prefs.getBoolean("multi_user_mode", false); + useGridView = prefs.getBoolean("use_grid_view", false); + userID = prefs.getInt("userid", 0); + } + + public void save() + { + SharedPreferences.Editor edit = prefs.edit(); + edit.putString("hostname", this.hostname); + edit.putBoolean("multi_user_mode", this.multiUserMode); + edit.putBoolean("use_grid_view", this.useGridView); + edit.putInt("userid", this.userID); + edit.apply(); + } +} diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java index e483ecb..fff0143 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java @@ -45,7 +45,9 @@ public static boolean onClickMultiUserMode(final Activity activity, final MenuIt item.setChecked(multiUserMode); if (multiUserMode) { - Utility.resetUsername(activity); + Config config = new Config(activity); + config.userID = 0; + config.save(); } return multiUserMode; } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index 06502ac..5090b71 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -58,12 +58,6 @@ public static void startActivity(final Activity activity, Class classType) activity.startActivity(intent); } - public static void resetUsername(final Activity activity) - { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); - prefs.edit().remove("userid").apply(); - } - public static boolean toggleUseGridView(final Activity activity) { return Utility.toogleBooleanSharedPreference(activity, "use_grid_view", false, R.string.menu_use_grid_view_enabled, R.string.menu_use_grid_view_disabled); From 37a86f6e9ce33188856d830c840b9004926deab3 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 17:25:38 +0200 Subject: [PATCH 066/197] Config: Make default values more clear. --- .../java/de/chaosdorf/meteroid/util/Config.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java index 7ede458..2f88a17 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java @@ -31,18 +31,18 @@ public class Config { private SharedPreferences prefs; - public String hostname; - public boolean multiUserMode; - public boolean useGridView; - public int userID; + public String hostname = null; + public boolean multiUserMode = false; + public boolean useGridView = false; + public int userID = 0; public Config(Activity activity) { prefs = PreferenceManager.getDefaultSharedPreferences(activity); - hostname = prefs.getString("hostname", null); - multiUserMode = prefs.getBoolean("multi_user_mode", false); - useGridView = prefs.getBoolean("use_grid_view", false); - userID = prefs.getInt("userid", 0); + hostname = prefs.getString("hostname", hostname); + multiUserMode = prefs.getBoolean("multi_user_mode", multiUserMode); + useGridView = prefs.getBoolean("use_grid_view", useGridView); + userID = prefs.getInt("userid", userID); } public void save() From e268d66751d1d453100b4418aa109b8d1ba28860 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 17:28:05 +0200 Subject: [PATCH 067/197] Make clear what userID==0 means. --- .../src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 8 ++++---- .../src/main/java/de/chaosdorf/meteroid/MainActivity.java | 2 +- .../src/main/java/de/chaosdorf/meteroid/UserSettings.java | 8 ++++---- .../src/main/java/de/chaosdorf/meteroid/util/Config.java | 4 +++- .../main/java/de/chaosdorf/meteroid/util/MenuUtility.java | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 4f6f45a..4712ebf 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -92,7 +92,7 @@ protected void onCreate(final Bundle savedInstanceState) { public void onClick(View view) { - config.userID = 0; + config.userID = config.NO_USER_ID; config.save(); Utility.startActivity(activity, PickUsername.class); } @@ -172,7 +172,7 @@ public boolean onOptionsItemSelected(final MenuItem item) switch (item.getItemId()) { case android.R.id.home: - config.userID = 0; + config.userID = config.NO_USER_ID; config.save(); Utility.startActivity(this, PickUsername.class); break; @@ -189,7 +189,7 @@ public boolean onOptionsItemSelected(final MenuItem item) Utility.startActivity(this, SetHostname.class); break; case R.id.reset_username: - config.userID = 0; + config.userID = config.NO_USER_ID; config.save(); Utility.startActivity(this, PickUsername.class); break; @@ -212,7 +212,7 @@ public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) { if (config.multiUserMode) { - config.userID = 0; + config.userID = config.NO_USER_ID; config.save(); Utility.startActivity(this, MainActivity.class); return true; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java index 097afb1..1c774d1 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java @@ -44,7 +44,7 @@ protected void onCreate(final Bundle savedInstanceState) // Set hostname if not done yet Utility.startActivity(this, SetHostname.class); } - else if (config.userID == 0) + else if (config.userID == config.NO_USER_ID) { // Pick username if not done yet Utility.startActivity(this, PickUsername.class); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 572c344..e6c36c6 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -171,7 +171,7 @@ private void makeWritable() private void goBack() { - if(config.userID == 0) //new user + if(config.userID == config.NO_USER_ID) //new user { Utility.startActivity(this, PickUsername.class); } @@ -183,7 +183,7 @@ private void goBack() private void deleteUser() { - if(config.userID == 0) //new user + if(config.userID == config.NO_USER_ID) //new user { new AlertDialog.Builder(this) .setMessage(R.string.user_settings_cant_delete_non_existing_user) @@ -212,7 +212,7 @@ public void displayErrorMessage(LongRunningIOTask task, String message) @Override public void processIOResult(LongRunningIOTask task, Void result) { - config.userID = 0; + config.userID = config.NO_USER_ID; config.save(); makeWritable(); Utility.displayToastMessage(userSettings, getResources().getString(R.string.user_settings_deleted_user)); @@ -259,7 +259,7 @@ private void saveUser() user.setBalance(balanceValue); final UserSettings userSettings = this; - if(config.userID == 0) //new user + if(config.userID == config.NO_USER_ID) //new user { new LongRunningIORequest(new LongRunningIOCallback() { @Override diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java index 2f88a17..f530ad3 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java @@ -30,11 +30,13 @@ public class Config { + public static final int NO_USER_ID = 0; + private SharedPreferences prefs; public String hostname = null; public boolean multiUserMode = false; public boolean useGridView = false; - public int userID = 0; + public int userID = NO_USER_ID; public Config(Activity activity) { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java index fff0143..f0517fe 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/MenuUtility.java @@ -46,7 +46,7 @@ public static boolean onClickMultiUserMode(final Activity activity, final MenuIt if (multiUserMode) { Config config = new Config(activity); - config.userID = 0; + config.userID = config.NO_USER_ID; config.save(); } return multiUserMode; From 7fd75b1127d5518685232a12657a1d3fb7319b35 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 17:29:25 +0200 Subject: [PATCH 068/197] Config: Logging. --- meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java index f530ad3..ebd636a 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java @@ -27,10 +27,12 @@ import android.app.Activity; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import android.util.Log; public class Config { public static final int NO_USER_ID = 0; + private static final String TAG = "Config"; private SharedPreferences prefs; public String hostname = null; @@ -49,6 +51,7 @@ public Config(Activity activity) public void save() { + Log.d(TAG, "Saving config."); SharedPreferences.Editor edit = prefs.edit(); edit.putString("hostname", this.hostname); edit.putBoolean("multi_user_mode", this.multiUserMode); From 4485e94d57d1408861c90b29772ad6b9ea057499 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 17:33:22 +0200 Subject: [PATCH 069/197] Config: Add a version. --- .../java/de/chaosdorf/meteroid/util/Config.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java index ebd636a..68eb26b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java @@ -39,6 +39,7 @@ public class Config public boolean multiUserMode = false; public boolean useGridView = false; public int userID = NO_USER_ID; + private int version = 0; public Config(Activity activity) { @@ -47,6 +48,8 @@ public Config(Activity activity) multiUserMode = prefs.getBoolean("multi_user_mode", multiUserMode); useGridView = prefs.getBoolean("use_grid_view", useGridView); userID = prefs.getInt("userid", userID); + version = prefs.getInt("config_version", version); + migrate(); } public void save() @@ -57,6 +60,17 @@ public void save() edit.putBoolean("multi_user_mode", this.multiUserMode); edit.putBoolean("use_grid_view", this.useGridView); edit.putInt("userid", this.userID); + edit.putInt("config_version", this.version); edit.apply(); } + + private void migrate() + { + if(version == 0) + { + Log.d(TAG, "Migrating config from v0 to v1: Adding version."); + version = 1; + save(); + } + } } From 38e1915fc1bcb8c7e5cc4a76b8dbfe085924b81b Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 8 Oct 2017 20:53:59 +0200 Subject: [PATCH 070/197] Upgrade Gradle. --- gradle/wrapper/gradle-wrapper.properties | 3 +-- meteroid/build.gradle | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2deee66..3710617 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 17 17:57:55 CEST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 9f5851d..2f1ead6 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -27,7 +27,7 @@ buildscript { maven { url 'http://repo1.maven.org/maven2' } } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0' + classpath 'com.android.tools.build:gradle:2.3.0' } } apply plugin: 'com.android.application' From 262944f8872e50b94d7e78adbd2c514dbce8113d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 9 Oct 2017 12:08:49 +0200 Subject: [PATCH 071/197] Downgrade org.jetbrains:annotations. --- meteroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 2f1ead6..ed98f74 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -36,7 +36,7 @@ dependencies { repositories { maven { url 'http://repo1.maven.org/maven2' } } - compile 'org.jetbrains:annotations:15.0' + compile 'org.jetbrains:annotations:13.0' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.google.zxing:android-integration:3.3.0' From 5861a332d6872008e10d370421eb94164556d2e6 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 9 Oct 2017 12:35:15 +0200 Subject: [PATCH 072/197] Add (simple) databinding to SetHostname. --- .../de/chaosdorf/meteroid/SetHostname.java | 28 ++++----- .../main/res/layout/activity_set_hostname.xml | 60 ++++++++++--------- 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java index ef4f4ab..d36418c 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java @@ -26,6 +26,7 @@ import android.app.Activity; import android.app.ActionBar; +import android.databinding.DataBindingUtil; import android.os.Bundle; import android.os.Build; import android.text.Editable; @@ -34,9 +35,8 @@ import android.view.Menu; import android.view.MenuItem; import android.webkit.URLUtil; -import android.widget.Button; -import android.widget.EditText; +import de.chaosdorf.meteroid.databinding.ActivitySetHostnameBinding; import de.chaosdorf.meteroid.util.Config; import de.chaosdorf.meteroid.util.Utility; @@ -44,34 +44,31 @@ public class SetHostname extends Activity { private Activity activity = null; private Config config; - private EditText editText; - private Button saveButton; + private ActivitySetHostnameBinding binding; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); activity = this; - setContentView(R.layout.activity_set_hostname); + binding = DataBindingUtil.setContentView(this, R.layout.activity_set_hostname); config = new Config(this); - editText = (EditText) findViewById(R.id.hostname); - if (editText != null) + if (binding.hostname != null) { if (config.hostname != null) { - editText.setText(config.hostname); + binding.hostname.setText(config.hostname); } - final Editable editTextHostname = editText.getText(); + final Editable editTextHostname = binding.hostname.getText(); if (editTextHostname != null) { Selection.setSelection(editTextHostname, editTextHostname.length()); } } - saveButton = (Button) findViewById(R.id.button_save); - saveButton.setOnClickListener(new View.OnClickListener() + binding.buttonSave.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { @@ -84,7 +81,7 @@ public void onClick(View view) ActionBar actionBar = getActionBar(); if(actionBar != null) { - saveButton.setVisibility(View.GONE); + binding.buttonSave.setVisibility(View.GONE); } } } @@ -110,12 +107,7 @@ public boolean onCreateOptionsMenu(final Menu menu) public void saveHostname() { - if (editText == null) - { - Utility.displayToastMessage(activity, getResources().getString(R.string.set_hostname_empty)); - return; - } - final Editable editTextHostname = editText.getText(); + final Editable editTextHostname = binding.hostname.getText(); if (editTextHostname == null) { Utility.displayToastMessage(activity, getResources().getString(R.string.set_hostname_empty)); diff --git a/meteroid/src/main/res/layout/activity_set_hostname.xml b/meteroid/src/main/res/layout/activity_set_hostname.xml index bdbc37b..71308e6 100644 --- a/meteroid/src/main/res/layout/activity_set_hostname.xml +++ b/meteroid/src/main/res/layout/activity_set_hostname.xml @@ -24,35 +24,39 @@ ~ THE SOFTWARE. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - + - + - + - diff --git a/meteroid/src/main/res/menu-v11/pickusername.xml b/meteroid/src/main/res/menu-v11/pickusername.xml index 36610c1..321fa6c 100644 --- a/meteroid/src/main/res/menu-v11/pickusername.xml +++ b/meteroid/src/main/res/menu-v11/pickusername.xml @@ -45,4 +45,9 @@ android:checked="false" android:orderInCategory="100" android:showAsAction="never"/> + diff --git a/meteroid/src/main/res/menu-v21/buydrink.xml b/meteroid/src/main/res/menu-v21/buydrink.xml index 6ff1fe4..c4a77cf 100644 --- a/meteroid/src/main/res/menu-v21/buydrink.xml +++ b/meteroid/src/main/res/menu-v21/buydrink.xml @@ -57,4 +57,9 @@ android:checked="false" android:orderInCategory="100" android:showAsAction="never"/> + diff --git a/meteroid/src/main/res/menu-v21/pickusername.xml b/meteroid/src/main/res/menu-v21/pickusername.xml index 684392d..fd57f38 100644 --- a/meteroid/src/main/res/menu-v21/pickusername.xml +++ b/meteroid/src/main/res/menu-v21/pickusername.xml @@ -40,4 +40,9 @@ android:checked="false" android:orderInCategory="100" android:showAsAction="never"/> + diff --git a/meteroid/src/main/res/menu/buydrink.xml b/meteroid/src/main/res/menu/buydrink.xml index 59b03a0..1e0923b 100644 --- a/meteroid/src/main/res/menu/buydrink.xml +++ b/meteroid/src/main/res/menu/buydrink.xml @@ -47,4 +47,9 @@ android:checked="false" android:orderInCategory="100" android:showAsAction="never"/> + diff --git a/meteroid/src/main/res/menu/pickusername.xml b/meteroid/src/main/res/menu/pickusername.xml index 1f53035..97be422 100644 --- a/meteroid/src/main/res/menu/pickusername.xml +++ b/meteroid/src/main/res/menu/pickusername.xml @@ -40,4 +40,9 @@ android:checked="false" android:orderInCategory="100" android:showAsAction="never"/> + diff --git a/meteroid/src/main/res/values-de/strings.xml b/meteroid/src/main/res/values-de/strings.xml index 6569643..4d4901d 100644 --- a/meteroid/src/main/res/values-de/strings.xml +++ b/meteroid/src/main/res/values-de/strings.xml @@ -64,6 +64,9 @@ Ups, das hat nicht geklappt. Bitte Eingaben und Netzwerkverbindung überprüfen und erneut versuchen oder Hostname/Benutzername ändern um fortzufahren. Benutzer bearbeiten Diese Aktion ist ungültig. + + + Über… Zurück diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index 2ecfa51..fe47f10 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -65,6 +65,9 @@ Edit user This action is invalid. + + About + Back Reload From 253f4f6ca7d8991bfd6eac3861946111c21e8fc5 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 4 Feb 2019 17:28:27 +0100 Subject: [PATCH 134/197] About: Support going back by tapping the icon in the ActionBar. --- .../java/de/chaosdorf/meteroid/About.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/About.java b/meteroid/src/main/java/de/chaosdorf/meteroid/About.java index db59e8f..30320ac 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/About.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/About.java @@ -24,11 +24,15 @@ package de.chaosdorf.meteroid; +import android.app.ActionBar; import android.app.Activity; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.databinding.DataBindingUtil; +import android.os.Build; import android.os.Bundle; +import android.view.MenuItem; + import de.chaosdorf.meteroid.databinding.ActivityAboutBinding; @@ -42,6 +46,7 @@ protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_about); + String versionName = FALLBACK_VERSION_NAME; try { @@ -50,5 +55,26 @@ protected void onCreate(final Bundle savedInstanceState) } catch(NameNotFoundException ignored) {} binding.setVersionName(versionName); + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + { + ActionBar actionBar = getActionBar(); + if(actionBar != null) + { + actionBar.setDisplayHomeAsUpEnabled(true); + } + } + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) + { + switch (item.getItemId()) + { + case android.R.id.home: + finish(); + break; + } + return super.onOptionsItemSelected(item); } } From 45523df693d8b615b2c9e463fcd4d1e12c7d9a89 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 4 Feb 2019 17:28:47 +0100 Subject: [PATCH 135/197] About: Change fallback version name. --- meteroid/src/main/java/de/chaosdorf/meteroid/About.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/About.java b/meteroid/src/main/java/de/chaosdorf/meteroid/About.java index 30320ac..337b9a9 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/About.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/About.java @@ -39,7 +39,7 @@ public class About extends Activity { private ActivityAboutBinding binding; - private static final String FALLBACK_VERSION_NAME = "unknown"; + private static final String FALLBACK_VERSION_NAME = "UNKNOWN"; @Override protected void onCreate(final Bundle savedInstanceState) From a6629bbe74f5feb9bc3d7719d7d0bcd471ca9871 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Wed, 6 Feb 2019 21:19:06 +0100 Subject: [PATCH 136/197] About: Add a link to Github --- meteroid/src/main/res/layout/activity_about.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/meteroid/src/main/res/layout/activity_about.xml b/meteroid/src/main/res/layout/activity_about.xml index cba6c88..05d2b44 100644 --- a/meteroid/src/main/res/layout/activity_about.xml +++ b/meteroid/src/main/res/layout/activity_about.xml @@ -64,6 +64,14 @@ android:gravity="center" android:textSize="12sp" android:text="@{'v' + version_name}"/> + + From 470fd993e5b92de2c4c8dcf5af638baa61be6544 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 7 Feb 2019 14:16:32 +0100 Subject: [PATCH 137/197] MeteroidAdapter: Fix getPositionForSection to not throw an exception. --- .../java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java index cdd1178..913be30 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java @@ -90,6 +90,9 @@ public int getSectionForPosition(int position) { } public int getPositionForSection(int sectionIndex) { + if(sectionIndex >= sections.size()) { + return objects.size() - 1; + } return indexForSection.get(sections.get(sectionIndex)); } } \ No newline at end of file From 1c52ba9e683dc43bfcd6b081f7343ae3e7966ee2 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 8 Feb 2019 21:04:30 +0100 Subject: [PATCH 138/197] Give more space to drinks in grid view. --- .../main/res/layout/activity_buy_drink_item_gridview.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml b/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml index a9fa4a7..5cca9cf 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml @@ -27,8 +27,8 @@ @@ -40,6 +40,7 @@ android:layout_height="wrap_content" android:adjustViewBounds="true" android:layout_gravity="center_horizontal" + android:layout_weight="2" android:contentDescription="@string/app_name"/> From 36902c491458ebd9be67fa03a109809e7c51f269 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 9 Feb 2019 21:49:34 +0100 Subject: [PATCH 139/197] Don't show the checkbox for multi-user mode in BuyDrink. --- meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 4 ---- meteroid/src/main/res/menu-v11/buydrink.xml | 7 ------- meteroid/src/main/res/menu-v21/buydrink.xml | 7 ------- meteroid/src/main/res/menu/buydrink.xml | 7 ------- 4 files changed, 25 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index bef5df7..ed99242 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -351,10 +351,6 @@ public boolean onOptionsItemSelected(final MenuItem item) item.setChecked(config.useGridView); Utility.startActivity(this, BuyDrink.class); break; - case R.id.multi_user_mode: - Utility.toggleMultiUserMode(this); - item.setChecked(config.multiUserMode); - break; case R.id.about: Utility.startActivity(this, About.class); break; diff --git a/meteroid/src/main/res/menu-v11/buydrink.xml b/meteroid/src/main/res/menu-v11/buydrink.xml index c140d41..cf5375d 100644 --- a/meteroid/src/main/res/menu-v11/buydrink.xml +++ b/meteroid/src/main/res/menu-v11/buydrink.xml @@ -55,13 +55,6 @@ android:checked="false" android:orderInCategory="100" android:showAsAction="never"/> - - - Date: Sat, 9 Feb 2019 22:03:30 +0100 Subject: [PATCH 140/197] BuyDrink: Rework exit behavior. --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index ed99242..49b335a 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -103,9 +103,7 @@ protected void onCreate(final Bundle savedInstanceState) { public void onClick(View view) { - config.userID = config.NO_USER_ID; - config.save(); - Utility.startActivity(activity, PickUsername.class); + pickUsername(); } }); @@ -309,6 +307,20 @@ public void reload() new LongRunningIORequest(this, LongRunningIOTask.GET_USER, connection.getAPI().getUser(config.userID)); new LongRunningIORequest>(this, LongRunningIOTask.GET_DRINKS, connection.getAPI().listDrinks()); } + + private void pickUsername() + { + config.userID = config.NO_USER_ID; + config.save(); + if(config.multiUserMode) + { + finish(); + } + else + { + Utility.startActivity(this, PickUsername.class); + } + } @Override public boolean onCreateOptionsMenu(final Menu menu) @@ -325,9 +337,7 @@ public boolean onOptionsItemSelected(final MenuItem item) switch (item.getItemId()) { case android.R.id.home: - config.userID = config.NO_USER_ID; - config.save(); - Utility.startActivity(this, PickUsername.class); + pickUsername(); break; case R.id.action_reload: reload(); @@ -342,14 +352,19 @@ public boolean onOptionsItemSelected(final MenuItem item) Utility.startActivity(this, SetHostname.class); break; case R.id.reset_username: - config.userID = config.NO_USER_ID; - config.save(); - Utility.startActivity(this, PickUsername.class); + pickUsername(); break; case R.id.use_grid_view: Utility.toggleUseGridView(this); item.setChecked(config.useGridView); - Utility.startActivity(this, BuyDrink.class); + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + { + recreate(); + } + else + { + Utility.startActivity(this, BuyDrink.class); + } break; case R.id.about: Utility.startActivity(this, About.class); @@ -358,22 +373,6 @@ public boolean onOptionsItemSelected(final MenuItem item) return super.onOptionsItemSelected(item); } - @Override - public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) - { - if (keyCode == KeyEvent.KEYCODE_BACK) - { - if (config.multiUserMode) - { - config.userID = config.NO_USER_ID; - config.save(); - Utility.startActivity(this, MainActivity.class); - return true; - } - } - return super.onKeyDown(keyCode, event); - } - @Override public void onDestroy() { @@ -478,7 +477,7 @@ public void processIOResult(final LongRunningIOTask task, final Object result) } if (config.multiUserMode && user.getRedirect()) { - Utility.startActivity(this, PickUsername.class); + pickUsername(); break; } if(!buyableItem.getActive()) From ca1d20ce04f7c1f978eb44e1d4aed4ad622cf863 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 9 Feb 2019 22:10:48 +0100 Subject: [PATCH 141/197] Start with PickUsername if in multi-user mode. --- meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java index 6a8657d..3b7708d 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java @@ -44,7 +44,7 @@ protected void onCreate(final Bundle savedInstanceState) // Set hostname if not done yet Utility.startActivity(this, SetHostname.class); } - else if (config.userID == config.NO_USER_ID) + else if (config.multiUserMode || config.userID == config.NO_USER_ID) { // Pick username if not done yet Utility.startActivity(this, PickUsername.class); From 6c2cb77c5b8093c9886b57d63eb12f20f5b53656 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 9 Feb 2019 22:11:17 +0100 Subject: [PATCH 142/197] Finish MainActivity directly. --- meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java index 3b7708d..06c21a7 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/MainActivity.java @@ -54,5 +54,6 @@ else if (config.multiUserMode || config.userID == config.NO_USER_ID) // Ready to buy some drinks Utility.startActivity(this, BuyDrink.class); } + finish(); } } From fd1e24f1520bdba8f370d4aadbd077dbdd8cfee7 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 9 Feb 2019 22:19:34 +0100 Subject: [PATCH 143/197] PickUsername: Record successful loading. --- meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java | 1 + 1 file changed, 1 insertion(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 9075e53..7e30f11 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -213,6 +213,7 @@ public void processIOResult(final LongRunningIOTask task, final List resul if (task == LongRunningIOTask.GET_USERS) { final List itemList = result; + editHostnameOnBackButton = false; if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { itemList.add(new User(config.NO_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0, true, false, true)); From e1c6dbb278768111a2fd244e6c7c48fae6a58bd8 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 12:14:23 +0100 Subject: [PATCH 144/197] Get the LayoutInflater more easily. --- meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 2 +- meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 49b335a..693a979 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -544,7 +544,7 @@ private class BuyableItemAdapter extends MeteroidAdapter { super(activity, R.layout.activity_buy_drink, drinkList); this.drinkList = drinkList; - this.inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + this.inflater = activity.getLayoutInflater(); } public View getView(final int position, final View convertView, final ViewGroup parent) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 7e30f11..43d0cda 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -259,7 +259,7 @@ public class UserAdapter extends MeteroidAdapter { super(activity, R.layout.activity_pick_username, userList); this.userList = userList; - this.inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + this.inflater = activity.getLayoutInflater(); } From 25c123c6c3bb24e4bf44aefc6aa9396db9215048 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 12:22:41 +0100 Subject: [PATCH 145/197] Don't increase the padding in dialogs on tablets. --- meteroid/src/main/res/layout/activity_about.xml | 4 ++-- meteroid/src/main/res/layout/activity_set_hostname.xml | 4 ++-- meteroid/src/main/res/layout/activity_user_settings.xml | 4 ++-- meteroid/src/main/res/values/dimens.xml | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/meteroid/src/main/res/layout/activity_about.xml b/meteroid/src/main/res/layout/activity_about.xml index 05d2b44..f3fe01b 100644 --- a/meteroid/src/main/res/layout/activity_about.xml +++ b/meteroid/src/main/res/layout/activity_about.xml @@ -40,8 +40,8 @@ android:layout_height="fill_parent" android:orientation="vertical" android:gravity="center" - android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingLeft="@dimen/activity_horizontal_margin_dialog" + android:paddingRight="@dimen/activity_horizontal_margin_dialog" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".About"> diff --git a/meteroid/src/main/res/layout/activity_set_hostname.xml b/meteroid/src/main/res/layout/activity_set_hostname.xml index 71308e6..889a684 100644 --- a/meteroid/src/main/res/layout/activity_set_hostname.xml +++ b/meteroid/src/main/res/layout/activity_set_hostname.xml @@ -32,8 +32,8 @@ diff --git a/meteroid/src/main/res/layout/activity_user_settings.xml b/meteroid/src/main/res/layout/activity_user_settings.xml index 7c0a7b3..abdf48e 100644 --- a/meteroid/src/main/res/layout/activity_user_settings.xml +++ b/meteroid/src/main/res/layout/activity_user_settings.xml @@ -48,8 +48,8 @@ diff --git a/meteroid/src/main/res/values/dimens.xml b/meteroid/src/main/res/values/dimens.xml index 32a1e55..1dbe75f 100644 --- a/meteroid/src/main/res/values/dimens.xml +++ b/meteroid/src/main/res/values/dimens.xml @@ -25,5 +25,6 @@ 16dp + 16dp 16dp From d98764db49bb16234b3b7208368f79e63a9b2770 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 13:14:31 +0100 Subject: [PATCH 146/197] Hide the delete menu item in SetHostname. --- .../src/main/java/de/chaosdorf/meteroid/SetHostname.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java index d70ad53..3653b88 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java @@ -106,6 +106,15 @@ public boolean onOptionsItemSelected(final MenuItem item) public boolean onCreateOptionsMenu(final Menu menu) { getMenuInflater().inflate(R.menu.settings, menu); + + // the delete item doesn't make sense here + final MenuItem deleteItem = menu.findItem(R.id.action_delete); + if(deleteItem != null) + { + deleteItem.setVisible(false); + deleteItem.setEnabled(false); + } + return true; } From 174587053826430abe6944bc7533286d0b21a39b Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 13:21:05 +0100 Subject: [PATCH 147/197] Add class files to .gitignore. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c2d7006..f32f0c5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ local.properties build/ *~ -*.swp \ No newline at end of file +*.swp +*.class From 7518d13af5f66f5216976401a9e9573d4aec9858 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 13:28:57 +0100 Subject: [PATCH 148/197] Move res_raw to gfx --- .../src/main/res_raw => gfx}/button_barcode.eps | 0 .../src/main/res_raw => gfx}/button_barcode.png | Bin .../src/main/res_raw => gfx}/button_barcode.xcf | Bin .../src/main/res_raw => gfx}/ic_launcher-web.png | Bin 4 files changed, 0 insertions(+), 0 deletions(-) rename {meteroid/src/main/res_raw => gfx}/button_barcode.eps (100%) rename {meteroid/src/main/res_raw => gfx}/button_barcode.png (100%) rename {meteroid/src/main/res_raw => gfx}/button_barcode.xcf (100%) rename {meteroid/src/main/res_raw => gfx}/ic_launcher-web.png (100%) diff --git a/meteroid/src/main/res_raw/button_barcode.eps b/gfx/button_barcode.eps similarity index 100% rename from meteroid/src/main/res_raw/button_barcode.eps rename to gfx/button_barcode.eps diff --git a/meteroid/src/main/res_raw/button_barcode.png b/gfx/button_barcode.png similarity index 100% rename from meteroid/src/main/res_raw/button_barcode.png rename to gfx/button_barcode.png diff --git a/meteroid/src/main/res_raw/button_barcode.xcf b/gfx/button_barcode.xcf similarity index 100% rename from meteroid/src/main/res_raw/button_barcode.xcf rename to gfx/button_barcode.xcf diff --git a/meteroid/src/main/res_raw/ic_launcher-web.png b/gfx/ic_launcher-web.png similarity index 100% rename from meteroid/src/main/res_raw/ic_launcher-web.png rename to gfx/ic_launcher-web.png From b48e480b65407513ff124cc8805e86690535a7eb Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 15:01:43 +0100 Subject: [PATCH 149/197] Add an empty glass. --- gfx/empty_glass.png | Bin 0 -> 40284 bytes meteroid/src/main/AndroidManifest.xml | 1 + .../java/de/chaosdorf/meteroid/About.java | 33 ++++++++++++++++++ .../main/res/drawable-hdpi/empty_glass.png | Bin 0 -> 2252 bytes .../main/res/drawable-mdpi/empty_glass.png | Bin 0 -> 1414 bytes .../main/res/drawable-xhdpi/empty_glass.png | Bin 0 -> 3255 bytes .../main/res/drawable-xxhdpi/empty_glass.png | Bin 0 -> 5552 bytes .../src/main/res/layout/activity_about.xml | 10 ++++-- 8 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 gfx/empty_glass.png create mode 100644 meteroid/src/main/res/drawable-hdpi/empty_glass.png create mode 100644 meteroid/src/main/res/drawable-mdpi/empty_glass.png create mode 100644 meteroid/src/main/res/drawable-xhdpi/empty_glass.png create mode 100644 meteroid/src/main/res/drawable-xxhdpi/empty_glass.png diff --git a/gfx/empty_glass.png b/gfx/empty_glass.png new file mode 100644 index 0000000000000000000000000000000000000000..a8e5096f956e05a7fa92a61135b1fe98e51a3b74 GIT binary patch literal 40284 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

`xx9F40x%T4NtO-;BcNWqPVo!nw!* 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 literal 0 HcmV?d00001 diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 0109d9d..f11d706 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -33,6 +33,7 @@ android:targetSdkVersion="28"/> + = Build.VERSION_CODES.O) + { + vibrator.vibrate(VibrationEffect.createOneShot(VIBRATOR_DURATION, VibrationEffect.DEFAULT_AMPLITUDE)); + } + else + { + vibrator.vibrate(VIBRATOR_DURATION); + } + } + glassEmpty.set(!glassEmpty.get()); + return true; + } + }); } @Override diff --git a/meteroid/src/main/res/drawable-hdpi/empty_glass.png b/meteroid/src/main/res/drawable-hdpi/empty_glass.png new file mode 100644 index 0000000000000000000000000000000000000000..3e05584c8c8107c4745b74da449a896d5d72424b GIT binary patch literal 2252 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 Y4v7B$h9Z4R7~cR`qwP`E=Lre_1CpZ>egFUf literal 0 HcmV?d00001 diff --git a/meteroid/src/main/res/drawable-mdpi/empty_glass.png b/meteroid/src/main/res/drawable-mdpi/empty_glass.png new file mode 100644 index 0000000000000000000000000000000000000000..963d092b58cc5345de0c675e2d7e720f3b55a9db GIT binary patch literal 1414 zcmV;11$p|3P){un1D6Gx7#0{4goptOa**Yf47SG%?FT{tE;OM zlAn>R0616Gd#ZZhT6+edtg0md$Etdmska1RFWI-rW&lh{M#=AlWRPrql05)jRs9RV zAN6|uCbt5$T8#j{0`QHs_H%3Pp|$ovRrghOuUszk^=s#pUHCE-x=}adCnB4<6{f(^IqL-drUNL&x`h$Md|S*RNlr)oOj} z`+i+S#`SvrySwgrZzEJy!!R_DA3t^~mCFBAQ`MClpV=@Ll}ZJbN(B!eK13YH zXfzt=^?L915m``QO!B7PZqIXVrMENnWGmF{ei(*2nM?rSm$d;BJM_BU?%ZK+C;a_a z59fUH?fz^w<9IxVi2RmU0k6~Pyszih>h1aa?%JO}c6)n^*=#le5IuSF1Z(*KfM^at zRh1i<%2J5*SgKB^(}9S1sv6%Fffg#@y6#LwJm2>VA6-+hZnq1P9?3Y52|+~K!{JcZ z8T7X4ADvDIBt2D)asdFi0TB0ky$>?a@qHg6l3xJ;Z4rr*NTfvrq(0!fuE`7Fk(?y} zEVA*|T1+MrOR~Mt%$GQmM>3iZrA3r(w+j)80eHCq>h*e?WIQ*R6$X&letv)?65W1? zP?|)bC^tZ65*GvkRQ30{0X08>sy0){TD75hJw6k%n{xx|Mhdi2 zyWCbomnlH9xytpc0`$W$L>PuUxBpauRUCL7Cyq(BlNsX96PZMT);0km0A3M!LB$whmy7@piq)l`Q5iT}sIX@Z!abNJPRnZ{DQo z-aFg6JwAW$%a<=9BC~ZASm~+h+wxki_O+_kRrR=9t)g13;{5y^XJ=<9m&-UlK87Uk zhO-ULrlQtbOs7+f$72iz1Ngp=>+5T@S}jbc)2ZV)Ke?{^XsZBo5MQe5BV)`L*4nD7 zo~!C70Pd;kzT-G>k{8`6h^nS3V!B*n0R$umBs(PkbR4HCB0syX`$P75TLsAG$yZlb z2O@F^-~fPwf8VzefMcy?^8LhK0$@lQ07^3b?7#w;CGkEgl}dj_ UwtBE=C;$Ke07*qoM6N<$g8sRL6951J literal 0 HcmV?d00001 diff --git a/meteroid/src/main/res/drawable-xhdpi/empty_glass.png b/meteroid/src/main/res/drawable-xhdpi/empty_glass.png new file mode 100644 index 0000000000000000000000000000000000000000..1367ce498f951afd9a2ec976edf9ede93c2243c1 GIT binary patch literal 3255 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 literal 0 HcmV?d00001 diff --git a/meteroid/src/main/res/drawable-xxhdpi/empty_glass.png b/meteroid/src/main/res/drawable-xxhdpi/empty_glass.png new file mode 100644 index 0000000000000000000000000000000000000000..b17df417964f941bd5ec7e0be5f3bb57b6475033 GIT binary patch literal 5552 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 + - + android:longClickable="true" + android:src="@{glass_empty ? @drawable/empty_glass : @drawable/ic_launcher}"/> Date: Sun, 10 Feb 2019 17:14:27 +0100 Subject: [PATCH 150/197] BuyDrink: Always finish when going to PickUsername. --- .../src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 693a979..8141bb2 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -312,14 +312,11 @@ private void pickUsername() { config.userID = config.NO_USER_ID; config.save(); - if(config.multiUserMode) + if(!config.multiUserMode) { - finish(); - } - else - { - Utility.startActivity(this, PickUsername.class); + Utility.startActivity(this, PickUsername.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); } + finish(); } @Override From 7c100721a9be3ca5b33f1a1ec36b804dd251ef64 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 17:21:10 +0100 Subject: [PATCH 151/197] Utility: Add flags to startActivity. --- .../src/main/java/de/chaosdorf/meteroid/util/Utility.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index 84a5f5b..e31e5f9 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -65,8 +65,14 @@ public static void displayToastMessage(final Activity activity, final String mes } public static void startActivity(final Activity activity, Class classType) + { + startActivity(activity, classType, 0); + } + + public static void startActivity(final Activity activity, Class classType, int flags) { final Intent intent = new Intent(activity, classType); + intent.addFlags(flags); activity.startActivity(intent); } From 006222b002af37d82c6734678ad7493dc28dc216 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 10 Feb 2019 17:21:21 +0100 Subject: [PATCH 152/197] UserSettings: Always finish. --- .../de/chaosdorf/meteroid/UserSettings.java | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 4218a80..62c702c 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -71,7 +71,7 @@ protected void onCreate(final Bundle savedInstanceState) { public void onClick(View view) { - goBack(); + finish(); } }); @@ -130,7 +130,7 @@ public boolean onOptionsItemSelected(final MenuItem item) switch (item.getItemId()) { case android.R.id.home: - goBack(); + finish(); break; case R.id.action_save: saveUser(); @@ -157,7 +157,7 @@ public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - goBack(); + finish(); return true; } return super.onKeyDown(keyCode, event); @@ -181,18 +181,6 @@ private void makeWritable() } catch(NoSuchMethodError err) {} // workaround for 2.3.3 } - private void goBack() - { - if(config.userID == config.NO_USER_ID) //new user - { - Utility.startActivity(this, PickUsername.class); - } - else - { - Utility.startActivity(this, BuyDrink.class); - } - } - private void deleteUser() { if(config.userID == config.NO_USER_ID) //new user @@ -228,7 +216,8 @@ public void processIOResult(LongRunningIOTask task, Void result) config.save(); makeWritable(); Utility.displayToastMessage(userSettings, getResources().getString(R.string.user_settings_deleted_user)); - Utility.startActivity(userSettings, PickUsername.class); + Utility.startActivity(userSettings, PickUsername.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); + finish(); } }, LongRunningIOTask.DELETE_USER, @@ -283,7 +272,8 @@ public void displayErrorMessage(LongRunningIOTask task, String message) @Override public void processIOResult(LongRunningIOTask task, User result) { - Utility.startActivity(userSettings, PickUsername.class); + Utility.startActivity(userSettings, PickUsername.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); + finish(); } }, LongRunningIOTask.ADD_USER, @@ -302,7 +292,8 @@ public void displayErrorMessage(LongRunningIOTask task, String message) @Override public void processIOResult(LongRunningIOTask task, Void result) { - Utility.startActivity(userSettings, BuyDrink.class); + Utility.startActivity(userSettings, BuyDrink.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); + finish(); } }, LongRunningIOTask.EDIT_USER, From 26856e99c70d9ea9eb6626965d958240cf205a14 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Wed, 13 Feb 2019 11:41:09 +0100 Subject: [PATCH 153/197] Use SpotBugs. --- meteroid/build.gradle | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 1aff511..d736312 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -25,12 +25,17 @@ buildscript { repositories { mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { classpath 'com.android.tools.build:gradle:2.3.0' + classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.9" } } apply plugin: 'com.android.application' +apply plugin: "com.github.spotbugs" dependencies { repositories { @@ -66,3 +71,22 @@ android { enabled = true } } + + +// see https://stackoverflow.com/a/52718914/2192464 +sourceSets { + main { + java.srcDirs = [] + } +} +tasks.withType(com.github.spotbugs.SpotBugsTask) { + dependsOn 'assembleDebug' + classes = files("$projectDir.absolutePath/build/intermediates/classes/debug") + source = fileTree('src/main/java') +} +spotbugs { + toolVersion = "3.1.3" + ignoreFailures = true + effort = "max" + reportLevel = "high" +} From 3fcce6f23f6306bbea4bc797b22f547c7e376899 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 24 May 2019 17:28:33 +0200 Subject: [PATCH 154/197] Picasso: Use placeholder instead of error. In this case, users don't get to see missing avatars. --- meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index e31e5f9..f8d1755 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -126,7 +126,7 @@ private static void loadGravatarImage(final Activity activity, final ImageView i .appendPath(md5Hex(email)) .appendQueryParameter("d", "404") .build(); - Picasso.with(activity).load(uri).error(R.drawable.default_user).into(icon); + Picasso.with(activity).load(uri).placeholder(R.drawable.default_user).into(icon); } else { From 16da88483f06107d60bb78dab97812343d49b5cf Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 24 May 2019 17:32:33 +0200 Subject: [PATCH 155/197] Change default URL. This is now specific to Chaosdorf, but this is arguably the most popular instance. --- meteroid/src/main/res/values-de/strings.xml | 2 +- meteroid/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/res/values-de/strings.xml b/meteroid/src/main/res/values-de/strings.xml index 4d4901d..184f427 100644 --- a/meteroid/src/main/res/values-de/strings.xml +++ b/meteroid/src/main/res/values-de/strings.xml @@ -31,7 +31,7 @@ Hostname - http://mete + https://mete.chaosdorf.space/api/v1 Bitte URL von mete eingeben Bitte einen Hostnamen eingeben Ungültiger Hostname eingegeben diff --git a/meteroid/src/main/res/values/strings.xml b/meteroid/src/main/res/values/strings.xml index fe47f10..22efc7d 100644 --- a/meteroid/src/main/res/values/strings.xml +++ b/meteroid/src/main/res/values/strings.xml @@ -31,7 +31,7 @@ Hostname - http://mete + https://mete.chaosdorf.space/api/v1 Please enter the URL of mete Please enter a hostname Invalid hostname entered From ec8d198c14ed76e3a5f4c62a7e9f9c2832552aae Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 24 May 2019 17:42:19 +0200 Subject: [PATCH 156/197] Bump version to 2.6.0. --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index f11d706..5bccffd 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="32" + android:versionName="2.6.0"> Date: Thu, 11 Jul 2019 18:17:15 +0200 Subject: [PATCH 157/197] MeteroidAdapter: Fix getPositionForSection to not throw an exception. This is related to 470fd99 and #19. --- .../java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java index 913be30..7e071ba 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/controller/MeteroidAdapter.java @@ -93,6 +93,9 @@ public int getPositionForSection(int sectionIndex) { if(sectionIndex >= sections.size()) { return objects.size() - 1; } + if(sectionIndex < 0) { + return 0; + } return indexForSection.get(sections.get(sectionIndex)); } } \ No newline at end of file From 840e703d2b503d159f7867ce042886aa7a411079 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 20 Oct 2019 16:47:10 +0200 Subject: [PATCH 158/197] Update Retrofit The new version doesn't officially support Android < 5 anymore, but it still seems to work on Android 2.3.3. --- meteroid/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index d736312..eaa9463 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -42,8 +42,8 @@ dependencies { mavenCentral() } compile 'org.jetbrains:annotations:13.0' - compile 'com.squareup.retrofit2:retrofit:2.5.0' - compile 'com.squareup.retrofit2:converter-gson:2.5.0' + compile 'com.squareup.retrofit2:retrofit:2.6.2' + compile 'com.squareup.retrofit2:converter-gson:2.6.2' compile 'com.google.zxing:android-integration:3.3.0' compile 'com.melnykov:floatingactionbutton:1.3.0' compile 'com.android.support:support-v4:22.1.1@aar' From d80027ea6af80942c404038100b43fa98fa88a20 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 20 Oct 2019 17:23:52 +0200 Subject: [PATCH 159/197] Update SDK, build tools and target SDK version to Android 10 --- meteroid/build.gradle | 4 ++-- meteroid/src/main/AndroidManifest.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index eaa9463..e6811fb 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -59,8 +59,8 @@ gradle.projectsEvaluated { } android { - compileSdkVersion 28 - buildToolsVersion '28.0.3' + compileSdkVersion 29 + buildToolsVersion '29.0.2' signingConfigs {} lintOptions { abortOnError false diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 5bccffd..e4efb27 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -30,7 +30,7 @@ + android:targetSdkVersion="29"/> From 3283cd0f59009d8c335da76e7caa6a44c27feb46 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 20 Oct 2019 17:28:26 +0200 Subject: [PATCH 160/197] Bump version to 2.6.1 --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index e4efb27..25bfff2 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="33" + android:versionName="2.6.1"> Date: Sun, 20 Oct 2019 18:43:11 +0200 Subject: [PATCH 161/197] Fix Travis config d80027ea introduced new a Android SDK and build tools. Travis needs to have those installed. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 25f4d12..dbb0429 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,5 @@ android: components: - platform-tools - tools - - build-tools-28.0.3 - - android-28 + - build-tools-29.0.2 + - android-29 From 1a6a2c5d64caa46e3c77e3bc3992dafb541604d7 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 2 Apr 2020 18:03:49 +0200 Subject: [PATCH 162/197] Show multiple dynamic shortcuts at the same time (closes #24) --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 8141bb2..ab3eb61 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -253,8 +253,7 @@ private void buy(BuyableItem buyableItem) if(shortcutManager != null) { - ShortcutInfo shortcut = shortcutForItem(buyableItem); - shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut)); + updateShortcuts(shortcutForItem(buyableItem)); } } @@ -269,7 +268,7 @@ private void scanBarcode() .setIcon(Icon.createWithResource(this, R.drawable.button_barcode)) .setIntent(intent) .build(); - shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut)); + updateShortcuts(shortcut); } barcodeIntegrator.initiateScan(); } @@ -298,6 +297,35 @@ private ShortcutInfo shortcutForItem(BuyableItem item) .build(); } + /** + * Updates the dynamic shortcuts. + * If a shortcut with this ID does not yet exist, it is added and some other one is removed. + * If a shortcut with this ID does already exist, nothing happens. + */ + private void updateShortcuts(ShortcutInfo shortcut) { + List shortcuts = shortcutManager.getDynamicShortcuts(); + for(ShortcutInfo current : shortcuts) { + if(current.getId().equals(shortcut.getId())) { + // nothing to do here + return; + } + } + + // Do we have enough space to add another one? + // getMaxShortcutCountPerActivity gives us the upper bound of how many shortcuts we can set. + // But not every launcher can display as much. WTF. + // At least the AOSP launcher can display 4. Let's hope that others can do the same. + int maxShortcuts = Math.min(shortcutManager.getMaxShortcutCountPerActivity(), 4); + if(shortcuts.size() >= maxShortcuts) { + // if not, we have to remove one first + // pick the last one per default - it's the one we put there the first, I think + String idToRemove = shortcuts.get(shortcuts.size() - 1).getId(); + shortcutManager.removeDynamicShortcuts(Arrays.asList(idToRemove)); + } + // then add our new one + shortcutManager.addDynamicShortcuts(Arrays.asList(shortcut)); + } + public void reload() { binding.gridView.setVisibility(View.GONE); From 5f40b0edf88fbfd09a09a9e00da777c1d7949f50 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 2 Apr 2020 18:08:01 +0200 Subject: [PATCH 163/197] Notify the system which shortcut has been used Also, send similar events. This should reorder the launcher's shortcut list. --- meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index ab3eb61..0de4e5b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -253,7 +253,9 @@ private void buy(BuyableItem buyableItem) if(shortcutManager != null) { - updateShortcuts(shortcutForItem(buyableItem)); + ShortcutInfo shortcut = shortcutForItem(buyableItem); + updateShortcuts(shortcut); + shortcutManager.reportShortcutUsed(shortcut.getId()); } } @@ -269,6 +271,7 @@ private void scanBarcode() .setIntent(intent) .build(); updateShortcuts(shortcut); + shortcutManager.reportShortcutUsed(shortcut.getId()); } barcodeIntegrator.initiateScan(); } From dab8260411ac33b9647aef0239db5e3f5607c631 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 15:12:59 +0200 Subject: [PATCH 164/197] Update dependencies where possible --- meteroid/build.gradle | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index e6811fb..8405547 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -31,6 +31,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:2.3.0' + // SpotBugs plugin >= 1.7 needs Gradle 5.0+ classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.9" } } @@ -42,8 +43,9 @@ dependencies { mavenCentral() } compile 'org.jetbrains:annotations:13.0' - compile 'com.squareup.retrofit2:retrofit:2.6.2' - compile 'com.squareup.retrofit2:converter-gson:2.6.2' + // Retrofit >= 2.7 needs Android 5+ + compile 'com.squareup.retrofit2:retrofit:2.6.4' + compile 'com.squareup.retrofit2:converter-gson:2.6.4' compile 'com.google.zxing:android-integration:3.3.0' compile 'com.melnykov:floatingactionbutton:1.3.0' compile 'com.android.support:support-v4:22.1.1@aar' @@ -85,7 +87,7 @@ tasks.withType(com.github.spotbugs.SpotBugsTask) { source = fileTree('src/main/java') } spotbugs { - toolVersion = "3.1.3" + toolVersion = "4.0.1" ignoreFailures = true effort = "max" reportLevel = "high" From e1731e76336bf3e3ae70721d89d9b1a6c78e6b30 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 15:23:52 +0200 Subject: [PATCH 165/197] util: Make singletons volatile --- meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java | 2 +- .../src/main/java/de/chaosdorf/meteroid/util/Connection.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java index 88f8d59..04b87dd 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Config.java @@ -42,7 +42,7 @@ public class Config public int userID = NO_USER_ID; private int version = 0; - private static Config instance; + private static volatile Config instance; private Config(Context context) { diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Connection.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Connection.java index c22194f..4ecdc1f 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Connection.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Connection.java @@ -42,7 +42,7 @@ public class Connection private Config config; private API api; - private static Connection instance; + private static volatile Connection instance; private Connection(Config config) { From ac9b1ebe5719df9690249a01fa762c9ea1e27387 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 15:24:15 +0200 Subject: [PATCH 166/197] Don't duplicate code in a switch-case --- .../src/main/java/de/chaosdorf/meteroid/PickUsername.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 43d0cda..f5e453b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -146,15 +146,13 @@ public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { - case android.R.id.home: - Utility.startActivity(this, SetHostname.class); - break; case R.id.action_reload: reload(); break; case R.id.action_add: Utility.startActivity(this, UserSettings.class); break; + case android.R.id.home: case R.id.edit_hostname: Utility.startActivity(this, SetHostname.class); break; From f6e671b7edbc4944b30beade306a0fb49ea12595 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 15:50:30 +0200 Subject: [PATCH 167/197] Disable shortcuts when deselecting user and reenable them when possible --- .../java/de/chaosdorf/meteroid/BuyDrink.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index 0de4e5b..a53c495 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -50,6 +50,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -159,6 +160,14 @@ public void onClick(View view) if(!config.multiUserMode) { shortcutManager = getSystemService(ShortcutManager.class); + // make sure all pinned shortcuts are enabled as we have a current user + List shortcuts = shortcutManager.getPinnedShortcuts(); + // if this were Java 8 I could use a stream :( + List shortcutIDs = new ArrayList<>(); + for(ShortcutInfo shortcut : shortcuts) { + shortcutIDs.add(shortcut.getId()); + } + shortcutManager.enableShortcuts(shortcutIDs); } } @@ -343,6 +352,19 @@ private void pickUsername() { config.userID = config.NO_USER_ID; config.save(); + if(shortcutManager != null) { + // if we have no user, we can't buy drinks + // removing dynamic shortcuts is easy + shortcutManager.removeAllDynamicShortcuts(); + // but if the user pinned them, that's going to be a bit more difficult + List shortcuts = shortcutManager.getPinnedShortcuts(); + // if this were Java 8 I could use a stream :( + List shortcutIDs = new ArrayList<>(); + for(ShortcutInfo shortcut : shortcuts) { + shortcutIDs.add(shortcut.getId()); + } + shortcutManager.disableShortcuts(shortcutIDs); + } if(!config.multiUserMode) { Utility.startActivity(this, PickUsername.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); From 78537d9acadb6753c4b554bbb77195f25fcc0b42 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 15:53:27 +0200 Subject: [PATCH 168/197] Bump version to 2.7.0 --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 25bfff2..269e167 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="34" + android:versionName="2.7.0"> Date: Fri, 3 Apr 2020 17:03:01 +0200 Subject: [PATCH 169/197] Replace com.melnykov.fab.FloatingActionButton with com.shamanland.fab.FloatingActionButton --- meteroid/build.gradle | 2 +- .../src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 8 ++++---- .../src/main/java/de/chaosdorf/meteroid/PickUsername.java | 7 +++---- meteroid/src/main/res/layout/activity_buy_drink.xml | 2 +- meteroid/src/main/res/layout/activity_pick_username.xml | 2 +- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 8405547..6d21d77 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -47,7 +47,7 @@ dependencies { compile 'com.squareup.retrofit2:retrofit:2.6.4' compile 'com.squareup.retrofit2:converter-gson:2.6.4' compile 'com.google.zxing:android-integration:3.3.0' - compile 'com.melnykov:floatingactionbutton:1.3.0' + compile 'com.shamanland:fab:0.0.8' compile 'com.android.support:support-v4:22.1.1@aar' compile 'com.squareup.picasso:picasso:2.5.2' } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index a53c495..c3086f6 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -45,7 +45,8 @@ import android.widget.ImageView; import android.widget.TextView; -import com.melnykov.fab.FloatingActionButton; +import com.shamanland.fab.FloatingActionButton; +import com.shamanland.fab.ShowHideOnScroll; import org.jetbrains.annotations.NotNull; @@ -144,7 +145,6 @@ public void onClick(View view) if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - binding.fab.hide(false); binding.fab.setOnClickListener(new View.OnClickListener() { public void onClick(View view) @@ -499,8 +499,8 @@ public void processIOResult(final LongRunningIOTask task, final Object result) binding.progressBar.setVisibility(View.GONE); if(binding.fab != null) { - binding.fab.attachToListView(config.useGridView? binding.gridView : binding.listView); - binding.fab.show(); + (config.useGridView? binding.gridView : binding.listView) + .setOnTouchListener(new ShowHideOnScroll(binding.fab)); } handleIntent(buyableItemList); break; diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index f5e453b..0b0371c 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -42,7 +42,8 @@ import android.support.v4.widget.SwipeRefreshLayout; -import com.melnykov.fab.FloatingActionButton; +import com.shamanland.fab.FloatingActionButton; +import com.shamanland.fab.ShowHideOnScroll; import org.jetbrains.annotations.NotNull; @@ -105,8 +106,7 @@ public void onRefresh() reload(); } }); - binding.fab.hide(false); - binding.fab.attachToListView(binding.gridView); + binding.gridView.setOnTouchListener(new ShowHideOnScroll(binding.fab)); binding.fab.setOnClickListener(new View.OnClickListener() { public void onClick(View view) @@ -115,7 +115,6 @@ public void onClick(View view) } }); binding.fab.setVisibility(View.VISIBLE); - binding.fab.show(); } reload(); diff --git a/meteroid/src/main/res/layout/activity_buy_drink.xml b/meteroid/src/main/res/layout/activity_buy_drink.xml index eff1955..5ae4f9a 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink.xml @@ -172,7 +172,7 @@ android:drawSelectorOnTop="false"/> - - Date: Fri, 3 Apr 2020 17:06:36 +0200 Subject: [PATCH 170/197] Don't specify version of the Android support library --- meteroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 6d21d77..87cafce 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -48,7 +48,7 @@ dependencies { compile 'com.squareup.retrofit2:converter-gson:2.6.4' compile 'com.google.zxing:android-integration:3.3.0' compile 'com.shamanland:fab:0.0.8' - compile 'com.android.support:support-v4:22.1.1@aar' + // com.android.support:support-v4 is being pulled in by the databinding compile 'com.squareup.picasso:picasso:2.5.2' } From faec748c070fe2f33af8fe45fa9d9fffacdee7e7 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 17:21:16 +0200 Subject: [PATCH 171/197] Update Android Gradle plugin to 3.3.2 (closes #22) This is the latest one that works with our Gradle version. Also, this forces us to drop support for all Android versions earlier than API 14 aka. Ice Cream Sandwhich aka. version 4.0. --- meteroid/build.gradle | 6 ++++-- meteroid/src/main/AndroidManifest.xml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 87cafce..95fbc65 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -28,9 +28,10 @@ buildscript { maven { url "https://plugins.gradle.org/m2/" } + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:3.3.2' // SpotBugs plugin >= 1.7 needs Gradle 5.0+ classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.9" } @@ -41,6 +42,7 @@ apply plugin: "com.github.spotbugs" dependencies { repositories { mavenCentral() + google() } compile 'org.jetbrains:annotations:13.0' // Retrofit >= 2.7 needs Android 5+ @@ -48,7 +50,7 @@ dependencies { compile 'com.squareup.retrofit2:converter-gson:2.6.4' compile 'com.google.zxing:android-integration:3.3.0' compile 'com.shamanland:fab:0.0.8' - // com.android.support:support-v4 is being pulled in by the databinding + compile 'com.android.support:support-core-ui:26.1.0' compile 'com.squareup.picasso:picasso:2.5.2' } diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 269e167..f7f0696 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -29,7 +29,7 @@ android:versionName="2.7.0"> From 09965c35608ae04de4c414ec32c881e1f9303eee Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 17:25:21 +0200 Subject: [PATCH 172/197] Update Gradle and wrapper to 5.6.4 --- gradle/wrapper/gradle-wrapper.jar | Bin 56177 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 22 +++++++++++++++++++--- gradlew.bat | 18 +++++++++++++++++- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 94336fcae912db8a11d55634156fa011f4686124..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch delta 47360 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 delta 47987 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 P{tQ5B1&<&s7});<9qHf~ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 290541c..5028f28 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d..83f2acf 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -109,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` diff --git a/gradlew.bat b/gradlew.bat index e95643d..24467a1 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome From 72edff54d1ac0cbdb5774e823deab7f971de0b40 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 17:28:33 +0200 Subject: [PATCH 173/197] build.gradle: Replace compile with implementation --- meteroid/build.gradle | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 95fbc65..332378a 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -44,14 +44,14 @@ dependencies { mavenCentral() google() } - compile 'org.jetbrains:annotations:13.0' + implementation 'org.jetbrains:annotations:13.0' // Retrofit >= 2.7 needs Android 5+ - compile 'com.squareup.retrofit2:retrofit:2.6.4' - compile 'com.squareup.retrofit2:converter-gson:2.6.4' - compile 'com.google.zxing:android-integration:3.3.0' - compile 'com.shamanland:fab:0.0.8' - compile 'com.android.support:support-core-ui:26.1.0' - compile 'com.squareup.picasso:picasso:2.5.2' + implementation 'com.squareup.retrofit2:retrofit:2.6.4' + implementation 'com.squareup.retrofit2:converter-gson:2.6.4' + implementation 'com.google.zxing:android-integration:3.3.0' + implementation 'com.shamanland:fab:0.0.8' + implementation 'com.android.support:support-core-ui:26.1.0' + implementation 'com.squareup.picasso:picasso:2.5.2' } //see https://stackoverflow.com/a/22183825/2192464 From 82d242960bd1381f1034e5318a44efe8526016f0 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 17:47:36 +0200 Subject: [PATCH 174/197] Adjust path for SpotBugs --- meteroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 332378a..5b798e9 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -85,7 +85,7 @@ sourceSets { } tasks.withType(com.github.spotbugs.SpotBugsTask) { dependsOn 'assembleDebug' - classes = files("$projectDir.absolutePath/build/intermediates/classes/debug") + classes = files("$projectDir.absolutePath/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/") source = fileTree('src/main/java') } spotbugs { From 783d7f35ae246f07e22223cc8478f27e6f902eea Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 17:49:33 +0200 Subject: [PATCH 175/197] Update Android Gradle plugin to 3.6.2 --- meteroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 5b798e9..a3e8748 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -31,7 +31,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.6.2' // SpotBugs plugin >= 1.7 needs Gradle 5.0+ classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.9" } From 45a5159a4b409b2e32f0f3c74e5230299714df32 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 17:52:34 +0200 Subject: [PATCH 176/197] Update Gradle SpotBugs plugin to 3.0.0 --- meteroid/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index a3e8748..7a2954c 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -32,8 +32,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.6.2' - // SpotBugs plugin >= 1.7 needs Gradle 5.0+ - classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.9" + classpath 'com.github.spotbugs:spotbugs-gradle-plugin:3.0.0' } } apply plugin: 'com.android.application' From 9883fac64a91ddc732b3d6f3d77509497b7f8138 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 18:02:24 +0200 Subject: [PATCH 177/197] Move from AndroidManifest.xml to build.gradle --- meteroid/build.gradle | 4 ++++ meteroid/src/main/AndroidManifest.xml | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 7a2954c..a25ca81 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -73,6 +73,10 @@ android { dataBinding { enabled = true } + defaultConfig { + targetSdkVersion 29 + minSdkVersion 14 + } } diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index f7f0696..2cc39e6 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -28,10 +28,6 @@ android:versionCode="34" android:versionName="2.7.0"> - - From cb0d49213bf538affd3d78d8492b47600e5e4130 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 18:03:00 +0200 Subject: [PATCH 178/197] Upgrade Gradle and wrapper to 6.3 Also, adjust path for SpotBugs. --- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 58694 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 29 ++++++++++------------- gradlew.bat | 3 +++ meteroid/build.gradle | 3 ++- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..490fda8577df6c95960ba7077c43220e5bb2c0d9 100644 GIT binary patch delta 22806 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 Z!$zsDgoO%|(a?lZ=Qe6kxv{^r{{!uYR<-~D delta 19980 zcmV)OK(@ce$^*c%1F$Or3aZ&=*aHOs0O|>ov1S>QP5~5uE@NzAb90SWTUQfT6#kBx zWMCWxV?cw7gEtZ`iM7^Nu(V3OAOS4_Y((1*$svqRX41*TOYawZ{Rh7GrB7X}eF?O# z+SS+oi~fr~Y4@4QKoWwhEY_Jb`|R8I?S1y-?`OY11#k*KD2U>Mf&om*cuU4b1--bW z;4-c#n8H#IL49*ZaXIO?i!4OI$7a62UyFk*ejA8NFYH67} z^ZK$$l4!=x>*k{F7~;Jyl-yOL!jR0^PBC3{^n%HM)At>{T;@*tf^EAMmtJOc!^*n4 z<8o)5AzTq#hGU7P%pLuno;G!>n9jP6VHL-HiD9QN873e1^3k0lMcCU$nL+VGUa?D* z%kE}lhED(Vs_szsdE0XN19#HYE0v6`7dQ#yzJ z`3!e|SM35rUxR|fS4^IF)BYK0_BIpuupE#VYjt~WXoB>25m))UGkV!mld(dKa+bBLPM!-nQP8eRDPgPP2#%^a zhu0bQZNn3T+IXVEz#SQPRhTHruvFM6tN1{FEJxtTsHkvJRdEmZDP`)JlwYEhS;vyP z?7fRzR6M{#%3JVEh+C*q@gY89=-w1xTfRfItN0k7P{jiDlcrtaf=3mf;%Ja>ofhhO z(^wX{eWv1be4*k?d_`#eq(+0JMpHw#h!V>Gk&3VJ4b^)y>|E7yjS}A|5W~euyJ{AH zG|P51lPd3W&0Xc14@?VuYFE$CX@(Vu3kKD|Sgr~W+TiiZU`oZe_)etuJ;UJtyj=|Y zx9dZ?L7PVn$#yNZHcHsF7v`pj+C;MPdQ6Qs7kjF%nc1S5A4<*SZx6uifp!unE?e1*G{ zZN^1k;sxP4P1@Jz#qq?}VYLNd9a>PHH`~}OZLvwdXwXCq>z;j=y83LRFaKUN`KpVO zTSZjVytpw8M_UF;8$=#zYFu$Hreq?yrI}57nl$DVdP z-Xx$awnIuSK--Yk2IxlQw$2ynlRQA*X7LvS6C;q;WAv7$C!=S0XbtRF+U&q_S|grt zKTgo9`U)6Cf}Yf^7$Pk)W&@-rlZ+3ItYOFO6NGZoACPjP(Hg=vM6&CUYv@=*=a{q( zB`(#lGcHBd8g`9^d?7Cuko71BCWr@}vbmCjxxNk7@^l z_X{xQWz8^7k?5OKXZ>f&DnifcC+N)$NB6B^e+}`Ok*5=(Gg6Oq=tmqL>5)zel4|IS z9;o5qV?^TNUmi*9r|17X!J%BVKj3N|hu5I}>6KQ{(@Uudk~9K6O0ZAT{tUqubZDfb zp&JtfSZGae5Hs!3!8}kCyAgVZn2a|VJMb^*(KYruf+Eo@!3SXXUDH*qIQd4(bSlb8WNLgNKg{P)6h=ZHOo#jom%>jOwdGMglOUq z@JAW%l!6U3MfYK6=H7G8J$G*A*YEE?0o=!92NRfe;9}OsTnh6JZek&Y#T1sz_LhTX z+;)(FZ)3&A9ft8|VI1n`3<*EK#ea}2%bH-gSP5hCy1lz2)EmANQN*jrDv!3f3eCA6 zOzKA1qTGg(d)>9RZirZiRj#FCa9_r;Q00iXT7odeid6NWu6QjHK}YdsQ>fsD?8K4e zwWYHHC5EZG&>KYWNL3rig)(MX^z)VX`~weSp@ZR|l8w6z3;xK$t0mL5wSQM+m^%l^ z;B3mas*3f{^qxLW6^suTX-tyFIi46M8(KFDP1En&mQXhCxhNo@OZ=NS<}$z}i#AqW zn(hNrKiT`!1;0_=MfFqC)rPQ{!9}41Jb!8X#%D()t7!stJU|#hWpAM0XX`;%((b;e)zjhixxTVa>{!-mJB}U8i4#k{WXqDQmE_8H;yg)D(%P$Ct8f) z=9_QkyZYi|e-y+H{IP*A82FPQmg7%@2;t9ycphI=(_d1}pPTrL zAl{F^RLx%*__F%`br8?tZ-V$+d_^^XS4C-mZ{i<<_(%McfqypfdJvoOFMfZhfAxTg zuLkk2__u2OJN_exXYrpV{!3B*TkZ5UMfsY6uPc52M>YSen*USHH&pY6YQCwOZz-K_ znnJVsMNFwMrP2^z5c~02Q~dl&fGlFDo=G=JRS;bgG^IL-YhsyFV@Rzc)tORn$}$5_ z7!nG~a#>-@O10}MLslEI#*}}sDQgW`XUh5@hGc^&8%?=I?Hi#cvdNTNO}WjK&8BQI z<#toHn$n;)*k(whAx#3SE0J*A&bXaQIVnM?&rM#QIgs`yorD(~wY{V(s2l7#-qU-k z=iJbt{%BWk581lU+ZXM&xSg12i+XM>F|kij)0s@9JUihH+3~bvO0$2Uwy(eUNdKW| z^jzmrZX%GbO66-ob;sc0!-x9MMY~QPsstKH3dEBW6AtCA>rT28Z4<6N7I)e%x%Tw5 zS$4$kO2|@j|o1Ac+RH{3c@|=X)r={FJ2a}f)@uWT0w}72H z2kwp~V%~m1N5c{tEH;0AF=gA3z}J}^qmp&qv4qo;o*Hr70ed9wDCZ?d?f8)G#?&}R z^m&sp`hUYxDpSSelA3)t=Dt}o){iC=nuzS?e@wB#Z(jZ?9mG+?CG2}=2%Xw z;FgB$z6r-`8|?4ONr@%f4#(n-mSEUpV@frqODQX}WXwr<m#GZ=NP2u+WlY7H4(gLgPxU)W_Zr$x zZ+YELV#1qbEb}?mnM^Ao%;#g|B7fe^4p;fOirTIz5zE?0IHO8cDo~kBdxBL3b9&R> zblRiS9eaw?6)}G0rVri|DrXZNl{iBVkvw>Ol@ta1QS zKjC=UMeYg5n@rM|Ym4|?XFN`6ZP_{UTaISV^BUQqTMBY^1IGQ0Hzqq0k|j72?~j@zCySn$NH`WRD?tS+ZB!E!ih`TXK)=x9~2!!@^JFXDqo_?ju0u>!d>$u`^a& zO)SG=%qX5x`yWtEhb5hI(87oCVGA!|jxJD&w`hN#TXIMaTXIB>@?2WN086^$m?g)h z+mI8M^hmEIeM;LWE2j?h_jL6fi43NgXpy4>1AP&V8j(`ih$JsMZp2Pd+mtiPqareo z3=uCG$s==wiy}v~10!QRh}_snTJf|-`r-~TLoG|iSW%I5L146%S*XM%-Ppr9kXpU4 z20GHQxUSGZRz2mNNee%Zk602@R-Ts&mc)OB`B1Ocwo+`owL`;{B?)1v2Is+tK);~Q zEt!^wa=BEzc5`7xZ5Dh6l39gva*83y5Z98Fu!{YI1BY9f*J-&}!k1sVybLZ0B8qys z_3~7_btIM;YdvUtwl_2F5R~bCeHtyB<_2C?wGJMe?hFxhezSfaTCpjoXwUoexu$=- zT_!N8$fcM!xkTV&sYoK}MN;YM=_GX+i;y-${D>SII-&FR5|J!hGOf9iQMJVbsFc{3 z!#x$a%a+WjD%3#MdNBuUR&JDotGeuPYMx>wQ>|GP4YF54wl%P=+mdSAl8Q8JN$u1B zZ7b?p@~}KYEGbjrT?Y$ynGH)J*baYI=JtHulm5RYk{H>1z6CC%1Xfq8otyd8om z$2;hZ+vzwHe_hdWSi-0Gs8M2Vm&B~=>hp)){Dm(tbzv;#ru4P*Gz-Z~YJYzeIOp$p z%NiD6G{X($Z(M4wmgXjk1F?3&o+TH!5UuKW9!m3eI`62hW$roU@6@%lv?RW(i%c!P z?q%;pou#)>+TO)mrmL^0{)RIhYFJ;A61m%J+Ew1nk4rBPS*m)r#Zq1KhfMLsvrnN( zL6hZW$ds=khpWn6@|4fN<8yz7(Nx0(MQ$%%+&O8xQRUmjs8e!bI-t2#u2Y+)@8YdP z?eZrO-zi=?MG=V!W$W?<_p@Wil+ON3Zp>o>8uV>fm!eeiX-fKNJegA0CdMQ>I_W5^ zG1xzvOnKQ}A3-qJvsI`}_D-f9g~O_-4!icml)lJKzo}eVOzHaGmMMQ50`#dJPb~;l z?s}}MspU=G({o3yy0?0T!%o?$QAN3Q+rnG&zHG*qz)pBETkbMV|Efskw%hXmD3uqW zVv>Id+*fAJnMG@gcUknbSo59c=*L*%V)6n*zqgDZ&y;a(xyOidSjUW~esWn=&O-GL zZCpA>3do;*rZ;ph6)S(0ee=(fzs4t%qI*hIh3+X~m0HB3IT3&FhMF_i$Bc1kCZ6;@5&3S+=PJs*{_BVqjrDOb<}6DtUWM?(C{3V4^!}p zS*+{{2QpaI?rUrc`)0A4E??7bgnglK*vMdQ*q6b&cK?5}27JnFH`Qpv?qJoP>Z(08 zVSm`nVB_%as*2|^bse{45P1qKKZZ@ATQj(A4x5KVTV`?l%d2WuR$a08)U2x3-|AJ> zE3kE{>OIe)sqqu23~kGx@suVyd#XtZ+(1ZunpOs{tg87WngVDEo0Ti8GH8C`=DYQp zmJC|M{u_TV!~P7~T5h0`l2?3fRl} zedM@@?%&S@xtG-Y(2N7vi4M+mvOS0{97Z3G(BVfh#L*azvHFfPow}LcJq$}Po*>85 zIEfFUA0H*>$1#9caf-4};|n;0FX1e{j0f-)oTGmhr}1^t-oRNAJRp9YlPcI^VMM3E zk5Zdjyn=V*M;O$dcovT{aScko!nr4yE)TNSe~f=sl=?ROID0|Ld;~v%pF}lvyo~p- zS3_%F!%xvxpGu5;O0kzqDfY4{RUy@Q67NH$sI<(j_p7M7$&G6atT(X3 zz%zdao;C1(1J4X|#U+~S8|b)6O#_P=2~js`P00)tT?~BSCJU~9 z(MnWCRuqibOeVhXvrs8<3Jq}Pak}GR28T{GhYo*d za3plJ^3&+b;8;&{=(rkp`#2u144sIQ*zRi)&i7={+wKqh!hTNn3|BUV`Z734hTd1u zf0Zi-)XKrqm0_Qh<8JrOVQ4sXN&(ngUZ#pBi{K=K+D}U#$}0%ve;l8nj>^MLsJKb-l{z4c*Gp2Z_nUNOEzDwGP{4yUM*zI zDt%JEmjQf|y1$QQ^b}$4nW9YDQP6&e&ShRSU}9%S3@3)$-94~?i#AT(NU>HstUebHebKmO=2(tq9 z2*{t(k+B$vPixyk1c1+I+rotUm-P)H!YX=&JwNx^jbC9eK+adSvzD8AGT>oE9 z6YBp(P9peiv#lSZ6$)@b;q_w&000RPlW#N{lh8m0lb_cJf1OwPe;j2Ue%|ac)6ImY zfd-eh5T($~mSlU-)}{w7Nh^^}T9PKAp(vBx>1LYA%sM;U0}nj#RunG?rzb^4DcEdN zs(_-XhziQD{vCck0_yY5>~1!jZEXEv-}8Gs@B4ke-*@)4f4}e|fK7O785=`3M`e?f z&7^Eh*&K^ue>0{OSTU%WR$#{v!<3vja+Fu`5!t(Pr63zmHbvPSk0FB-F`UFH75B=O zkII#gsra~5`9uu&;gfRZQ_c7^J|hM0m($NS<1jwgjB$KkHeXQjMY;T?7`}|J#Bir{ zmcdtL^MHb{srb5z2UUDS#W!Q<#JA+ex23i3#CU**e-u2dU`D|s08+&;EMDy{kWboos^vK5NMV%S+n5vnXbTZ!6g|_iM_j9_WE);;WT>A?E2LP) zv5%U$qN__efzGt!=2AIV&ss+6gsbQChMO7-`rcYm>c{Kd3{UEtwrm|PP7AaJ&Me)| zrG_bBf9I$W^(M{2+6@A$8+qxs3!ZLSQf{Ydo8E4L`x8qEF1&AMnYINZ02m;E4p;IcdR!_ENpPSm~|-p4hNcbTdY9S6Vq7-BOI<-e+elr$7=67~Z6lRq&*S@8WwJ zcH(-)aWer!u5Ah=nPvJDf z+wDwgcv{Z);Kv$%f}d)5Mm9f_Yd^=ce+tfMcn;4CM7s03>uLCf+&+t0daVSS#yh0N zl7e#@=5Sua3%H=*ml}SB7d5lCeQhwXSBMf+Ye-$CYdcn&+!Euan=e|o{O zdua6yd7?M*Hw}N6{%@0aw0fy5q3!yR3#?f(=9Ng4D*>zELXI+r=NI}tgLS}hD<|{) z)ST>^i-RMTGOnR}eqIS|Z&j1gStFRKu(48L4De&PmTHFDs9_L z@vcOJDz<2;%sncqo)atyT%TxEe?{xdVY6B2tB}Ko%bF533jxmM#JP8(;8;b^IH-G* zycj)`F$%2v8(8_%mtD~t9Ao~jRy8m-U+ffF=tf+V)i<&5LFlZ13!_=ddt)B$Mv1m@ z7%ONSzLjYwm-DZ6K^V&QX{j*8FKUc;Y&ne1%0_`5ork~bH7e7s^Sxw#cMD2bhr75FK>V-k$ zB(pPY`&|XV%@RP@Oz|DxZw#o+ZM2{fM_Ne?UE)Jd36hmR&&X z@HsRGGp&S{wkz0_u>2f9s<;{|VZ{vAtS_N$2JKuBaxvJrat>FW2{hXtff7EAaA+6j z;W?}vTs?!SCH=Hl{q%(6;S#PMlh)_(p0a3LoB~}XTtlG}Rt1}@rTKXHJl2E|4+qw+ z9jm~a!*xCWE}!q7e@HxX9`6;H!7e#^pTNsdd!lttuBVfDlxGRhlpV#Rb67ie`ads~ zEk{bYp~U#mAAj6jSKep}+$K)ro}NgZ=_E}C2&M71^}#e$p5C;;VU1dsL_~+(Re^Y< zf+NJu8+q%2uXtn*DVp6d7LS~P5WQkZjPUPS*k^~0RsNsPe*{^&oh(h0n@7mYEIBzz zRz65hK15cYB~xA{SKc5;{z1)m&?nYlpIC?eB8l5XFK!n@I7rKBF@^#000zagI3S+K zkaz{d;&mJnZ(`JE;SnsO-COWMWrZs;$~htG3pvpSJxL{fegl^WMy4k_-a!Blo>`mvhhZ zKg+%I+!qHA5z!p}$W7aMxHKcA87a*uX+~#%qsftGjC_uDQz7RnJkCb^>SJzlbDoTi zm&W7f2|Q7nNp7CZQ`~d|PnE{2@JVhO%hP23$qG+*alV@#;28?fbkhVbaMK1^9i!0>0SlC^E zB4ekzDUX-B_%wMg%jQa6?&d14cH^x^;T3LLh`lg&x-=`LsTB%m2!%6UTqiyC3O6Xc z%EhZ)e3o>qanmwxlxD4)UgLENuUB}3yq@i*T5fXFNMQwcF5V;`=Snk2 z;mvMp3o^n&KJmnZ-~4Xy6F?X zNIox;w~NIz7b*NrCbc#k)}vKHEf&*bOrGkR6_xAi)^4t@ZCtyicKN!swW}I`Hm|N+ zyOJrV?mTUqRvy&Ct>ukIG!SlG%rv|z5{?;K*jTRx z*E89xB7U7|WL+SvH^f8DdUUOZL9sx@rv=w*(SUp>I_*YV0G6ASac8kjFbMA5zNoGl zdUYUXFfGa`!3OIIgSG@(<5A5BM8b;;Eu#k_<)RZYg)e=asqnZ-K_WkYwvPsyO z8e|$_kq_%e`MNc=n39`5rLj$$Gk-y2Jj66QD56)V4J!OCbk_~;W}0_QEl(e^3Og&Z zb9Eq^Vya(e)!h7?K)ZZHm%xeMF3VyH?|@k_=!*xT-ZX}%6%3?On8|x=ZF(mY2k=)5 zOSYKgvqEr*$=39k?u$o%14dVQJ+KHMRtH-3m?0}$#OS%HJ!-@4aRYR9Erd~q8l27X zmKK3}*2d-Vw&pHaUo$kOY;0|qV`?ki!Zu1LnZ^vAAS3z!gs)1u-Qtv$%@ws_Y#EKW zL$&Es+*Sx!83}>TaOD5n?*4$&$ zIz}Mrr!`M#m7WN#bNUz0m&Iot$Kn$WqFJ4D`*&G?AiFF+VRNUuO_J2Y6P8vMH=42A zg1(xVS0>X`dYYb5=^c7krCxeirQg#ZRC=7AQ0Wr-mP!}XH&uF&9#ZLYz6u+kP^l@4 zzNgZ+=`xje5VG#~RsI2At@1T|t-{yI$Mq`zkZ(}=M|=a)@zI5vK3j^wBg&1qH~;xA3hh-^RDAdKq z`Ck61H20~zo3B;*XY>YgLI27%@vspH>8Y5_wB>YD4sUur;GLNto9XpO^q4msF}x^0 z4J{D%YT+(Siz1;$B$}0ZYZBSjYec*)2;^RWy%UKz*yWv_n%7l^QlfwVRn6z2Tjihg z{i3G_RNlk)Fl{<26N$ZJ*dpQ$eKihL-pdcFbSvGa@n{_?xHMCH>q-}3Uz-TMW51R#fG~_kfGy{!) z?wy&j+@9%ek4CW2=<-6-U9y)2u+jv;$`a!c+bcz@HxPqzq9P*<{3+K;Q`4{jIP@wZ>F_j(;VD4oma=0HIRlnaVHlwaD+HLV^E_$!P=2ER|o9X;Z#`ywXzm zWtD%;uc-X01iQSUks+aiqN+$d=r^4hwJ4k;S&Vwy`>RoJOC(z1m8kI>g@3E^Yy1Eb z@#>(i#RN`XIqZt-!M1R$K#K{r4lQhm)5S4IV3u%Lk2 z{)5VYukqDbv_Y_2K}2*S1A}BOTTm5cRth z%>}i!@|<~`HxytIN85q=7*$X>_=;luph;rakNMtXS%PWviCoEirTdMXL2R3+ znUr|_MsZ_a>Z)VMS1!K>YVEj%%Ul;awZ!?VGUG|fL<^EL;E7|GQC;;8#{W5xB z3^lJHhZ&KT{WmeW1+^Km2I*e;F=TMUssWhtkBem>%SY!H>?c5*_u z4(68QRyM~X!MLG|D-2AyU8pkPoi^mI^c#iM;HLjvJSIao)X^?qLAi?3I|HUcEd%4r zjI!Bsk0V$#FH#DJ#JFLBSaq`a0}GlTwmbRQS7g{?6lAK>!jUk_!k{J8xPlB93TCJS zoTH{D(-ql&m7;WiXaNKHA7R- z5N3wl9!U_YPhO~{nG!MHbiLsTS5JNq47^tFV!6{v7A)rR@3>qdc`xNT>hWIgB_gd> zAX%L#l$mB67yZRaaje8BaawN4)-|SnUr8HSYzB$CNC%>SB378 zL5t{Gx(-y_G>@)_er;G=L_egRkZdC4ype9gtZ6ifevCIK-Hg?Cth@zlaQwC8;S12` z#>l0AIpg<}r@ogaG!^&I#0J{}`{+^hu&ct6YtOosCY5>|-85-|J=cCq-zOy=hb&yseqJIn|jDwq1YCDLY0uyR9m6~ZL`JgC2 zokFcpM}SVJ^Jooi#f%`nLUcYws0)1;QPfmn3j~zaw?j$UbOz0*JLo6m5}{LSy_D{R zlHeLxbr;5k5FNgt)y{3!6Awt#b^n_$*qau(!s;F15}np3C!8kFxP>$6JmA& z=U)fnE}$xSXuoeXq?FTOVu{VSeNbY57FMpLZt8(@_M=xd6(>Ch&?9QdrmQ10U7>?h z28h^84<|%?2|5%eYD%A`s-lt}DzC7Yir>t-k>&zYvp3|-QA|mS8=LItnA_OoC~a(V zdh8-ug<~(x6GYCp@23TOQm`p9v3vkOx@ZY(3o&w)l2EVC)hM!z% zdXp1z~9sKj1{J{hGU~_^dAQ7PDKpb(@S|x z#W_oR=(Kun=%r;%&PS-S$(FMm2Ff(WI7D^xv<+BdY)c@ zu`B3IdeQW%D=_zE`ZfBlhgn~yS4=n`P66OBFev~SgPnh4!Z{az{QNcr=NfXk`mnDn zX?gswRA`w(uPL-rp?abtGzEQql9$sb5iM7!@eGC54KD=Q*XfN!25-Zcc+G^IE&EB^ zOU>Qnt1Hg&caxrVCpql9ZM#z*oMW>4Bv^ln#sOmE0WeXbp)h?T}8F`Q~vwx(7mTLYj?&yC@mv(+!|Y1$P;$x64urYyj8@ zmT^Nhqo4|Z50o*T-iGqtp;IC0GI|e`-UqD@kh(tvr4NvmK14?P2=qQiEdK=5K8E5x zLG|+wQ`u{vm+5pi{e}Jtjcr0<@E-jQ79WMY_CEa`J40tFWnTk|RtCEUbOrQRE zP#-Mk7_<^wBr`=L*!U;?E0HN~MxVenf3zKCS3_|r%B`ja_M2!#NvT2*B(@ zsM^+_@vL0_-)R32@%~d(d;dnoi{wk6r$7m!DNW>K?mea^^67t|G0Ejq&7#Hz$mY@i znuX4P{ics0ha>*)JwmzM&-5r4cKS5IbPZOCrj?>%vwl^(0uFC(84#65H4Rn%86N+c0z#vKz0e2( z%4H+bR(O+m%yxmJE*!XguSDA;P;?6?+8Ln`?T+AHbKb$Cond+uPwFx16w63Z=1erk zVu=r|XE?}uRfg5Ep3z}gSMg-R8uM+siqQ=USAS_do78r6Fm9NPCOmx*?A`}oJ^*&` z%-ZLy8?2DH@|xd7e*jQR0|W{H00;;G002P%9ZJ~Z76$+TTMhsKCIFLh)fJOJS`~k3 zV;ff$J!4B6SsurZVkfm@7sWBHEZG(bG(g-2yfsm4*}+?J($*bY6L}JOq>e_34P_~i zmVGHuD3r28*B*CUi}$dH#|Lxm;V1z8kTJRN^Q1UcEUMJk2i$Xt#<#ZB41CBvqQtq6|c6A^q; z{)^+8Fg_K*r}3ExbbMB%XH|So=FdlP5?_$vwu9X34S5)v|wM7Ayr? z+OiCLBCnT9MoGbmi*sX>(^D&p^HXyxmu53lEAtC;>6wcPqSM#)n|dm*Te;Lc4OqER z1#J@rtK{gGv!v(ChJquP=Vl+7npmivI+C;XY~ENb8TO^ZhG=+Z%tGp6GjGsD=t0vm zoeK(@$>jg1(wJ1YgK6>9#3re>32$n`GTTU9fX04=Q!b z){8~MPF>cW^)Y(2K~0-LN8|gU1+6`2IQ!$V5^rSdF>j`~*UVhm)us+WuzT>=@-(yS-8+Jyq$u)UQke{khXSInY<+4z53v-d9iY>;`i zZ09fOrFBY-p(owf0HxvKwhg0H(sRb7nKMd`f<8~FWUQ5K)7eU8_Wn)%;Odqm)!B4) zT!BI#yY^U}+FUb=etbeD7lH`$j=pvyqZj=`X}67y!cAjp(=n`)8}@+ZMoVFIlr&@L zSArMAe%}+za8iqN=|g`)AmLrK^R=Sh)u!>K7s)Ip)Fn zLfKw3WRu0eudGJogoaT(sNusnui}RqCh)R`$MJ-Qk7HIt8q>Vndo64D5nj=-iZ$Ny zgDl3&Wqxc)kRVw3rjMW!2OR=(b!z$b&-;TO7v#ZyQ zHD}+}ykFw?zr*{>!|}m`1$yj2;~RHtt~1`S&<`q$|0FL^R#w6AJG%CMiAfW43cEg> zKG2gJ7+Uh~5Zjo?(O-BR#u|3({hhxN!rnJP+Z!4MC;xv>EArYz+I{lY$mPu8o*&xF z!qO1Db{2>aN<#~ki&@>FxnTV2xG)N3eY8+K?d^2M(+x9|Xw=v1I}7V};g&Q&*U?r! z@+6-%HfOJi$p+l%e@m&ny4yvM$J32*rRV!qU_4#c^Q8m!ys{k~yt2P?w@Qw&;RW%s zU0|x5twVo^Ea4QtlFssrtQp;S0Oz3KgIqOXkn0caStt2p6QmsG9(y9khq!t_XN7Yx zQHAoFt9pTBgfq~G0Pe*{C~2M&K8i8UVqn}i@Gvz+HzEcS$vbGOTRB2n;CEGkG+WT` zS~~7&`<6r!T0&w1lfKRW5=rHJJCUrQxr#t0F;ss=a3(RFtRi$iumg2j{t8#ovV+KS z6|G!p6|_ZIiSA%`sEW?*nmauRag5WI zL9`=*6O8HvhOmiY*R@L?>6&Y|F~#t(R`3iiG8aueb(31>7?u;T`1+htJN#btbq_^pi39OilUH01>> zy55Y`*pFbzW&arE5R_GwI8E}T`>e0?q?BG~GJ3j#froluMliXZZ0@b#z1!|>5l&Ip zvqzb=X`*Bp{aKew%sX2{>%_8)rc&byt`f<|{TJH!wI$yZKJK$TDK>i;r~5KPlA3>k z3w;D1+8*i)JXOK{b@b!(81ykn|1^5oL7$@Zp`NXt8iO7@i4|f5(S@hnO44|_giEu_ zr3K2r5mliJ9e%s`bY7qt3EX5dI#@yCC4>{NqiH)CO}eWNxf{`;yBMxwWLvW5msK>y za&l|yeY=<9%$o;@KTgmmNa9JRYK0<2r0==ilQrU#$kq}?E=Rifzu^|?HKtt3lb?SYQhw@y|JPX6Afz*_qk%^Uv3B0MeM3 z(11i8ElCNDNJvN_9Y8PcarANA7m@)99D^JWIEEzzFd{+1BaX)$8HQTxwN{KIe;L}d zhM7;~O?joDCX|Af7&F$_Wql>9>FS(p7FBbIw1+iavql&uI^EU()v(zsWqLzhiwwRo zV?||X6pY!;^<~w3E-x2|6V4inTv(J%O`JSN?69Evlb9B3Yqf11ij80rmu!IDiYw_$09&N0T&vJL%gyIwC-_qO8rx z8}_H*c*3xDE>++jYs#(^&)cL}QesInM5?*RAT1c1rlO8(qI_B^bb3Ute}V|(LJ%P| zaXbxT91|RqK}_KpLz`P_7zSM(d7-cA#+H6WJ+vMt3gRlR3CCurkX;Q-9|PZVoS?hP z0&@z8TC4mh+?o|jj-l^NJyuOjj>XKDY^sN2I!=&2ebZ3wyI0YPMc^n=oym%#7K@RA zBvol|6^+s5wCSd$6%y1{f1<+RSzJ~493tEyt{-7RNv%+cIB6xzF^X3aUY zWBJgjwt1(kntRov{W`a`fbu_ zlFnY*gVES0c%rfR4!j@e>_IcF4MN5yP{Sq>U{h!zUJJ=cAD3_if3PWy!Qhv(AVC0}Z6d$KU}3005f{ z002CbAEhLcj2?ed+eQ@r))uTIi^RB?gtnv(H359V+>&6MBn6sVad28Ev?jgDLU9#r zIU~zWUZIcBw@7E&At}?O|2osR=-<9WJ3T8oU}A$zCNuq`-97v1oNqs!Jvx8>`|Aq; zb9f+Q2#Y7^k&zL>B1cY!ge4hSTn^$2u5x@N7Rwwf0``Bg3>nurt_N^~W6owHmsWBlMDC z8uk^28sva*DPdS|*2=ndS1nh`63*8(wYs5NhFG_ZlAy~F zSQcJgh2qH`80ybqJlD~ED^>;7lpLxG`-tWxJ znddyuG?=3BgJGe&qw*>npLO)vUEjM@#{7*ee&K16WP?7H*q=zoIz4me9!1ft zYw@snjD_1wJznQ^->R^*ds}MrSGCS^FsSvE4B?Czw>RB$n|b@hxF3ZDCa+^6kn8OR z&^5N~j+lG4+3y+#6VYjfgw-Hg`Awxh4qE+5hnT>RC5vjU4ln(+aZa9DKl&WgU#WOc zrrq;~vy`{m>LR&sOqI&I;asi<{q?azMRDQ|C&pt{w^YBOI4kVU{jJ_^Sxx7&meAE` zoTGPenfiH4tueS{0JqCpA{o8k0xYz|;#zPGVFb#ju=3R&Kg!6AcDG;Osn3zj@WXLu zC`!iIRusjKeJ)5gH+;+WV3I&*{p=U_`nMFWG8ZnqEE|~#oB>{3YVMP@6s&BhaLJ}+ z2ID#Hl*mNa8)RG6e=d-cv3O5Y!F*ohql?sJiz^~9hbGlqe<)MG+5xxOjCo-iRG>V% zYR$B*^0F@)4c9R%l6z zZZ+zAMIR<=gL4-g?g-gIVasLt53rUK!33QMKfZM47j(Tel`3;R>LS6WyYxl+hh|%x z8p`nC#<<&h%}IzP8@`2rPe}a{Rj84VjFw!SNm>`&N+a1?`=NEgJFlLnZHvq^n7m4R z0MxR2Rp|Uq6P6Vtpr@vzm&;mMa@SCq>c>GiGP;`yPK(vb_CVFETin-P|IoMn<1@#@ zscaU-b&YMn+cm{l8LRXTMbYDaf+JhX=gpQE4bMn}hAV?feQ=ui8APAZ8$+k0Cxrpp z4YU-zxR2&BHcD|b5pg3sB`aN5Xk|ks`j1FQqri%JM2%eHQ-Fr@gES2}aT?nJE+lJV z<}CL7Sn;T%SqE^+ost?$&cdo~s9PPtyot4&esqsq9x4w_=(Ty>iXxLR(7&=o^gX?GV!39 zhgA*5v_N61v$2J%N=a>Ba$rz`l1e#ZE5_5g$!u`E95=P^2Tch?kb5>Vl=W$jtv(l* zW{fN2SBp!s(0A9lD@$_=R_~;7R)Bn(b_N}nYlt!jMOts3UkO8())gUDr?}sEM86)` z{SomLEfPmQF{C{IWeqG%a{h_gnCl^A^UXc`+;BLg3Vjq<RwWIqRIWM{6_ zmk&KkH7@GBBlf-hR)dcOGZFKZmQDBry-qXjSC2B07bS9js!6xcGZ)X>KC+K;!e={s zin^{F!~Gvy$V&|63~H^}r}*VJArwL!!n^#)oqv-Yi&YCt!=Q(zW&L+QW4wjC3gb)ar0p{D0XG{-GV z`||TIlm8`c#4oz!2h?-;1U&YfNiny1HEPs@nuRXM3R~&yyQDRAzb7MI^ z{_J9LJmcom__KEeal58^Iz@r6V(L=Q42`mj?~5M_E)NIqCEWIWIMLFXG?msCwrr+L*h4d8hM|m{Zktx8~8jzVXL5a#&+e9IaVS zO{VPamJfA{&Ruit5ifSS(-6qujjq=Vlg*#r-{wt?+WRfZV*m2pUuCa7QEx3IEdw!? z=bb6>SfJ&)eH2E>8`f>-()G@{aP(6pN8O7y$|ob0Ij0XYMb8T*DBcqd7-+nX@L5lH z%-JhYqQ*8+OLoq&v8kw7zvj;^@cF7ajnY128ezYi?x;jACJZOnMgg%v&?R9(W+q*66aB! z1R7v7)+-wB0nee&*G_QQeZKG#SJ5zBza{8myX)*vyQ)*Q%fHewAcP&XKwBUW$xV+a z#Iv+}7P5+}R6?$01R30R`9^n{)s~UwYQRH5_NMycn~X7+61!ch4@1gXoJNGy)GK#J zTF%uLsd|TFgzKKByU!TihMaesfHjjbElh_*uzasL71AMMX80sZZurU78^8rgJ3MdG zuP9=qB8!2CFdinnk}$#k%JVNYU)gT?xkPH{2EN>xMt>aCI(L0$%D`Qp(>S*J-n~}d zj$z7#>%}Wp+k0%=Yvc&Wj896{Co2U8{V^wMbI0*a379qQKx@OLlN^&AiaEX=nLZcC z-!Tr*S;IplWEwK?mzi$IwHGzWP0ykuaWV`06D*g`Y9{rM&LtMQ#Z;fun)ZK}bp(SC zpld--1}_@1?wbRB#v-MUmrS;ldb>Hkn;lV|>`qrac^G+tu&|>M9Eph)d)C&u0@jN_ z{YJm??96Q0O_M+UeZKkV{jxXtO@{u7!U{Qvc#Ynf1Z4-5fw=!ju$~5 zkE8KN0)gaXn`nq4LjVUSY3K0jKq)5?vVpI8dBOf!80avL0G{)bsLgRoFl$^5xGV6F zc@A)pAVJ*;9^}8bmLL%Re~TcNVI)Zs4XaZT?=iuV$Ins!tIWr4$^9dw2QN;F0@w6O zW|cV|m@^4O9^Vf6uOGD`N%;5Xh%oZ_s``J0tj7NcSx9YjnnD1cmq`@P7Db|p9AR{S zJo2%jR^ZZ2zMok34uPB3vs3s7()LRBzv1qKStB7hIKK;8l*Xf=Bd2=yYtY+puF?i4Y1 z{tk(%T}FZua|l2%fM^PUp%GNz%eOG(|JOcfAQ0taHDC-R30)!);Ov|zP!~cn>F+ax zs`D`9u}R%Azml-u!sK`^q8kjXpGN@XktEmcc{$|&hj>g7i0U!7+GvuFp=z)pSgAU|kJL=^4GgOVVM*iQD>|Lt&*E^uwx5jf}ucZQXTJs}E=^n%SR7Xbb~ Z5H)%VJiSWIAOn$sbP+#;Q{V4m{s)AkOUM8K diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5028f28..a4b4429 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acf..2fe81a7 100755 --- a/gradlew +++ b/gradlew @@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +175,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a1..9109989 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" diff --git a/meteroid/build.gradle b/meteroid/build.gradle index a25ca81..84fa7f1 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -42,6 +42,7 @@ dependencies { repositories { mavenCentral() google() + jcenter() } implementation 'org.jetbrains:annotations:13.0' // Retrofit >= 2.7 needs Android 5+ @@ -88,7 +89,7 @@ sourceSets { } tasks.withType(com.github.spotbugs.SpotBugsTask) { dependsOn 'assembleDebug' - classes = files("$projectDir.absolutePath/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/") + classes = files("$projectDir.absolutePath/build/intermediates/javac/debug/classes/") source = fileTree('src/main/java') } spotbugs { From 227d5134267b22dc9966073748916056d9942139 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 17 Jan 2019 14:44:19 +0100 Subject: [PATCH 179/197] Revert "UserSettings: Workaround for 2.3.3." This reverts commit 8fbaa49dda2abd67c57946a0fda092beb2b647dc. --- .../src/main/java/de/chaosdorf/meteroid/UserSettings.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 62c702c..8c1a2bc 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -166,9 +166,7 @@ public boolean onKeyDown(final int keyCode, @NotNull final KeyEvent event) private void makeReadOnly() { writable.set(false); - try { - invalidateOptionsMenu(); - } catch(NoSuchMethodError err) {} // workaround for 2.3.3 + invalidateOptionsMenu(); setProgressBarIndeterminateVisibility(true); } @@ -176,9 +174,7 @@ private void makeWritable() { setProgressBarIndeterminateVisibility(false); writable.set(true); - try { - invalidateOptionsMenu(); - } catch(NoSuchMethodError err) {} // workaround for 2.3.3 + invalidateOptionsMenu(); } private void deleteUser() From 40d881e5bb27770c6e559ad6ed89aaff61bcad9e Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 17 Jan 2019 14:51:50 +0100 Subject: [PATCH 180/197] Merge default values and v11+ ones. --- meteroid/src/main/res/menu-v11/buydrink.xml | 63 ------------------- .../src/main/res/menu-v11/pickusername.xml | 53 ---------------- meteroid/src/main/res/menu-v11/settings.xml | 37 ----------- meteroid/src/main/res/menu/buydrink.xml | 15 +++++ meteroid/src/main/res/menu/pickusername.xml | 5 ++ meteroid/src/main/res/menu/settings.xml | 11 ++++ meteroid/src/main/res/values-v11/styles.xml | 40 ------------ meteroid/src/main/res/values/styles.xml | 7 +-- 8 files changed, 34 insertions(+), 197 deletions(-) delete mode 100644 meteroid/src/main/res/menu-v11/buydrink.xml delete mode 100644 meteroid/src/main/res/menu-v11/pickusername.xml delete mode 100644 meteroid/src/main/res/menu-v11/settings.xml delete mode 100644 meteroid/src/main/res/values-v11/styles.xml diff --git a/meteroid/src/main/res/menu-v11/buydrink.xml b/meteroid/src/main/res/menu-v11/buydrink.xml deleted file mode 100644 index cf5375d..0000000 --- a/meteroid/src/main/res/menu-v11/buydrink.xml +++ /dev/null @@ -1,63 +0,0 @@ - - -

- - - - - - - - diff --git a/meteroid/src/main/res/menu-v11/pickusername.xml b/meteroid/src/main/res/menu-v11/pickusername.xml deleted file mode 100644 index 321fa6c..0000000 --- a/meteroid/src/main/res/menu-v11/pickusername.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - diff --git a/meteroid/src/main/res/menu-v11/settings.xml b/meteroid/src/main/res/menu-v11/settings.xml deleted file mode 100644 index 639a76a..0000000 --- a/meteroid/src/main/res/menu-v11/settings.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - diff --git a/meteroid/src/main/res/menu/buydrink.xml b/meteroid/src/main/res/menu/buydrink.xml index 89385c0..cf5375d 100644 --- a/meteroid/src/main/res/menu/buydrink.xml +++ b/meteroid/src/main/res/menu/buydrink.xml @@ -23,6 +23,21 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> + + + + + + + diff --git a/meteroid/src/main/res/values-v11/styles.xml b/meteroid/src/main/res/values-v11/styles.xml deleted file mode 100644 index 9a35215..0000000 --- a/meteroid/src/main/res/values-v11/styles.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - diff --git a/meteroid/src/main/res/values/styles.xml b/meteroid/src/main/res/values/styles.xml index 0dec8a7..7052ac7 100644 --- a/meteroid/src/main/res/values/styles.xml +++ b/meteroid/src/main/res/values/styles.xml @@ -28,7 +28,7 @@ Base application theme, dependent on API level. This theme is replaced by AppBaseTheme from res/values-vXX/styles.xml on newer devices. --> - - - From 67a78834a2f71e31323fd9e4054069eb4f606324 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 17 Jan 2019 14:52:11 +0100 Subject: [PATCH 181/197] Gradle: Remove workaround for Gingerbread. --- meteroid/build.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 84fa7f1..ebd38e2 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -68,8 +68,6 @@ android { signingConfigs {} lintOptions { abortOnError false - //ActionBar on Gingerbread - disable 'UnusedAttribute' } dataBinding { enabled = true From b5fe5ab25e02ee08ebdb708ce1c79446b000dd87 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Thu, 17 Jan 2019 15:04:17 +0100 Subject: [PATCH 182/197] Remove code specific to pre-Holo versions of Android --- .../java/de/chaosdorf/meteroid/About.java | 9 ++-- .../java/de/chaosdorf/meteroid/BuyDrink.java | 52 ++----------------- .../de/chaosdorf/meteroid/PickUsername.java | 29 +---------- .../de/chaosdorf/meteroid/SetHostname.java | 9 ++-- .../de/chaosdorf/meteroid/UserSettings.java | 15 +++--- .../main/res/layout/activity_buy_drink.xml | 37 ------------- .../res/layout/activity_pick_username.xml | 24 --------- 7 files changed, 17 insertions(+), 158 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/About.java b/meteroid/src/main/java/de/chaosdorf/meteroid/About.java index f222932..5707331 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/About.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/About.java @@ -66,13 +66,10 @@ protected void onCreate(final Bundle savedInstanceState) catch(NameNotFoundException ignored) {} binding.setVersionName(versionName); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + ActionBar actionBar = getActionBar(); + if(actionBar != null) { - ActionBar actionBar = getActionBar(); - if(actionBar != null) - { - actionBar.setDisplayHomeAsUpEnabled(true); - } + actionBar.setDisplayHomeAsUpEnabled(true); } binding.appIcon.setOnLongClickListener(new View.OnLongClickListener() diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index c3086f6..a49fa7e 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -101,47 +101,8 @@ protected void onCreate(final Bundle savedInstanceState) barcodeIntegrator = new IntentIntegrator(this); - binding.buttonBack.setOnClickListener(new View.OnClickListener() - { - public void onClick(View view) - { - pickUsername(); - } - }); - - binding.buttonReload.setOnClickListener(new View.OnClickListener() - { - public void onClick(View view) - { - reload(); - } - }); - - binding.buttonEdit.setOnClickListener(new View.OnClickListener() - { - public void onClick(View view) - { - Utility.startActivity(activity, UserSettings.class); - } - }); - - binding.buttonBarcode.setOnClickListener(new View.OnClickListener() - { - public void onClick(View view) - { - scanBarcode(); - } - }); - - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) - { - ActionBar actionBar = getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - binding.buttonReload.setVisibility(View.GONE); - binding.buttonBack.setVisibility(View.GONE); - binding.buttonEdit.setVisibility(View.GONE); - binding.buttonBarcode.setVisibility(View.GONE); - } + ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -407,14 +368,7 @@ public boolean onOptionsItemSelected(final MenuItem item) case R.id.use_grid_view: Utility.toggleUseGridView(this); item.setChecked(config.useGridView); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) - { - recreate(); - } - else - { - Utility.startActivity(this, BuyDrink.class); - } + recreate(); break; case R.id.about: Utility.startActivity(this, About.class); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 0b0371c..13542da 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -71,29 +71,8 @@ protected void onCreate(final Bundle savedInstanceState) super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_pick_username); - binding.buttonBack.setOnClickListener(new View.OnClickListener() - { - public void onClick(View view) - { - Utility.startActivity(activity, SetHostname.class); - } - }); - - binding.buttonReload.setOnClickListener(new View.OnClickListener() - { - public void onClick(View view) - { - reload(); - } - }); - - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) - { - ActionBar actionBar = getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - binding.buttonReload.setVisibility(View.GONE); - binding.buttonBack.setVisibility(View.GONE); - } + ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -211,10 +190,6 @@ public void processIOResult(final LongRunningIOTask task, final List resul { final List itemList = result; editHostnameOnBackButton = false; - if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) - { - itemList.add(new User(config.NO_USER_ID, getResources().getString(R.string.pick_username_new_user), "", 0, true, false, true)); - } final UserAdapter userAdapter = new UserAdapter(itemList); binding.gridView.setAdapter(userAdapter); diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java index 3653b88..58ef857 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/SetHostname.java @@ -80,13 +80,10 @@ public void onClick(View view) } }); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + ActionBar actionBar = getActionBar(); + if(actionBar != null) { - ActionBar actionBar = getActionBar(); - if(actionBar != null) - { - binding.buttonSave.setVisibility(View.GONE); - } + binding.buttonSave.setVisibility(View.GONE); } } diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java index 8c1a2bc..840a495 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/UserSettings.java @@ -93,16 +93,13 @@ public void onClick(View view) } }); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + ActionBar actionBar = getActionBar(); + if(actionBar != null) { - ActionBar actionBar = getActionBar(); - if(actionBar != null) - { - actionBar.setDisplayHomeAsUpEnabled(true); - binding.buttonBack.setVisibility(View.GONE); - binding.buttonDelete.setVisibility(View.GONE); - binding.buttonSave.setVisibility(View.GONE); - } + actionBar.setDisplayHomeAsUpEnabled(true); + binding.buttonBack.setVisibility(View.GONE); + binding.buttonDelete.setVisibility(View.GONE); + binding.buttonSave.setVisibility(View.GONE); } makeReadOnly(); diff --git a/meteroid/src/main/res/layout/activity_buy_drink.xml b/meteroid/src/main/res/layout/activity_buy_drink.xml index 5ae4f9a..78ec6d5 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink.xml @@ -62,43 +62,6 @@ android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> - - - - - - - - - - - - - - - - - - - - - Date: Fri, 3 Apr 2020 18:57:19 +0200 Subject: [PATCH 183/197] Remove unused layout property --- .../src/main/res/layout/activity_buy_drink_item_gridview.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml b/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml index 5cca9cf..0beeb7b 100644 --- a/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml +++ b/meteroid/src/main/res/layout/activity_buy_drink_item_gridview.xml @@ -48,9 +48,8 @@ android:paddingTop="2dp" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentBottom="true" android:layout_weight="0" android:gravity="center_horizontal" android:textSize="14sp"/> - \ No newline at end of file + From 7467f4ce74372967f67f85034b8fcfde4f1fc4f6 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 19:02:34 +0200 Subject: [PATCH 184/197] Ensure that updateShortcuts is only being called on Android 7.1 and newer --- meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java index a49fa7e..7339b38 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/BuyDrink.java @@ -24,6 +24,7 @@ package de.chaosdorf.meteroid; +import android.annotation.TargetApi; import android.app.ActionBar; import android.content.Context; import android.content.Intent; @@ -275,7 +276,9 @@ private ShortcutInfo shortcutForItem(BuyableItem item) * If a shortcut with this ID does not yet exist, it is added and some other one is removed. * If a shortcut with this ID does already exist, nothing happens. */ + @TargetApi(Build.VERSION_CODES.N_MR1) private void updateShortcuts(ShortcutInfo shortcut) { + assert shortcutManager != null; List shortcuts = shortcutManager.getDynamicShortcuts(); for(ShortcutInfo current : shortcuts) { if(current.getId().equals(shortcut.getId())) { From 04f95f3f0237dead2e5579bc2d91e99dc24a8e0d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 20:17:54 +0200 Subject: [PATCH 185/197] Remove unneeded XML schema --- meteroid/src/main/res/layout/activity_pick_username.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/meteroid/src/main/res/layout/activity_pick_username.xml b/meteroid/src/main/res/layout/activity_pick_username.xml index b282e0f..15e9ca9 100644 --- a/meteroid/src/main/res/layout/activity_pick_username.xml +++ b/meteroid/src/main/res/layout/activity_pick_username.xml @@ -61,7 +61,6 @@ style="@android:style/Widget.ProgressBar.Large"/> Date: Fri, 3 Apr 2020 20:30:08 +0200 Subject: [PATCH 186/197] Add autofill hints on user settings page --- meteroid/src/main/res/layout/activity_user_settings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meteroid/src/main/res/layout/activity_user_settings.xml b/meteroid/src/main/res/layout/activity_user_settings.xml index abdf48e..f6ef15b 100644 --- a/meteroid/src/main/res/layout/activity_user_settings.xml +++ b/meteroid/src/main/res/layout/activity_user_settings.xml @@ -61,6 +61,7 @@ android:layout_width="fill_parent" android:inputType="text" android:text="@={user.name}" + android:autofillHints="username" android:enabled="@{writable}" /> @@ -71,6 +72,7 @@ android:layout_width="fill_parent" android:inputType="textEmailAddress" android:text="@={user.email}" + android:autofillHints="emailAddress" android:enabled="@{writable}" /> From 0ca2f305e9df57b5411ad8f09dde766f12c81dec Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Fri, 3 Apr 2020 20:44:10 +0200 Subject: [PATCH 187/197] Don't specify a Java version --- build.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build.gradle b/build.gradle index 8a1b4bf..495c503 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. - -// Be compatible to Java 7. -tasks.withType(JavaCompile) { - sourceCompatibility = "1.7" - targetCompatibility = "1.7" -} From 3525685defcfeb6468acd1bd4616c5620e915b0f Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Wed, 8 Apr 2020 18:10:02 +0200 Subject: [PATCH 188/197] Use view binding for the grid view in PickUsername --- meteroid/build.gradle | 3 ++ .../de/chaosdorf/meteroid/PickUsername.java | 29 +++++++++++++------ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index ebd38e2..96d4a89 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -72,6 +72,9 @@ android { dataBinding { enabled = true } + viewBinding { + enabled = true + } defaultConfig { targetSdkVersion 29 minSdkVersion 14 diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 13542da..8e2d6df 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -52,6 +52,7 @@ import de.chaosdorf.meteroid.controller.MeteroidAdapter; import de.chaosdorf.meteroid.databinding.ActivityPickUsernameBinding; +import de.chaosdorf.meteroid.databinding.ActivityPickUsernameItemBinding; import de.chaosdorf.meteroid.longrunningio.LongRunningIOCallback; import de.chaosdorf.meteroid.longrunningio.LongRunningIORequest; import de.chaosdorf.meteroid.longrunningio.LongRunningIOTask; @@ -238,33 +239,43 @@ public class UserAdapter extends MeteroidAdapter public View getView(final int position, final View convertView, final ViewGroup parent) { View view = convertView; + ActivityPickUsernameItemBinding itemBinding; if (view == null) { - view = inflater.inflate(R.layout.activity_pick_username_item, parent, false); + itemBinding = ActivityPickUsernameItemBinding.inflate( + inflater, parent, false + ); + view = itemBinding.getRoot(); } - if (view == null) + else + { + itemBinding = ActivityPickUsernameItemBinding.bind(view); + } + if (view == null | itemBinding == null) { return null; } final User user = userList.get(position); - final ImageView icon = (ImageView) view.findViewById(R.id.icon); - final TextView label = (TextView) view.findViewById(R.id.label); - Utility.loadUserImage(activity, icon, user); - icon.setContentDescription(user.getName()); - label.setText(user.getName()); + Utility.loadUserImage(activity, itemBinding.icon, user); + itemBinding.icon.setContentDescription(user.getName()); + itemBinding.label.setText(user.getName()); if (user.getId() == config.NO_USER_ID) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - icon.setImageDrawable(getDrawable(R.drawable.add_user)); + itemBinding.icon.setImageDrawable( + getDrawable(R.drawable.add_user) + ); } else { // This is only called on KitKat and lower. - icon.setImageDrawable(getResources().getDrawable(R.drawable.add_user)); + itemBinding.icon.setImageDrawable( + getResources().getDrawable(R.drawable.add_user) + ); } } From 166a7eba0ba999a4cb349c2083348a71cf1ad4a6 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Wed, 8 Apr 2020 18:10:52 +0200 Subject: [PATCH 189/197] PickUsername: Don't support adding users via the last item As we now only support Android >= 4, we always have an ActionBar. --- .../de/chaosdorf/meteroid/PickUsername.java | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java index 8e2d6df..55d940b 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/PickUsername.java @@ -212,14 +212,7 @@ public void onItemClick(final AdapterView adapterView, final View view, final { config.userID = user.getId(); config.save(); - if (user.getId() == config.NO_USER_ID) - { - Utility.startActivity(this, UserSettings.class); - } - else - { - Utility.startActivity(this, BuyDrink.class); - } + Utility.startActivity(this, BuyDrink.class); } } @@ -262,23 +255,6 @@ public View getView(final int position, final View convertView, final ViewGroup itemBinding.icon.setContentDescription(user.getName()); itemBinding.label.setText(user.getName()); - if (user.getId() == config.NO_USER_ID) - { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - { - itemBinding.icon.setImageDrawable( - getDrawable(R.drawable.add_user) - ); - } - else - { - // This is only called on KitKat and lower. - itemBinding.icon.setImageDrawable( - getResources().getDrawable(R.drawable.add_user) - ); - } - } - return view; } } From 75c745d9636a2e20000d30acba18d36cc5c568e8 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sat, 9 May 2020 23:58:12 +0200 Subject: [PATCH 190/197] Update German translation --- meteroid/src/main/res/values-de/strings.xml | 31 ++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/meteroid/src/main/res/values-de/strings.xml b/meteroid/src/main/res/values-de/strings.xml index 184f427..b33f7ee 100644 --- a/meteroid/src/main/res/values-de/strings.xml +++ b/meteroid/src/main/res/values-de/strings.xml @@ -38,31 +38,30 @@ Die eingegebene URL ist nicht sicher (HTTP statt HTTPS). Wirklich fortfahren? - Benutzer auswählen - Neuer Benutzer - Konnte Benutzerliste nicht laden. Bitte Netzwerkverbindung überprüfen oder Hostnamen ändern um fortzufahren. + Account auswählen + Neuer Account + Konnte Accountliste nicht laden. Bitte Netzwerkverbindung überprüfen oder Hostnamen ändern um fortzufahren. - Benutzer hinzufügen oder bearbeiten - Benutzername + Account hinzufügen oder bearbeiten + Nickname Email Guthaben Aktiv? Transaktionen loggen? Umleiten nach einer Transaktion? - Bitte Benutzername eingeben + Bitte Nickname eingeben Bitte Guthaben als Zahl eingeben - Kann keinen noch nicht erstellten Benutzer löschen. - Diesen Benutzer wirklich löschen? - Benutzer gelöscht. - + Kann keinen noch nicht erstellten Account löschen. + Diesen Account wirklich löschen? + Account gelöscht. Für Getränk spenden Bitte warten bis aktueller Vorgang abgeschlossen ist… %2$s für %1$s gespendet Erfolgreich %1$s aufgeladen - Ups, das hat nicht geklappt. Bitte Eingaben und Netzwerkverbindung überprüfen und erneut versuchen oder Hostname/Benutzername ändern um fortzufahren. - Benutzer bearbeiten + Ups, das hat nicht geklappt. Bitte Eingaben und Netzwerkverbindung überprüfen und erneut versuchen oder Hostname/Account ändern um fortzufahren. + Account bearbeiten Diese Aktion ist ungültig. @@ -77,10 +76,10 @@ Hostname ändern - Benutzer zurücksetzen - Mehrbenutzer-Modus - Mehrbenutzer-Modus aktiviert - Mehrbenutzer-Modus deaktiviert + Account zurücksetzen + Mehrpersonen-Modus + Mehrpersonen-Modus aktiviert + Mehrpersonen-Modus deaktiviert Kachelansicht Kachelansicht aktiviert Kachelansicht deaktiviert From 22c02d32d56d028e111d544fb169b238a0a989f9 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 9 Aug 2020 13:57:46 +0200 Subject: [PATCH 191/197] Update Android Gradle plugin to 4.0.1 --- meteroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 96d4a89..80a97a8 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -31,7 +31,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.2' + classpath 'com.android.tools.build:gradle:4.0.1' classpath 'com.github.spotbugs:spotbugs-gradle-plugin:3.0.0' } } From 1f70c9a120244c9bf43f426686c59247e15e4e3d Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Sun, 9 Aug 2020 14:02:46 +0200 Subject: [PATCH 192/197] Move dataBinding and viewBinding config The old location was deprecated. --- meteroid/build.gradle | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 80a97a8..0336ec1 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -69,11 +69,9 @@ android { lintOptions { abortOnError false } - dataBinding { - enabled = true - } - viewBinding { - enabled = true + buildFeatures { + dataBinding = true + viewBinding = true } defaultConfig { targetSdkVersion 29 From 60ba990befa2b13b9da11fa3a862466ccc4c9022 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 8 Mar 2021 17:38:45 +0100 Subject: [PATCH 193/197] Update Picasso --- meteroid/build.gradle | 2 +- .../src/main/java/de/chaosdorf/meteroid/util/Utility.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 0336ec1..fae6062 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -51,7 +51,7 @@ dependencies { implementation 'com.google.zxing:android-integration:3.3.0' implementation 'com.shamanland:fab:0.0.8' implementation 'com.android.support:support-core-ui:26.1.0' - implementation 'com.squareup.picasso:picasso:2.5.2' + implementation 'com.squareup.picasso:picasso:2.71828' } //see https://stackoverflow.com/a/22183825/2192464 diff --git a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java index f8d1755..fac67dd 100644 --- a/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java +++ b/meteroid/src/main/java/de/chaosdorf/meteroid/util/Utility.java @@ -126,7 +126,7 @@ private static void loadGravatarImage(final Activity activity, final ImageView i .appendPath(md5Hex(email)) .appendQueryParameter("d", "404") .build(); - Picasso.with(activity).load(uri).placeholder(R.drawable.default_user).into(icon); + Picasso.get().load(uri).placeholder(R.drawable.default_user).into(icon); } else { @@ -150,7 +150,7 @@ private static void loadBuyableItemImage_(final Activity activity, final ImageVi if (buyableItem.isDrink()) { uri = Uri.parse(buyableItem.getLogoUrl(hostname)); - Picasso.with(activity).load(uri).error(R.drawable.default_drink).into(icon); + Picasso.get().load(uri).error(R.drawable.default_drink).into(icon); return; } final int iconID = activity.getResources().getIdentifier(buyableItem.getLogoUrl(hostname), "drawable", activity.getPackageName()); From 5e0074f7daaaaba3fa855264640962720372ce46 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 8 Mar 2021 18:54:04 +0100 Subject: [PATCH 194/197] Target Android 11 --- .travis.yml | 2 +- meteroid/build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index dbb0429..2eb9dca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ android: - platform-tools - tools - build-tools-29.0.2 - - android-29 + - android-30 diff --git a/meteroid/build.gradle b/meteroid/build.gradle index fae6062..8352070 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -63,7 +63,7 @@ gradle.projectsEvaluated { } android { - compileSdkVersion 29 + compileSdkVersion 30 buildToolsVersion '29.0.2' signingConfigs {} lintOptions { @@ -74,7 +74,7 @@ android { viewBinding = true } defaultConfig { - targetSdkVersion 29 + targetSdkVersion 30 minSdkVersion 14 } } From 20ad08d79fbe6acaf70d9f1b3782a5236aa4bdcb Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 8 Mar 2021 19:08:36 +0100 Subject: [PATCH 195/197] Try to unify support version libraries Picasso depends on 27.1, the view binding depends on 26.1. --- meteroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meteroid/build.gradle b/meteroid/build.gradle index 8352070..3c1a541 100644 --- a/meteroid/build.gradle +++ b/meteroid/build.gradle @@ -50,7 +50,7 @@ dependencies { implementation 'com.squareup.retrofit2:converter-gson:2.6.4' implementation 'com.google.zxing:android-integration:3.3.0' implementation 'com.shamanland:fab:0.0.8' - implementation 'com.android.support:support-core-ui:26.1.0' + implementation 'com.android.support:support-core-ui:27.1.0' implementation 'com.squareup.picasso:picasso:2.71828' } From 2b71e36bed6913f5557f78a447c915f16766855a Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 8 Mar 2021 19:13:09 +0100 Subject: [PATCH 196/197] Update Gradle and wrapper to 6.8.3 --- gradle/wrapper/gradle-wrapper.jar | Bin 58694 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 ++ gradlew.bat | 22 ++++------------------ 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 490fda8577df6c95960ba7077c43220e5bb2c0d9..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 6763 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 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From 05fc8ed3bb387960c64e52047a7a63671e9ed052 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Tue, 9 Mar 2021 13:42:32 +0100 Subject: [PATCH 197/197] Bump version to 2.8.0 --- meteroid/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meteroid/src/main/AndroidManifest.xml b/meteroid/src/main/AndroidManifest.xml index 2cc39e6..a6f4bb0 100644 --- a/meteroid/src/main/AndroidManifest.xml +++ b/meteroid/src/main/AndroidManifest.xml @@ -25,8 +25,8 @@ + android:versionCode="40" + android:versionName="2.8.0">