Browse Source

add, delete and partly update area

master
Felix Diemar 3 years ago
parent
commit
489fd26187
19 changed files with 1209 additions and 207 deletions
  1. 1
    0
      Code Android/meinWald/app/build.gradle
  2. 1
    2
      Code Android/meinWald/app/src/main/AndroidManifest.xml
  3. 0
    18
      Code Android/meinWald/app/src/main/java/com/example/meinwald/MyApplication.java
  4. 149
    26
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaAdapter.java
  5. 137
    57
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaFragment.java
  6. 2
    2
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/LocationService.java
  7. 247
    18
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/OwnArea.java
  8. 96
    9
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/map/MapsFragment.java
  9. 62
    0
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/OwnTask.java
  10. 153
    2
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TaskAdapter.java
  11. 33
    44
      Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TasksFragment.java
  12. 43
    4
      Code Android/meinWald/app/src/main/res/layout/area_element.xml
  13. 66
    9
      Code Android/meinWald/app/src/main/res/layout/area_input.xml
  14. 40
    5
      Code Android/meinWald/app/src/main/res/layout/area_management.xml
  15. 7
    2
      Code Android/meinWald/app/src/main/res/layout/image_large.xml
  16. 22
    6
      Code Android/meinWald/app/src/main/res/layout/task_element.xml
  17. 0
    2
      Code Android/meinWald/app/src/main/res/layout/task_input.xml
  18. 144
    0
      Code Android/meinWald/app/src/main/res/layout/task_management.xml
  19. 6
    1
      Code Android/meinWald/app/src/main/res/values/colors.xml

+ 1
- 0
Code Android/meinWald/app/build.gradle View File

@@ -39,5 +39,6 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
compile 'com.google.maps.android:android-maps-utils:0.6.2'

}

+ 1
- 2
Code Android/meinWald/app/src/main/AndroidManifest.xml View File

@@ -3,7 +3,6 @@
package="com.example.meinwald">

<application
android:name="com.example.meinwald.MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@@ -25,7 +24,7 @@
android:value="@string/google_maps_key" />

<service
android:name=".ui.area.LocationTrack"
android:name=".ui.area.LocationService"
android:exported="false">
</service>


+ 0
- 18
Code Android/meinWald/app/src/main/java/com/example/meinwald/MyApplication.java View File

@@ -1,18 +0,0 @@
package com.example.meinwald;

import android.app.Application;
import android.content.Context;

public class MyApplication extends Application {

private static Context context;

public void onCreate() {
super.onCreate();
MyApplication.context = getApplicationContext();
}

public static Context getAppContext() {
return MyApplication.context;
}
}

+ 149
- 26
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaAdapter.java View File

@@ -3,7 +3,8 @@ package com.example.meinwald.ui.area;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Rect;
import android.database.DataSetObserver;
import android.os.Build;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -16,23 +17,23 @@ import android.widget.Toast;

import com.example.meinwald.BuildConfig;
import com.example.meinwald.R;
import com.example.meinwald.ui.task.OwnTask;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import androidx.appcompat.widget.AlertDialogLayout;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.annotation.RequiresApi;
import androidx.constraintlayout.widget.ConstraintLayout;

import static java.security.AccessController.getContext;

public class AreaAdapter extends BaseAdapter
{
private final static String TAG = AreaAdapter.class.getSimpleName();

List<OwnArea> areaList;
LayoutInflater inflater;
Context context;
boolean deleted = false;
Integer deletedPosition = null;

public AreaAdapter(Context applicationContext, List<OwnArea> areaList)
{
@@ -49,30 +50,30 @@ public class AreaAdapter extends BaseAdapter
}

@Override
public View getView(final int i, View view, final ViewGroup viewGroup) {
public View getView(final int i, final View view, final ViewGroup viewGroup) {

view = inflater.inflate(R.layout.area_element, null);
final ConstraintLayout elementView = view.findViewById(R.id.areaElement);
final ConstraintLayout infovView = view.findViewById(R.id.areaInfoView);
final TextView title = (TextView) view.findViewById(R.id.areaInfoTitle);
final TextView notice = (TextView) view.findViewById(R.id.areaInfoNotice);
final ImageView icon = (ImageView) view.findViewById(R.id.areaIcon);
final ImageView manageArea = (ImageView) view.findViewById(R.id.areaManageArea);
final View areaView = inflater.inflate(R.layout.area_element, null);
final ConstraintLayout elementView = areaView.findViewById(R.id.areaElement);
final ConstraintLayout infovView = areaView.findViewById(R.id.areaInfoView);
final TextView title = (TextView) areaView.findViewById(R.id.areaInfoTitle);
final TextView notice = (TextView) areaView.findViewById(R.id.areaInfoNotice);
final TextView area = (TextView) areaView.findViewById(R.id.areaInfoArea);
final ImageView icon = (ImageView) areaView.findViewById(R.id.areaIcon);
final ImageView manageArea = (ImageView) areaView.findViewById(R.id.areaManageArea);

context = view.getContext();

if (BuildConfig.DEBUG)
{
Log.d("AreaAdapter",areaList.get(i).toString());
Log.d("AreaAdapter",areaList.get(i).getTitle());
Log.d("AreaAdapter",areaList.get(i).getNotice());
}
context = areaView.getContext();

title.setText(areaList.get(i).getTitle());
notice.setText(areaList.get(i).getNotice());
icon.setImageBitmap(areaList.get(i).getImage());

if (areaList.get(i).getArea() != null)
{
area.setText(String. format("%.2f", areaList.get(i).getArea()) + " Quadratmeter");
}

manageArea.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onClick(View v)
{
@@ -80,22 +81,38 @@ public class AreaAdapter extends BaseAdapter
final View viewInflated = LayoutInflater.from(v.getRootView().getContext()).inflate(R.layout.area_management, viewGroup, false);

builder.setView(viewInflated);
builder.setCancelable(true);

//get elements
TextView title = viewInflated.findViewById(R.id.areaManageTitle);
final TextView notice = viewInflated.findViewById(R.id.areaManageNotice);
TextView gpscount = viewInflated.findViewById(R.id.areaManageGPSPoints);
ImageView image = (ImageView) viewInflated.findViewById(R.id.areaManageImage);
final TextView lastChecked = viewInflated.findViewById(R.id.areaManagementLastChecked);

ImageView newNotice = (ImageView) viewInflated.findViewById(R.id.areaManageNewDescription);
ImageView newGPS = (ImageView) viewInflated.findViewById(R.id.areaManageNewGPS);
ImageView newImage = (ImageView) viewInflated.findViewById(R.id.areaManageNewImage);
ImageView deleteArea = (ImageView) viewInflated.findViewById(R.id.areaManageDeleteArea);
ImageView newDate = (ImageView) viewInflated.findViewById(R.id.areaManageNewDate);

//set current vlues
//set current values
title.setText(areaList.get(i).getTitle());
notice.setText(areaList.get(i).getNotice());
gpscount.setText(String.valueOf(areaList.get(i).getLocations().size()));
if (areaList.get(i).getCheckHistory() != null)
{
lastChecked.setText(areaList.get(i).parseAndFormatLastCheckUpdate());
}

if (areaList.get(i).getLocations() != null)
{
gpscount.setText(String.valueOf(areaList.get(i).getLocations().size()));
}
else
{
gpscount.setText(String.valueOf(0));
}


if (areaList.get(i).getImage() != null)
{
@@ -112,6 +129,7 @@ public class AreaAdapter extends BaseAdapter
newbuilder.setView(viewInflated);

final TextView noticeView = viewInflated.findViewById(R.id.areaManagementNoticeUserInput);
noticeView.setText(areaList.get(i).getNotice());

newbuilder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
@@ -133,12 +151,108 @@ public class AreaAdapter extends BaseAdapter
newbuilder.show();
}});

newDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final AlertDialog.Builder newbuilder = new AlertDialog.Builder(v.getRootView().getContext());

newbuilder.setTitle("Neu Kontrolle hinzufügen?");

newbuilder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
areaList.get(i).addCheckDate(new Date());
lastChecked.setText(areaList.get(i).parseAndFormatLastCheckUpdate());

//notifyDataSetChanged();

if (BuildConfig.DEBUG) {
for (OwnArea area : areaList) {
Log.d(TAG, "areaList item: " + area.toString());
}
}

dialog.dismiss();
}
});

