diff --git a/app/build.gradle b/app/build.gradle index 10d7a63..66c7acc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "de.janl1.betteropelapp" minSdkVersion 26 targetSdkVersion 29 - versionCode 1 - versionName "1.0" + versionCode 2 + versionName "1.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -34,14 +34,13 @@ dependencies { implementation 'com.squareup.retrofit2:converter-gson:2.1.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1' implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'androidx.cardview:cardview:1.0.0' implementation 'com.google.android.gms:play-services-maps:17.0.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' diff --git a/app/src/main/java/de/janl1/betteropelapp/VehicleActivity.java b/app/src/main/java/de/janl1/betteropelapp/VehicleActivity.java index eab827b..f630b01 100644 --- a/app/src/main/java/de/janl1/betteropelapp/VehicleActivity.java +++ b/app/src/main/java/de/janl1/betteropelapp/VehicleActivity.java @@ -17,6 +17,7 @@ import android.view.View; import android.widget.Toast; +import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; @@ -52,12 +53,15 @@ protected void onCreate(Bundle savedInstanceState) { prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); apiInterface = ApiClient.getClient().create(TronityApi.class); - checkTokenExistanceAndExpiry(); + if (!isTokenStillValid()) { + requestToken(); + return; + } Call call1 = apiInterface.getVehicles("Bearer " + prefs.getString(Vars.PREF_AUTH_ACCESSTOKEN, "")); call1.enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(@NotNull Call call, @NotNull Response response) { if (response.isSuccessful()) { @@ -74,13 +78,13 @@ public void onResponse(Call call, Response call, Throwable t) { + public void onFailure(@NotNull Call call, @NotNull Throwable t) { Dialog.showErrorMessage(VehicleActivity.this, "Laden der Fahrzeugliste", t.getMessage()).show(); } }); } - private void checkTokenExistanceAndExpiry() + private boolean isTokenStillValid() { String accessToken = prefs.getString(Vars.PREF_AUTH_ACCESSTOKEN, ""); long expiresTimestamp = prefs.getLong(Vars.PREF_AUTH_EXPIRES, 0); @@ -95,14 +99,11 @@ private void checkTokenExistanceAndExpiry() if (accessToken.equals("") || expiresTimestamp == 0) { Toast.makeText(getBaseContext(), "Kein Token gefunden! Fordere neuen Token an!", Toast.LENGTH_SHORT).show(); - requestToken(); + return false; } long currentTimestamp = new Date().getTime() / 1000L; - if (currentTimestamp > expiresTimestamp) { - // Toast.makeText(getBaseContext(), "Token abgelaufen! Fordere neuen Token an!", Toast.LENGTH_SHORT).show(); - requestToken(); - } + return currentTimestamp <= expiresTimestamp; } private void requestToken() @@ -117,14 +118,17 @@ private void requestToken() Call call1 = apiInterface.auth(tokenRequestDTO); call1.enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { - - System.out.println("Request ist gelaufen!"); + public void onResponse(@NotNull Call call, @NotNull Response response) { if (response.isSuccessful()) { try { Token token = response.body(); + if (token == null) { + Dialog.showErrorMessage(VehicleActivity.this, "Parsen des Tokens", "Die von der Schnittstelle zurückgegebenen Daten sind leer!").show(); + return; + } + editor = prefs.edit(); editor.putString(Vars.PREF_AUTH_ACCESSTOKEN, token.access_token); editor.putLong(Vars.PREF_AUTH_EXPIRES, new JSONObject(new String(Base64.getDecoder().decode(token.access_token.split(Pattern.quote("."))[1]))).getLong("exp")); @@ -158,7 +162,7 @@ public void onResponse(Call call, Response response) { } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(@NotNull Call call, @NotNull Throwable t) { Dialog.showErrorMessage(VehicleActivity.this, "Authentifizierung", t.getMessage()).show(); } }); diff --git a/app/src/main/java/de/janl1/betteropelapp/listadapters/TripListArrayAdapter.java b/app/src/main/java/de/janl1/betteropelapp/listadapters/TripListArrayAdapter.java index 60d8d58..e4f584e 100644 --- a/app/src/main/java/de/janl1/betteropelapp/listadapters/TripListArrayAdapter.java +++ b/app/src/main/java/de/janl1/betteropelapp/listadapters/TripListArrayAdapter.java @@ -8,10 +8,13 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Locale; import de.janl1.betteropelapp.R; import de.janl1.betteropelapp.retrofit.objects.Trip; @@ -28,32 +31,51 @@ public TripListArrayAdapter(Context context, Trip[] values) { @Override public View getView(int position, View convertView, ViewGroup parent) { + + ViewHolder holder; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View rowView = inflater.inflate(R.layout.list_trips, parent, false); - TextView startDate = (TextView) rowView.findViewById(R.id.startDate); - TextView stopDate = (TextView) rowView.findViewById(R.id.stopDate); - TextView distance = (TextView) rowView.findViewById(R.id.distanceValue); - TextView consumption = (TextView) rowView.findViewById(R.id.consumptionValue); - TextView consumptionTotal = (TextView) rowView.findViewById(R.id.totalConsumptionValue); - TextView temperature = (TextView) rowView.findViewById(R.id.temperatureValue); + + if (convertView == null) { + + convertView = inflater.inflate(R.layout.list_trips, (ViewGroup) parent.getTag()); + holder = new ViewHolder(); + + holder.startDate = convertView.findViewById(R.id.startDate); + holder.stopDate = convertView.findViewById(R.id.stopDate); + holder.distance = convertView.findViewById(R.id.distanceValue); + holder.consumption = convertView.findViewById(R.id.consumptionValue); + holder.consumptionTotal = convertView.findViewById(R.id.totalConsumptionValue); + holder.temperature = convertView.findViewById(R.id.temperatureValue); + + convertView.setTag(holder); + + } else { + holder = (ViewHolder) convertView.getTag(); + } + Trip trip = values[position]; Date start = new Date((long)trip.startTime); Date end = new Date((long)trip.endTime); - startDate.setText(dateParsed(start)); - stopDate.setText(dateParsed(end)); - distance.setText(String.format("%s km", String.valueOf(Math.round(trip.distance * 1.609)))); - consumption.setText(String.format("%s kWh", String.valueOf(round(trip.usedkWh / (trip.distance * 1.609) * 100, 2)))); - consumptionTotal.setText(String.format("%s kWh", String.valueOf(round(trip.usedkWh, 2)))); - temperature.setText(String.format("%s *C", String.valueOf(trip.avgTemp))); + double consumptionValue = round(trip.usedkWh / (trip.distance * 1.609) * 100, 2); + if (consumptionValue < 0) { + consumptionValue = 0; + } + + holder.startDate.setText(dateParsed(start)); + holder.stopDate.setText(dateParsed(end)); + holder.distance.setText(String.format("%s km", Math.round(trip.distance * 1.609))); + holder.consumption.setText(String.format("%s kWh", consumptionValue)); + holder.consumptionTotal.setText(String.format("%s kWh", round(trip.usedkWh, 2))); + holder.temperature.setText(String.format("%s *C", trip.avgTemp)); - return rowView; + return convertView; } private String dateParsed(Date date) { - SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyy\nH:m"); + SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyy\nH:m", Locale.GERMANY); String format = formatter.format(date); return format + " Uhr"; } @@ -66,4 +88,13 @@ public static double round(double value, int places) { long tmp = Math.round(value); return (double) tmp / factor; } + + static class ViewHolder { + private TextView startDate; + private TextView stopDate; + private TextView distance; + private TextView consumption; + private TextView consumptionTotal; + private TextView temperature; + } } diff --git a/app/src/main/java/de/janl1/betteropelapp/ui/main/VehicleFragment.java b/app/src/main/java/de/janl1/betteropelapp/ui/main/VehicleFragment.java index c011ad0..e26e28a 100644 --- a/app/src/main/java/de/janl1/betteropelapp/ui/main/VehicleFragment.java +++ b/app/src/main/java/de/janl1/betteropelapp/ui/main/VehicleFragment.java @@ -22,7 +22,6 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.CameraUpdateFactory; @@ -68,7 +67,6 @@ public class VehicleFragment extends Fragment implements OnMapReadyCallback { MapView mapView; GoogleMap googleMap; - SwipeRefreshLayout swipeRefreshLayout; FloatingActionButton refreshFloatingButton; ProgressBar progressBar; @@ -124,15 +122,15 @@ public View onCreateView( progressBar = root.findViewById(R.id.progressBar); apiInterface = ApiClient.getClient().create(TronityApi.class); - prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - pageViewModel.getmVehicle().observe(getActivity(), veh -> loadBulkData(swipeRefreshLayout)); + pageViewModel.getmVehicle().observe(getActivity(), veh -> loadBulkData()); mapView = root.findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); mapView.getMapAsync(this); - refreshFloatingButton.setOnClickListener(v -> VehicleFragment.this.loadBulkData(swipeRefreshLayout)); + refreshFloatingButton.setOnClickListener(v -> VehicleFragment.this.loadBulkData()); // swipeRefreshLayout.setOnRefreshListener(() -> loadBulkData(swipeRefreshLayout)); return root; @@ -178,7 +176,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis public void onMapReady(GoogleMap googleMap) { googleMapIsReady = true; - if (ActivityCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Display a helptext before requesting permission! getActivity().requestPermissions(new String[] { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION }, PERMISSION_REQUEST_CODE); } else { @@ -190,7 +188,7 @@ public void onMapReady(GoogleMap googleMap) { loadMapData(); } - private void loadBulkData(SwipeRefreshLayout swipeRefreshLayout) + private void loadBulkData() { showLoadingSpinner(); Call bulkCall = apiInterface.getBulkInformation("Bearer " + prefs.getString(Vars.PREF_AUTH_ACCESSTOKEN, ""), vehicle.id); @@ -200,20 +198,23 @@ public void onResponse(@NotNull Call call, @NotNull Response respons Bulk vehicleInformation = response.body(); + if (vehicleInformation == null) { + Dialog.showErrorMessage(getActivity(), "Laden der Fahrzeuginformation", "Die von der Schnittstelle zurückgegebenen Daten sind leer!").show(); + hideLoadingSpinner(); + return; + } + if (response.isSuccessful()) { tvBatteryValue.setText(MessageFormat.format("{0} %", vehicleInformation.level)); tvDistanceValue.setText(MessageFormat.format("{0} km", vehicleInformation.range)); tvTotalDistanceValue.setText(MessageFormat.format("{0} km", vehicleInformation.odometer)); if (vehicleInformation.charging.equals("Charging")) { - - - - cardViewPercentage.setCardBackgroundColor(ContextCompat.getColor(getActivity().getBaseContext(), R.color.batteryStateCharging)); + cardViewPercentage.setCardBackgroundColor(ContextCompat.getColor(getActivity(), R.color.batteryStateCharging)); tvBatteryValue.setTextColor(ContextCompat.getColor(getActivity().getBaseContext(), android.R.color.background_light)); tvBatteryText.setTextColor(ContextCompat.getColor(getActivity().getBaseContext(), android.R.color.background_light)); } else { - cardViewPercentage.setCardBackgroundColor(ContextCompat.getColor(getActivity().getBaseContext(), android.R.color.background_light)); + cardViewPercentage.setCardBackgroundColor(ContextCompat.getColor(getActivity(), android.R.color.background_light)); tvBatteryValue.setTextColor(ContextCompat.getColor(getActivity().getBaseContext(), android.R.color.secondary_text_light)); tvBatteryText.setTextColor(ContextCompat.getColor(getActivity().getBaseContext(), android.R.color.secondary_text_light)); } @@ -234,19 +235,19 @@ public void onResponse(@NotNull Call call, @NotNull Response respons hideLoadingSpinner(); } else { - Dialog.showErrorMessage(getActivity().getApplicationContext(), "Laden der Fahrzeuginformation", response.code() + " " + response.message()).show(); + Dialog.showErrorMessage(getActivity(), "Laden der Fahrzeuginformation", response.code() + " " + response.message()).show(); hideLoadingSpinner(); } } @Override public void onFailure(@NotNull Call call, @NotNull Throwable t) { - Dialog.showErrorMessage(getActivity().getApplicationContext(), "Laden der Fahrzeuginformation", t.getMessage()).show(); + Dialog.showErrorMessage(getActivity(), "Laden der Fahrzeuginformation", t.getMessage()).show(); hideLoadingSpinner(); } }); - Call tripsCall = apiInterface.getTrips("Bearer " + prefs.getString(Vars.PREF_AUTH_ACCESSTOKEN, ""), "Metric", vehicle.id); + Call tripsCall = apiInterface.getTrips("Bearer " + prefs.getString(Vars.PREF_AUTH_ACCESSTOKEN, ""), "metric", vehicle.id); tripsCall.enqueue(new Callback() { @Override public void onResponse(@NotNull Call call, @NotNull Response response) { @@ -295,13 +296,13 @@ public void onResponse(@NotNull Call call, @NotNull Response googleMap.animateCamera(cameraUpdate); } else { - Dialog.showErrorMessage(getActivity().getApplicationContext(), "Laden der Fahrzeugposition", response.code() + " " + response.message()).show(); + Dialog.showErrorMessage(getActivity(), "Laden der Fahrzeugposition", response.code() + " " + response.message()).show(); } } @Override public void onFailure(@NotNull Call call, @NotNull Throwable t) { - Dialog.showErrorMessage(getActivity().getApplicationContext(), "Laden der Fahrzeugposition", t.getMessage()).show(); + Dialog.showErrorMessage(getActivity(), "Laden der Fahrzeugposition", t.getMessage()).show(); } }); } diff --git a/app/src/main/res/layout/list_trips.xml b/app/src/main/res/layout/list_trips.xml index bb96fb8..7b75bce 100644 --- a/app/src/main/res/layout/list_trips.xml +++ b/app/src/main/res/layout/list_trips.xml @@ -2,7 +2,6 @@ @@ -25,7 +24,7 @@ android:layout_marginTop="5dp" android:layout_marginEnd="5dp" android:layout_marginBottom="5dp" - android:text="21.11.2020\n21:24" + android:text="@string/triplistview_placeholder_end" android:textAlignment="center" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -39,7 +38,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="21.11.2020\n21:25" + android:text="@string/triplistview_placeholder_start" android:textAlignment="center" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -52,7 +51,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="bis" + android:text="@string/triplistview_placeholder_divider" android:textStyle="bold|italic" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -77,7 +76,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="Strecke" + android:text="@string/triplistview_text_distance" android:textStyle="bold|italic" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -90,7 +89,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="5 km" + android:text="@string/triplistview_placeholder_distance" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/distanceText" /> @@ -102,7 +101,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="Avg. Temp" + android:text="@string/triplistview_text_temperature" android:textStyle="bold|italic" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -116,7 +115,7 @@ android:layout_marginTop="5dp" android:layout_marginEnd="5dp" android:layout_marginBottom="5dp" - android:text="12 *C" + android:text="@string/triplistview_placeholder_temperature" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -141,7 +140,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="Ø Verbrauch" + android:text="@string/triplistview_text_consumption" android:textStyle="bold|italic" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -154,7 +153,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="14,4 kWh" + android:text="@string/triplistview_placeholder_consumption" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/consumptionText" /> @@ -166,7 +165,7 @@ android:layout_marginStart="5dp" android:layout_marginTop="5dp" android:layout_marginEnd="5dp" - android:text="Gesamtstrom" + android:text="@string/triplistview_text_totalconsumption" android:textStyle="bold|italic" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -180,7 +179,7 @@ android:layout_marginTop="5dp" android:layout_marginEnd="5dp" android:layout_marginBottom="5dp" - android:text="4 kWh" + android:text="@string/triplistview_placeholder_totalconsumption" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7583880..e8e5a9e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,4 +25,18 @@ -- km - km -- kWh + + --.--.----\n--:-- + --.--.----\n--:-- + bis + + -- km + -- kWh + -- *C + -- kW + + Strecke + Ø Verbrauch + Ø Temp. + Gesamtstrom \ No newline at end of file diff --git a/build.gradle b/build.gradle index 53524a2..04baf1e 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:4.1.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files