newbuilder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});

newbuilder.show();
}});

deleteArea.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
final AlertDialog.Builder newbuilder = new AlertDialog.Builder(v.getRootView().getContext());

newbuilder.setTitle("Das Grundstück wirklich löschen?");

newbuilder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {

areaList.get(i).deleteFromExternalStorage(context);
areaList.remove(i);

notifyDataSetChanged();

if (BuildConfig.DEBUG)
{
for (OwnArea area: areaList)
{
Log.d(TAG, "areaList item: " + area.toString());
}
}

dialog.dismiss();

((ViewGroup)viewInflated.getParent()).removeView(viewInflated);
builder.show().cancel();
}
});

newbuilder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});

newbuilder.show();
}});



builder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {

if (areaList.size() > i && areaList.get(i) != null)
{
if (BuildConfig.DEBUG)
{
Log.d(TAG, "update area: " + areaList.get(i).toString());
}
areaList.get(i).deleteFromExternalStorage(context);
areaList.get(i).writeToExternalStorage(context);
}

if (BuildConfig.DEBUG)
{
for (OwnArea area: areaList)
{
Log.d(TAG, "areaList item: " + area.toString());
}
}

dialog.dismiss();

}
});

@@ -194,7 +308,16 @@ public class AreaAdapter extends BaseAdapter
}
});

return view;
return areaView;
}

public boolean isDeleted() {
return deleted;
}

public Integer getDeletedPosition()
{
return deletedPosition;
}

@Override

+ 137
- 57
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaFragment.java View File

@@ -5,6 +5,8 @@ import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.database.DataSetObserver;
import android.location.Location;
import android.os.Bundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
@@ -28,7 +30,10 @@ import com.example.meinwald.BuildConfig;
import com.example.meinwald.R;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

import org.json.JSONArray;
@@ -66,6 +71,11 @@ public class AreaFragment extends Fragment {
* LOCATION
*/
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
/**
* The geographical location where the device is currently located.
* That is the last-known location retrieved by the Fused Location Provider.
*/
private Location mLastKnownLocation;
/**
* The entry point to the Fused Location Provider.
*/
@@ -124,6 +134,10 @@ public class AreaFragment extends Fragment {

//get saved areas
allAreas = loadAreasFromPreferences();
for (int i = 0; i < allAreas.size(); i++)
{
allAreas.get(i).setPathFile(areaReferences.get(i).getPath());
}
instantiateAreasList();

PowerManager powerManager = (PowerManager) getContext().getSystemService(POWER_SERVICE);
@@ -144,13 +158,14 @@ public class AreaFragment extends Fragment {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());

newArea = new OwnArea();
newPositions = new ArrayList<>();

final View viewInflated = LayoutInflater.from(getContext()).inflate(R.layout.area_input, (ViewGroup) getView(), false);
builder.setView(viewInflated);

final Button startTracking = viewInflated.findViewById(R.id.areaStartTracking);
final Button stopTracking = viewInflated.findViewById(R.id.areaStopTracking);
final Button addLocation = viewInflated.findViewById(R.id.areaAddGPSPoint);

startTracking.setOnClickListener(new View.OnClickListener() {
@Override
@@ -161,6 +176,7 @@ public class AreaFragment extends Fragment {

startTracking.setVisibility(View.INVISIBLE);
stopTracking.setVisibility(View.VISIBLE);
addLocation.setVisibility(View.INVISIBLE);
}
});

@@ -169,21 +185,35 @@ public class AreaFragment extends Fragment {
public void onClick(View view) {

//stop tracking
newPositions = gps.getPositions();
List<LatLng> positionsToAdd = new ArrayList<>();
positionsToAdd = gps.getPositions();

for (LatLng pos: positionsToAdd)
{
newPositions.add(pos);
}

if (BuildConfig.DEBUG)
{
Log.d(TAG, "Received locations: " + newPositions.size());
}

newArea.setLocations(newPositions);
wakeLock.release();

startTracking.setVisibility(View.VISIBLE);
stopTracking.setVisibility(View.INVISIBLE);
addLocation.setVisibility(View.VISIBLE);
}
});

addLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

//get last known location
getDeviceLocation();
}});

builder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@@ -200,6 +230,8 @@ public class AreaFragment extends Fragment {
//save user input
newArea.setTitle(String.valueOf(titleView.getText()));
newArea.setNotice(String.valueOf(noticeView.getText()));
newArea.setLocations(newPositions);
newArea.calculateArea();

boolean result = allAreas.add(newArea);

@@ -209,9 +241,10 @@ public class AreaFragment extends Fragment {
Log.d(TAG, "add new task result: " + result);
}

emptyPreferencesAndSaveAreaReferencesToPreferences();
newArea.writeToExternalStorage(getContext());
areaReferences.add(new AreaReference(newArea.getId(), newArea.getPathFile()));

areaReferences.add(new AreaReference(newArea.getId(), writeAreaToExternalStorage(newArea)));
emptyPreferencesAndSaveAreaReferencesToPreferences();

//actuate list
instantiateAreasList();
@@ -245,7 +278,12 @@ public class AreaFragment extends Fragment {

builder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
public void onClick(DialogInterface dialog, int which)
{
//reset variables
newArea = new OwnArea();
newPositions = new ArrayList<>();

dialog.cancel();
}
});
@@ -262,6 +300,39 @@ public class AreaFragment extends Fragment {
public void instantiateAreasList()
{
final AreaAdapter adapter = new AreaAdapter(getActivity().getApplicationContext(), allAreas);
adapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();

if (BuildConfig.DEBUG)
{
Log.d(TAG, "onChanged");
}

if (BuildConfig.DEBUG)
{
Log.d(TAG, "dataset size: " + areaList.getAdapter().getCount());
}

if (areaList.getAdapter().getCount() > 0)
{
allAreas = new ArrayList<>();
areaReferences =new ArrayList<>();

for (int i = 0; i < areaList.getAdapter().getCount(); i++)
{
allAreas.add((OwnArea) areaList.getAdapter().getItem(i));
if (BuildConfig.DEBUG)
{
Log.d(TAG, "dataset added: " + allAreas.get(i).toString());
}

areaReferences.add(new AreaReference(allAreas.get(i).getId(), allAreas.get(i).getPathFile()));
}
}
}
});
areaList.setAdapter(adapter);

//initialise onClickListeners
@@ -319,55 +390,6 @@ public class AreaFragment extends Fragment {
return areas;
}

/**
* Save OwnArea object in textfile on external storage.
*
* @param newArea OwnArea object to write to file.
* @return
*/
private String writeAreaToExternalStorage(OwnArea newArea){

if (BuildConfig.DEBUG)
{
Log.d(TAG, "writeAreaToExternalStorage()");
}

// Find the root of the external storage.
File root = android.os.Environment.getExternalStorageDirectory();

//create file if it does not exist
File path = new File (getContext().getFilesDir(), "meinWald" + File.pathSeparator + "areas");
if(!path.exists()){
path.mkdirs();
if (BuildConfig.DEBUG)
{
Log.d(TAG, "Create new text file: " + path);
}
}
File file = new File(path, newArea.getId() + ".txt");

//open file and write to it
try {
FileOutputStream f = new FileOutputStream(file);
PrintWriter pw = new PrintWriter(f);
pw.print(areaToString(newArea));
pw.close();
f.close();
} catch (FileNotFoundException e) {
if (BuildConfig.DEBUG)
{
Log.e(TAG, "Failed write to external storage: " + e.toString());
}
} catch (IOException e) {
if (BuildConfig.DEBUG)
{
Log.e(TAG, "Failed write to external storage: " + e.toString());
}
}

return file.getPath();
}

/**
* Read OwnArea from file in external storage and return as a string.
*
@@ -393,6 +415,10 @@ public class AreaFragment extends Fragment {

while ((line = br.readLine()) != null) {
text.append(line);
if (BuildConfig.DEBUG)
{
Log.d(TAG, "Line: " + line);
}
}
br.close();
}
@@ -438,8 +464,19 @@ public class AreaFragment extends Fragment {
String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_AREA_REFERENCES, "error");
if(!"error".equalsIgnoreCase(jsonString)) {
JSONArray jsonObjects = new JSONArray(jsonString);
for (int i = 0; i<jsonObjects.length();i++) {
for (int i = 0; i<jsonObjects.length();i++)
{
areas.add(new AreaReference(jsonObjects.getJSONObject(i)));

// Find the root of the external storage.
File root = android.os.Environment.getExternalStorageDirectory();

//delete reference if file does not exist
File file = new File(getContext().getFilesDir(), "meinWald" + File.pathSeparator + "areas" + File.pathSeparator + areas.get(i).getId() + ".txt");
if(file.exists())
{
areas.remove(i);
}
}
}
else
@@ -468,7 +505,7 @@ public class AreaFragment extends Fragment {
}

/**
* Saves epicolors to preferences
* Saves areas to preferences
*/
private void emptyPreferencesAndSaveAreaReferencesToPreferences()
{
@@ -562,6 +599,49 @@ public class AreaFragment extends Fragment {

}

/**
* Get the best and most recent location of the device, which may be null in rare
* cases when a location is not available.
*
*/
private void getDeviceLocation() {
try {
if (mLocationPermissionGranted) {
Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener<Location>() {
@Override
public void onComplete(@NonNull Task<Location> task) {
if (task.isSuccessful())
{
// Set the last known position to the current location of the device and add to tracking stack
mLastKnownLocation = task.getResult();
newPositions.add(new LatLng(mLastKnownLocation.getLatitude(),mLastKnownLocation.getLongitude()));

if (BuildConfig.DEBUG) {

if (task.getResult() != null)
{
Log.d(TAG, "getDeviceLocation: " + task.getResult().toString());
Log.d(TAG, "Size: " + newPositions.size());
}
}
} else {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Current location is null. Using defaults.");
Log.e(TAG, "Exception: %s", task.getException());
}
}
}
});
}
} catch (SecurityException e) {
if (BuildConfig.DEBUG) {
Log.e(TAG, "Exception occurred: ");
e.printStackTrace();
}
}
}

public void startLocationTracking(){

final Runnable runnable= new Runnable() {

+ 2
- 2
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/LocationService.java View File

@@ -53,7 +53,7 @@ public class LocationService extends Service implements LocationListener {
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1; // 5 meters

// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 5 * 1; // 5 seconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 1 * 1; // 5 seconds

// Declaring a Location Manager
protected LocationManager mLocationManager;
@@ -268,7 +268,7 @@ public class LocationService extends Service implements LocationListener {
Log.d(TAG, "onLocationChanged(), new location: " + location.toString());
}

positions.add(new LatLng(location.getLatitude(), getLongitude()));
positions.add(new LatLng(location.getLatitude(), location.getLongitude()));
}

@Override

+ 247
- 18
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/OwnArea.java View File

@@ -1,18 +1,25 @@
package com.example.meinwald.ui.area;

import android.content.Context;
import android.graphics.Bitmap;
import android.location.Location;
import android.util.Log;

import com.example.meinwald.BuildConfig;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.SphericalUtil;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.sql.Time;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@@ -23,8 +30,10 @@ public class OwnArea {
private List<LatLng> locations;
private Bitmap image;
private String pathImage;
private String pathLocations;
private String pathFile;
private String id;
private List<Date> checkHistory;
private Double area;

public void setImage(Bitmap image) {
this.image = image;
@@ -47,8 +56,21 @@ public class OwnArea {
this.pathImage = pathImage;
}

public void setPathLocations(String pathLocations) {
this.pathLocations = pathLocations;
public void setPathFile(String pathFile) {
this.pathFile = pathFile;
}

public Double getArea() {
return area;
}

public void setArea(Double area) {
this.area = area;
}

public void calculateArea()
{
this.area = SphericalUtil.computeArea(this.locations);
}

public String getNotice() {
@@ -75,16 +97,49 @@ public class OwnArea {
return pathImage;
}

public String getPathLocations() {
return pathLocations;
public String getPathFile() {
return pathFile;
}

public OwnArea()
public List<Date> getCheckHistory() {
return checkHistory;
}

public void setCheckHistory(List<Date> checkHistory) {
this.checkHistory = checkHistory;
}

public void addCheckDate(Date newDate)
{
if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "add DATE");
}
if(this.checkHistory == null)
{
this.checkHistory = new ArrayList<>();
}

this.checkHistory.add(newDate);
}

public OwnArea()
{
this.title = null;
this.id = null;
this.notice = null;
this.pathFile = null;
this.image = null;
this.pathImage = null;
this.locations = new ArrayList<>();
this.checkHistory = new ArrayList<>();
}

public OwnArea(String jsonString){
public OwnArea(String jsonString)
{
this.checkHistory = new ArrayList<>();
this.locations = new ArrayList<>();

try {
JSONObject areaObject = new JSONObject(jsonString);
this.title = areaObject.getString("title");
@@ -104,6 +159,24 @@ public class OwnArea {
}
}

String historyString = areaObject.getString("history");
JSONArray history = new JSONArray(historyString);
this.checkHistory = new ArrayList<>();

for (int i = 0; i<history.length();i++) {
this.checkHistory.add(new Date(history.getJSONObject(i).getLong("date")));

if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "read location: " + this.checkHistory.get(i).toString());
}
}

if (this.locations != null && this.locations.size()>2)
{
calculateArea();
}

} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(this.getClass().getSimpleName(), "area json: " + jsonString);
@@ -124,6 +197,85 @@ public class OwnArea {
return id;
}

/**
* Save OwnArea object in textfile on external storage.
*
* @return
*/
public void writeToExternalStorage(Context context){

if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "writeAreaToExternalStorage()");
}

// Find the root of the external storage.
File root = android.os.Environment.getExternalStorageDirectory();

//create file if it does not exist
File path = new File (context.getFilesDir(), "meinWald" + File.pathSeparator + "areas");
if(!path.exists()){
path.mkdirs();
if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "Create new text file: " + path);
}
}
File file = new File(path, this.getId() + ".txt");

//open file and write to it
try {
FileOutputStream f = new FileOutputStream(file);
PrintWriter pw = new PrintWriter(f);
pw.print(this.toJSONObject());
if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "Json to write in file: " + this.toJSONObject().toString());
}
pw.close();
f.close();
} catch (FileNotFoundException e) {
if (BuildConfig.DEBUG)
{
Log.e(getClass().getSimpleName(), "Failed write to external storage: " + e.toString());
}
} catch (IOException e) {
if (BuildConfig.DEBUG)
{
Log.e(getClass().getSimpleName(), "Failed write to external storage: " + e.toString());
}
}

this.pathFile = file.getPath();
}

/**
* Delete OwnArea object textfile from external storage.
*/
public void deleteFromExternalStorage(Context context)
{
if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "deleteFromExternalStorage()");
}

// Find the root of the external storage.
File root = android.os.Environment.getExternalStorageDirectory();

//delete file if exists
File file = new File(context.getFilesDir(), "meinWald" + File.pathSeparator + "areas" + File.pathSeparator + this.getId() + ".txt");
if(!file.exists()){

file.delete();

if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "Delete text file: " + file.getPath());
}
}

}


/**
* Returns OwnArea as JSONObject.
@@ -140,27 +292,71 @@ public class OwnArea {
//convert all locations
JSONArray writeObjects = new JSONArray();

for (LatLng location: this.locations) {
if (BuildConfig.DEBUG) {
Log.d("OwnArea", "Save locations, locations size: " + locations.size());
}

JSONObject singleLocationObject = new JSONObject();
singleLocationObject.put("Lat", location.latitude);
singleLocationObject.put("Lng", location.longitude);
if (this.locations != null && this.locations.size() > 0)
{
for (LatLng location: this.locations) {

writeObjects.put(singleLocationObject);
JSONObject singleLocationObject = new JSONObject();
singleLocationObject.put("Lat", location.latitude);
singleLocationObject.put("Lng", location.longitude);

if (BuildConfig.DEBUG) {
Log.d("OwnArea", "added location object: " + singleLocationObject.toString());
writeObjects.put(singleLocationObject);

if (BuildConfig.DEBUG) {
Log.d("OwnArea", "added location object: " + singleLocationObject.toString());
}
}
}

object.put("locations", writeObjects.toString());

//convert all locations
writeObjects = new JSONArray();

if (BuildConfig.DEBUG) {
Log.d("OwnArea", "Save history, history size: " + checkHistory.size());
}

if (this.checkHistory != null && this.checkHistory.size() > 0)
{
if (BuildConfig.DEBUG) {
Log.d("OwnArea", "history not empty");
}

for (Date date : this.checkHistory) {

JSONObject singleHistoryObject = new JSONObject();
singleHistoryObject.put("date", date.getTime());

writeObjects.put(singleHistoryObject);

if (BuildConfig.DEBUG) {
Log.d("OwnArea", "added history object: " + singleHistoryObject.toString());
}
}
}

object.put("history", writeObjects.toString());

if (area!=null)
{
object.put("area",this.area);
}
else
{
object.put("area", null);
}

return object;

} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(this.getClass().getSimpleName(),
String.format("Error while parsing epiColorDto to JSONObject. Values of epiColorDto: %s", this.toString()));
String.format("Error while parsing OwnArea to JSONObject. Values of OwnArea: %s", this.toString()));
}
return null;
}
@@ -172,8 +368,41 @@ public class OwnArea {
"title='" + title + '\'' +
", notice='" + notice + '\'' +
", pathImage='" + pathImage + '\'' +
", pathLocations='" + pathLocations + '\'' +
", pathLocations='" + pathFile + '\'' +
", id='" + id + '\'' +
", dates='" + checkHistory.size() + '\'' +
'}';
}

/**
* Parses last check update from milliseconds to string and formats it to "dd.MM.yyyy hh:mm".
*
* @return date parsed and mapped as string representation
*/
public String parseAndFormatLastCheckUpdate() {
SimpleDateFormat formatter = new SimpleDateFormat( "dd.MM.yyyy kk:mm");
Calendar calendar = Calendar.getInstance();
if (checkHistory != null && checkHistory.size()> 0)
{
calendar.setTimeInMillis(this.checkHistory.get(this.checkHistory.size()-1).getTime());
}
else
{
return "Keine Kontrolle vorhanden!";
}

return formatter.format(calendar.getTime());
}

public Long getLastChecked()
{
if (checkHistory != null && checkHistory.size()> 0)
{
return this.checkHistory.get(this.checkHistory.size()-1).getTime();
}
else
{
return (long) -1;
}
}
}

+ 96
- 9
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/map/MapsFragment.java View File

@@ -4,6 +4,7 @@ import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
@@ -13,12 +14,14 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.Toast;

import com.example.meinwald.BuildConfig;
import com.example.meinwald.R;
import com.example.meinwald.ui.area.AreaReference;
import com.example.meinwald.ui.area.OwnArea;
import com.example.meinwald.ui.task.OwnTask;
import com.google.android.gms.common.util.Hex;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
@@ -29,11 +32,15 @@ import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.maps.android.SphericalUtil;

import org.json.JSONArray;
import org.json.JSONException;
@@ -43,6 +50,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import androidx.annotation.NonNull;
@@ -152,13 +160,31 @@ public class MapsFragment extends Fragment implements OnMapReadyCallback {
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity());

//wait for map is ready
mapFragment.getMapAsync(new OnMapReadyCallback() {
mapFragment.getMapAsync(new OnMapReadyCallback()
{
@Override
public void onMapReady(GoogleMap googleMap) {
//save map instance locally
mMap = googleMap;
//set max zoom level
mMap.setMaxZoomPreference(MAX_ZOOM);
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {

if (mMap.getCameraPosition().zoom < 17.5)
{
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(marker.getPosition().latitude, marker.getPosition().longitude),(float)17.5));
}
else
{
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(marker.getPosition().latitude, marker.getPosition().longitude),mMap.getCameraPosition().zoom));
}

return false;
}
});

//retrieve saved instance state
mCameraPosition = parseCameraPosition(PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_CAMERA_POSITION, new CameraPosition(new LatLng(45.0,11.0), (float) 1.0, (float) 0.0,(float) 0.0).toString()));
@@ -198,21 +224,33 @@ public class MapsFragment extends Fragment implements OnMapReadyCallback {
{
for (OwnArea area: allAreas)
{

PolylineOptions options = new PolylineOptions().clickable(true);

for (LatLng location: area.getLocations())
if (area.getLocations() != null && area.getLocations().size()>0)
{
options.add(location);
PolygonOptions options = new PolygonOptions().clickable(true);

if (BuildConfig.DEBUG)
{
Log.d(TAG, "Position: " + location.toString());
Log.d(TAG, "Color: " + getAreaColor(area.getLastChecked()));
Log.d(TAG, "Color: " + String.valueOf(getAreaColor(area.getLastChecked() & 0x00FFFFFF) | 0x60000000));
Log.d(TAG, "Area: " + SphericalUtil.computeArea(area.getLocations()));
}
options.strokeColor(getAreaColor(area.getLastChecked()));
options.fillColor((options.getStrokeColor() & 0x00FFFFFF) | 0x60000000);

for (LatLng location: area.getLocations())
{
options.add(location);

if (BuildConfig.DEBUG)
{
Log.d(TAG, "Position: " + location.toString());
}
}
}

Polyline polyline1 = mMap.addPolyline(options);
options.add(area.getLocations().get(0));

mMap.addPolygon(options);
}
}
}

@@ -503,6 +541,55 @@ public class MapsFragment extends Fragment implements OnMapReadyCallback {
drawAreas();
}

/**
* Decides color of area based on the time passed since last ckeck update.
*
* @param time difference in milliseconds between last check and now
* @return color number
*/
private int getAreaColor(long time) {
//set transparency related to time difference
if(time > -1)
{
long timeDiff = new Date().getTime() - time;

//less than a week
if (timeDiff < 7*24*60*60*1000L)
{
return Color.parseColor("#57a639");
}
//less than two weeks
else if (timeDiff < 14*24*60*60*1000L)
{
return Color.parseColor("#819b45");
}
//less than three weeks
else if (timeDiff < 21*24*60*60*1000L)
{
return Color.parseColor("#d3d30c");
}
//less than four weeks
else if (timeDiff < 28*24*60*60*1000L)
{
return Color.parseColor("#df9600");
}
//less than 6 weeks
else if (timeDiff < 42*24*60*60*1000L)
{
return Color.parseColor("#df3d00");
}
//longer than four weeks
else
{
return Color.parseColor("#f70000");
}
}
else
{
return Color.parseColor("#f70000");
}
}

/**
* Request read external storage permission, so that we can get saved images from external storage.
* The result of the permission request is handled by a callback,

+ 62
- 0
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/OwnTask.java View File

@@ -1,5 +1,6 @@
package com.example.meinwald.ui.task;

import android.content.Context;
import android.graphics.Bitmap;
import android.location.Location;
import android.media.Image;
@@ -11,6 +12,10 @@ import com.google.android.gms.maps.model.LatLng;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

public class OwnTask
@@ -129,6 +134,63 @@ public class OwnTask

public void setPathImage(String pathImage) { this.pathImage = pathImage; }

public String saveImageToExternalStorage(Context context){

File path = null;

try {
path = new File(context.getFilesDir(), "meinWald" + File.separator + "Images");
if(!path.exists()){
path.mkdirs();
}

if (BuildConfig.DEBUG) {
Log.d(this.getClass().getSimpleName(), "Image file path: " + path);
}

File outFile = new File(path, this.id + ".jpeg");
if (!outFile.exists())
{
FileOutputStream outputStream = new FileOutputStream(outFile);
this.image.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.close();
}

} catch (FileNotFoundException e) {
Log.e(this.getClass().getSimpleName(), "Saving received message failed with", e);
} catch (IOException e) {
Log.e(this.getClass().getSimpleName(), "Saving received message failed with", e);
}

return path.toString();
}

/**
* Delete OwnArea object textfile from external storage.
*/
public void deleteFromExternalStorage(Context context)
{
if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "deleteFromExternalStorage()");
}

// Find the root of the external storage.
File root = android.os.Environment.getExternalStorageDirectory();

//delete file if exists
File file = new File(context.getFilesDir(), "meinWald" + File.pathSeparator + "Images" + File.pathSeparator + this.getId() + ".txt");
if(!file.exists()){

file.delete();

if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "Delete image file: " + file.getPath());
}
}
}

@Override
public String toString() {
return "OwnTask{" +

+ 153
- 2
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TaskAdapter.java View File

@@ -4,6 +4,7 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -14,12 +15,14 @@ import android.widget.TextView;

import com.example.meinwald.BuildConfig;
import com.example.meinwald.R;
import com.example.meinwald.ui.area.AreaAdapter;
import com.example.meinwald.ui.area.OwnArea;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.RequiresApi;
import androidx.appcompat.widget.AlertDialogLayout;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.constraintlayout.widget.ConstraintLayout;
@@ -28,6 +31,8 @@ import static java.security.AccessController.getContext;

public class TaskAdapter extends BaseAdapter
{
private final static String TAG = TaskAdapter.class.getSimpleName();

List<OwnTask> taskList;
LayoutInflater inflater;
Context context;
@@ -56,6 +61,7 @@ public class TaskAdapter extends BaseAdapter
final TextView title = (TextView) view.findViewById(R.id.taskInfoTitle);
final TextView notice = (TextView) view.findViewById(R.id.taskInfoNotice);
final ImageView icon = (ImageView) view.findViewById(R.id.taskIcon);
final ImageView manageTask = (ImageView) view.findViewById(R.id.taskManageTask);
context = view.getContext();


@@ -89,6 +95,147 @@ public class TaskAdapter extends BaseAdapter
}
});

manageTask.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onClick(View v)
{
final AlertDialog.Builder builder = new AlertDialog.Builder(v.getRootView().getContext());
final View viewInflated = LayoutInflater.from(v.getRootView().getContext()).inflate(R.layout.area_management, viewGroup, false);

builder.setView(viewInflated);

//get elements
TextView title = viewInflated.findViewById(R.id.areaManageTitle);
final TextView notice = viewInflated.findViewById(R.id.areaManageNotice);
TextView gps = viewInflated.findViewById(R.id.areaManageGPSPoints);
ImageView image = (ImageView) viewInflated.findViewById(R.id.areaManageImage);

ImageView newNotice = (ImageView) viewInflated.findViewById(R.id.areaManageNewDescription);
ImageView newGPS = (ImageView) viewInflated.findViewById(R.id.areaManageNewGPS);
ImageView newImage = (ImageView) viewInflated.findViewById(R.id.areaManageNewImage);
ImageView deleteArea = (ImageView) viewInflated.findViewById(R.id.areaManageDeleteArea);

//set current vlues
title.setText(taskList.get(i).getTitle());
notice.setText(taskList.get(i).getNotice());

if (taskList.get(i).getLocation() != null)
{
gps.setText(String.valueOf(taskList.get(i).getLocation()));
}
else
{
gps.setText("Kein Standort gespeichert!");
}

if (taskList.get(i).getImage() != null)
{
image.setImageBitmap(taskList.get(i).getImage());
}

newNotice.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
final AlertDialog.Builder newbuilder = new AlertDialog.Builder(v.getRootView().getContext());
final View viewInflated = LayoutInflater.from(v.getRootView().getContext()).inflate(R.layout.area_management_notice, viewGroup, false);

newbuilder.setView(viewInflated);

final TextView noticeView = viewInflated.findViewById(R.id.areaManagementNoticeUserInput);

newbuilder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {

taskList.get(i).setNotice(noticeView.getText().toString());
notice.setText(taskList.get(i).getNotice());
dialog.dismiss();
}
});

newbuilder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});

newbuilder.show();
}});

deleteArea.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final AlertDialog.Builder newbuilder = new AlertDialog.Builder(v.getRootView().getContext());

newbuilder.setTitle("Das Grundstück wirklich löschen?");

newbuilder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {

taskList.get(i).deleteFromExternalStorage(context);
taskList.remove(i);

notifyDataSetChanged();

if (BuildConfig.DEBUG)
{
for (OwnTask task: taskList)
{
Log.d(TAG, "areaList item: " + task.toString());
}
}

dialog.dismiss();
}
});

newbuilder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});

newbuilder.show();
}});

builder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {

if (taskList.size()-1 > i && taskList.get(i) != null)
{
taskList.get(i).deleteFromExternalStorage(context);
taskList.get(i).saveImageToExternalStorage(context);
}

if (BuildConfig.DEBUG)
{
for (OwnTask task: taskList)
{
Log.d(TAG, "areaList item: " + task.toString());
}
}

dialog.dismiss();
}
});

builder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});

builder.show();
}
});

icon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
@@ -104,8 +251,12 @@ public class TaskAdapter extends BaseAdapter
final ConstraintLayout imageViewLayout = viewInflated.findViewById(R.id.taskLargeImageLayout);
final ImageView imageView = viewInflated.findViewById(R.id.taskLargeImage);

//ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(taskList.get(i).getImage().getWidth(),5 * taskList.get(i).getImage().getHeight());
//imageViewLayout.setLayoutParams(layoutParams);
Log.d("TaskAdapter", String.valueOf(taskList.get(i).getImage().getHeight()));

//ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(taskList.get(i).getImage().getWidth(), taskList.get(i).getImage().getHeight());
//layoutParams.width = taskList.get(i).getImage().getWidth();
//layoutParams.height = taskList.get(i).getImage().getHeight();
//imageView.setLayoutParams(layoutParams);
imageView.setImageBitmap(taskList.get(i).getImage());

builder.setNegativeButton("Zurück", new DialogInterface.OnClickListener() {

+ 33
- 44
Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TasksFragment.java View File

@@ -6,6 +6,7 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
@@ -38,6 +39,8 @@ import androidx.lifecycle.ViewModelProviders;

import com.example.meinwald.BuildConfig;
import com.example.meinwald.R;
import com.example.meinwald.ui.area.AreaReference;
import com.example.meinwald.ui.area.OwnArea;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
@@ -175,7 +178,7 @@ public class TasksFragment extends Fragment {

//save and display location
newTask.setLocation(mLastKnownLocation);
locationText.setText("Lat: " +String.valueOf(mLastKnownLocation.getLatitude()) + " Lng: " + String.valueOf(mLastKnownLocation.getLongitude()));
locationText.setText("Auf " + newTask.getLocation().getAccuracy() + " Meter genau!");
}
});

@@ -226,7 +229,7 @@ public class TasksFragment extends Fragment {
//save user input
newTask.setTitle(String.valueOf(titleView.getText()));
newTask.setNotice(String.valueOf(noticeView.getText()));
newTask.setPathImage(newTask.saveImageToExternalStorage(getContext()));

boolean result = allTasks.add(newTask);

@@ -234,15 +237,6 @@ public class TasksFragment extends Fragment {
{
Log.d(TAG, "new Task: " + newTask.toString());
Log.d(TAG, "add new task result: " + result);

/**
for (OwnTask task: allTasks)
{
if (BuildConfig.DEBUG) {
Log.d(TAG, task.toString());
}
}
**/
}

instantiateTaskList();
@@ -336,7 +330,7 @@ public class TasksFragment extends Fragment {
{

//save image to external storage and save path
String path = saveReceivedImage(task.getImage(), task.getId());
String path = task.saveImageToExternalStorage(getContext());
task.setPathImage(path);

if (BuildConfig.DEBUG) {
@@ -357,37 +351,6 @@ public class TasksFragment extends Fragment {
}
}

private String saveReceivedImage(Bitmap bitmap, String imageName){

File path = null;

try {
path = new File(getContext().getFilesDir(), "meinWald" + File.separator + "Images");
if(!path.exists()){
path.mkdirs();
}

if (BuildConfig.DEBUG) {
Log.d(TAG, "Image file path: " + path);
}

File outFile = new File(path, imageName + ".jpeg");
if (!outFile.exists())
{
FileOutputStream outputStream = new FileOutputStream(outFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.close();
}

} catch (FileNotFoundException e) {
Log.e(TAG, "Saving received message failed with", e);
} catch (IOException e) {
Log.e(TAG, "Saving received message failed with", e);
}

return path.toString();
}

/**
* Reads tasks saved in preferences as jsonStrings
*
@@ -431,6 +394,33 @@ public class TasksFragment extends Fragment {
public void instantiateTaskList()
{
final TaskAdapter adapter = new TaskAdapter(getActivity().getApplicationContext(),allTasks);

adapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();

if (BuildConfig.DEBUG)
{
Log.d(TAG, "onChanged");
}

if (BuildConfig.DEBUG)
{
Log.d(TAG, "dataset size: " + taskList.getAdapter().getCount());
}

if (taskList.getAdapter().getCount() > 0)
{
allTasks = new ArrayList<>();

for (int i = 0; i < taskList.getAdapter().getCount(); i++)
{
allTasks.add((OwnTask) taskList.getAdapter().getItem(i));
}
}
}
});
taskList.setAdapter(adapter);

//initialise onClickListeners
@@ -574,7 +564,6 @@ public class TasksFragment extends Fragment {
{
Bitmap photo = (Bitmap) data.getExtras().get("data");
newTask.setImage(photo);
newTask.setPathImage(saveReceivedImage(photo,newTask.getId()));

if (imageToAdd != null && photo != null)
{

+ 43
- 4
Code Android/meinWald/app/src/main/res/layout/area_element.xml View File

@@ -25,6 +25,7 @@
android:focusable="false"
android:textColor="@android:color/primary_text_light"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

@@ -87,18 +88,56 @@
<TextView
android:id="@+id/areaInfoNotice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:layout_gravity="left"
android:clickable="false"
android:duplicateParentState="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:textColor="@android:color/primary_text_light"
android:textSize="12sp"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="@+id/taskIcon"
app:layout_constraintBottom_toTopOf="@+id/areaInfoArea"
app:layout_constraintEnd_toStartOf="@+id/areaIcon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:duplicateParentState="true"/>
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/areaInfoAreatv"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_gravity="left"
android:layout_marginBottom="5dp"
android:clickable="false"
android:duplicateParentState="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="Fläche:"
android:textColor="@android:color/primary_text_light"
android:textSize="14sp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<TextView
android:id="@+id/areaInfoArea"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="left"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginBottom="5dp"
android:clickable="false"
android:duplicateParentState="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:textColor="@android:color/primary_text_light"
android:textSize="14sp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/areaIcon"
app:layout_constraintStart_toEndOf="@+id/areaInfoAreatv"
app:layout_constraintTop_toTopOf="@+id/areaInfoAreatv" />

</androidx.constraintlayout.widget.ConstraintLayout>


+ 66
- 9
Code Android/meinWald/app/src/main/res/layout/area_input.xml View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_area_root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@@ -11,14 +12,26 @@
android:id="@+id/areaTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:text="Grundstück"
android:textAppearance="?android:attr/textAppearanceLarge" />
android:textAppearance="?android:attr/textAppearanceLarge"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<EditText
android:id="@+id/areaTitleUserInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Titel eingeben!">
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:hint="Titel eingeben!"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaTitle">

<requestFocus />

@@ -28,28 +41,72 @@
android:id="@+id/areaManagementNotice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="15dp"
android:text="Beschreibung"
android:textAppearance="?android:attr/textAppearanceLarge" />
android:textAppearance="?android:attr/textAppearanceLarge"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaTitleUserInput" />

<EditText
android:id="@+id/areaManagementNoticeUserInput"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:cursorVisible="true"
android:hint="Beschreibung eingeben!"
android:isScrollContainer="true">
<requestFocus />
android:isScrollContainer="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaManagementNotice">

</EditText>

<Button
android:id="@+id/areaStartTracking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Grundstücksaufnahme Starten!" />
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:text="Grundstücksaufnahme Starten!"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaManagementNoticeUserInput" />

<Button
android:id="@+id/areaStopTracking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:text="Grundstücksaufnahme Beenden!"
android:visibility="invisible"/>
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaManagementNoticeUserInput" />

<Button
android:id="@+id/areaAddGPSPoint"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:text="Grenzpunkt hinzufügen"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaStartTracking" />

</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

+ 40
- 5
Code Android/meinWald/app/src/main/res/layout/area_management.xml View File

@@ -66,7 +66,7 @@
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="15dp"
android:text="Bild"
android:text="Zuletzt überprüft"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
@@ -85,6 +85,30 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4" />

<TextView
android:id="@+id/textView7"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="15dp"
android:text="Bild"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaManagementLastChecked" />

<TextView
android:id="@+id/areaManagementLastChecked"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:textSize="12sp"
app:layout_constraintEnd_toStartOf="@+id/areaManageNewDate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView6" />

<ImageView
android:id="@+id/areaManageImage"
android:layout_width="match_parent"
@@ -93,11 +117,12 @@
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:src="@android:drawable/ic_menu_gallery"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView6"
android:src="@android:drawable/ic_menu_gallery"
android:visibility="visible"/>
app:layout_constraintTop_toBottomOf="@+id/textView7" />

<ImageView
android:id="@+id/areaManageNewDescription"
@@ -119,6 +144,16 @@
app:layout_constraintEnd_toEndOf="@+id/areaManageGPSPoints"
android:src="@android:drawable/ic_popup_sync" />

<ImageView
android:id="@+id/areaManageNewDate"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@android:drawable/ic_popup_sync"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/areaManagementLastChecked"
app:layout_constraintEnd_toEndOf="@+id/areaManageGPSPoints"
app:tint="#1B5E20" />

<ImageView
android:id="@+id/areaManageNewImage"
android:layout_width="30dp"
@@ -141,5 +176,5 @@
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
/>
</androidx.constraintlayout.widget.ConstraintLayout>

+ 7
- 2
Code Android/meinWald/app/src/main/res/layout/image_large.xml View File

@@ -12,8 +12,13 @@

<ImageView
android:id="@+id/taskLargeImage"
android:layout_width="match_parent"
android:layout_height="575dp"
android:layout_width="0dp"
android:layout_height="500dp"
android:layout_marginStart="40dp"
android:layout_marginLeft="40dp"
android:layout_marginTop="60dp"
android:layout_marginEnd="40dp"
android:layout_marginRight="40dp"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

+ 22
- 6
Code Android/meinWald/app/src/main/res/layout/task_element.xml View File

@@ -13,23 +13,39 @@

<TextView
android:id="@+id/taskInfoTitle"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_gravity="left"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:clickable="false"
android:focusable="false"

android:textColor="@android:color/primary_text_light"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@+id/taskManageTask"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageView
android:id="@+id/taskManageTask"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:clickable="true"
android:duplicateParentState="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:src="@android:drawable/ic_menu_manage"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/areaInfoView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/areaInfoTitle"
app:layout_constraintTop_toTopOf="parent" />

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/taskInfoView"
android:layout_width="0dp"

+ 0
- 2
Code Android/meinWald/app/src/main/res/layout/task_input.xml View File

@@ -38,8 +38,6 @@
android:hint="Beschreibung eingeben!"
android:isScrollContainer="true">

<requestFocus />

</EditText>

<Button

+ 144
- 0
Code Android/meinWald/app/src/main/res/layout/task_management.xml View File

@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

<TextView
android:id="@+id/taskManageTitle"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:text="TextView"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/textView2"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:text="Beschreibung"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/taskManageTitle" />

<TextView
android:id="@+id/taskManageNotice"
android:layout_width="0dp"
android:layout_height="75dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:isScrollContainer="true"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />

<TextView
android:id="@+id/textView4"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="15dp"
android:text="Standort"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/taskManageNotice" />

<TextView
android:id="@+id/textView6"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="15dp"
android:text="Bild"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/taskManageGPSPoint" />

<TextView
android:id="@+id/taskManageGPSPoint"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4" />

<ImageView
android:id="@+id/taskManageImage"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView6"
android:src="@android:drawable/ic_menu_gallery"
android:visibility="visible"/>

<ImageView
android:id="@+id/taskManageNewDescription"
android:layout_width="30dp"
android:layout_height="30dp"
app:tint="#1B5E20"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/taskManageNotice"
app:layout_constraintEnd_toEndOf="@+id/taskManageNotice"
android:src="@android:drawable/ic_popup_sync" />

<ImageView
android:id="@+id/taskManageNewGPS"
android:layout_width="30dp"
android:layout_height="30dp"
app:tint="#1B5E20"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/taskManageGPSPoint"
app:layout_constraintEnd_toEndOf="@+id/taskManageGPSPoint"
android:src="@android:drawable/ic_popup_sync" />

<ImageView
android:id="@+id/taskManageNewImage"
android:layout_width="30dp"
android:layout_height="30dp"
app:tint="#1B5E20"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/taskManageImage"
app:layout_constraintEnd_toEndOf="@+id/taskManageImage"
android:src="@android:drawable/ic_menu_camera" />

<ImageView
android:id="@+id/taskManageDeleteTask"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:src="@android:drawable/ic_menu_delete"
app:tint="#B71C1C"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>

</androidx.constraintlayout.widget.ConstraintLayout>

+ 6
- 1
Code Android/meinWald/app/src/main/res/values/colors.xml View File

@@ -1,7 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#1B5E20</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorPrimaryDark">#1B5E20</color>
<color name="colorAccent">#03DAC5</color>
<color name="selectionBackground">#c0edc3</color>
<color name="colorArea1">#57a639</color>
<color name="colorArea2">#819b45</color>
<color name="colorArea3">#d3d30c</color>
<color name="colorArea4">#df9600</color>
<color name="colorArea5">#df3d00</color>
</resources>

Loading…
Cancel
Save