diff --git a/Sources/app/build.gradle b/Sources/app/build.gradle index 29fabad836482ce62a3c0b2272fb6816a04e0ee1..607feaf34e7686f5b299e121e3e217cfda83b8d0 100644 --- a/Sources/app/build.gradle +++ b/Sources/app/build.gradle @@ -32,6 +32,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'com.google.android.gms:play-services-location:20.0.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/Sources/app/src/main/AndroidManifest.xml b/Sources/app/src/main/AndroidManifest.xml index f45be7463c3ea8d9ddcb7ea323d2838848ed2e7d..200daf11fbe293d6a3c60f010e8743c6981fc14a 100644 --- a/Sources/app/src/main/AndroidManifest.xml +++ b/Sources/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> - + <uses-permission android:name="android.permission.INTERNET" /> <uses-feature android:name="android.hardware.location.gps" /> <application @@ -20,6 +20,7 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" + android:usesCleartextTraffic="true" android:theme="@style/Theme.RoomView" tools:targetApi="31"> <activity diff --git a/Sources/app/src/main/java/Common/ImageManager.java b/Sources/app/src/main/java/Common/ImageManager.java index 3d6db2bd4da336a8fed199631f7327a911ed0e17..ee139f4227b86c64e5031717a22e57e4214ba7ea 100644 --- a/Sources/app/src/main/java/Common/ImageManager.java +++ b/Sources/app/src/main/java/Common/ImageManager.java @@ -1,11 +1,16 @@ package Common; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.widget.Toast; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import Structures.BuildingInfo; import Structures.PhotoInfo; @@ -13,51 +18,17 @@ import Structures.RoomInfo; import Structures.ZoneInfo; public class ImageManager { - private static File saveDir; - private static Context context = null; - - public static void setContext(Context c) { - context = c; - saveDir = context.getFilesDir(); - } - - public static boolean saveImage(byte[] data, PhotoInfo photo) { - boolean res = true; - File imgFile = getImageFile(photo); - try { - FileOutputStream fos = new FileOutputStream(imgFile); - fos.write(data); - fos.close(); - res = true; - } catch (Exception e) { - res = false; - } - return res; - } - - public static byte[] getImage(PhotoInfo photo) { - byte[] res = new byte[0]; - File imgFile = getImageFile(photo); - try { - FileInputStream fis = new FileInputStream(imgFile); - int length = (int) imgFile.length(); - res = new byte[length]; - fis.read(res, 0, length); - fis.close(); - } catch (Exception ignored) {} - return res; - } - - protected static String getImagePath(PhotoInfo photo) { - ZoneInfo zone = photo.getZone(); - RoomInfo room = zone.getRoom(); - BuildingInfo building = room.getBuilding(); - return "img-"+building.getName()+"-"+room.getName()+"-"+zone.getName()+"-"+photo.getOrientation()+".png"; - } - - protected static File getImageFile(PhotoInfo photo) { - String abs_path = saveDir + getImagePath(photo); - Toast.makeText(context, "saved to "+abs_path, Toast.LENGTH_SHORT).show(); - return new File(abs_path); + public static void bitmapFromURL(Callback onResolve, Callback onReject, String url) { + ExecutorService service = Executors.newSingleThreadExecutor(); + service.execute(() -> { + Bitmap icon = null; + try { + InputStream in = new java.net.URL(url).openConnection().getInputStream(); + icon = BitmapFactory.decodeStream(in); + onResolve.call(icon); + } catch (Exception e) { + onReject.call("Image decode error : (image: "+url+")" + e.getMessage()); + } + }); } } diff --git a/Sources/app/src/main/java/Common/Position.java b/Sources/app/src/main/java/Common/Position.java new file mode 100644 index 0000000000000000000000000000000000000000..5eb0e619ade63933507c3bca77654559c5ac2c5f --- /dev/null +++ b/Sources/app/src/main/java/Common/Position.java @@ -0,0 +1,33 @@ +package Common; + +import android.location.Location; + +import java.io.Serializable; + +public class Position implements Serializable { + public double latitude; + public double longitude; + + public Position(double latitude, double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + public Position(Location location) { + this.latitude = location.getLatitude(); + this.longitude = location.getLongitude(); + } + + public Position() { + this.latitude = 0; + this.longitude = 0; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/Popups/PhotoInfoPopup.java b/Sources/app/src/main/java/Popups/PhotoInfoPopup.java index 324da13dc6a0345cd25944a822875741a1666f86..b739e3134f2c89f1a61df9ea7a7b033193ebf29a 100644 --- a/Sources/app/src/main/java/Popups/PhotoInfoPopup.java +++ b/Sources/app/src/main/java/Popups/PhotoInfoPopup.java @@ -14,6 +14,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import Common.Callback; +import Structures.MeteoInfo; import Structures.PhotoInfo; public class PhotoInfoPopup { @@ -23,6 +24,15 @@ public class PhotoInfoPopup { AlertDialog dialog = null; Button validate_btn = null; + private void setText(int id, String text) { + TextView tv = dialog.findViewById(id); + if (text == null || text.isEmpty()) { + tv.setText(""); + } else { + tv.setText(text); + } + } + public PhotoInfoPopup(Context context, PhotoInfo photo) { AlertDialog.Builder builder = new AlertDialog.Builder(context); dialog = builder.create(); @@ -31,11 +41,15 @@ public class PhotoInfoPopup { dialog.setView(popup); dialog.setOnShowListener(dialogInterface -> { - TextView tv_hour = popup.findViewById(R.id.photo_hour); - TextView tv_date = popup.findViewById(R.id.photo_date); Date d = photo.getDate(); - tv_hour.setText(new SimpleDateFormat("HH:mm").format(d)); - tv_date.setText(new SimpleDateFormat("yyyy / MM / dd").format(d)); + setText(R.id.photo_hour, new SimpleDateFormat("HH:mm").format(d)); + setText(R.id.photo_date, new SimpleDateFormat("yyyy / MM / dd").format(d)); + + MeteoInfo meteo = photo.getMeteo(); + setText(R.id.photo_temp, Math.round(meteo.getTemperature()) + " °C"); + setText(R.id.photo_humidity, (int)meteo.getHumidity() + " %"); + setText(R.id.photo_pressure, (int)(meteo.getPressure() * 1000) + " hPa"); + setText(R.id.photo_weather, MeteoInfo.weatherToString(meteo.getWeather())); validate_btn = popup.findViewById(R.id.btn_validate_room); validate_btn.setOnClickListener(view -> this.dismiss()); diff --git a/Sources/app/src/main/java/Structures/MeteoInfo.java b/Sources/app/src/main/java/Structures/MeteoInfo.java index 42225ad33c28f0c882173e9d41acd63c95858580..a0ff7142f5040ebc955af19af5434b6afecc5907 100644 --- a/Sources/app/src/main/java/Structures/MeteoInfo.java +++ b/Sources/app/src/main/java/Structures/MeteoInfo.java @@ -1,22 +1,283 @@ package Structures; +import android.Manifest; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.util.Log; + +import androidx.core.app.ActivityCompat; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.Serializable; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import Common.BuildingManager; +import Common.Callback; +import Common.ImageManager; +import Common.Position; + +import com.furwaz.roomview.PhotoActivity; +import com.furwaz.roomview.R; +import com.google.android.gms.location.FusedLocationProviderClient; + +import org.json.JSONObject; public class MeteoInfo implements Serializable { - public static MeteoInfo GetCurrentMeteo() { - // TODO - return null; + enum WeatherType { + CLEAR_SKY, + FEW_CLOUDS, + SCATTERED_CLOUDS, + BROKEN_CLOUDS, + SHOWER_RAIN, + RAIN, + THUNDERSTORM, + SNOW, + MIST + } + + public static WeatherType WeatherFromString(String s) { + switch (s.toLowerCase(Locale.ROOT)) { + case "clouds": return WeatherType.FEW_CLOUDS; + case "rain": return WeatherType.RAIN; + case "thunderstorm": return WeatherType.THUNDERSTORM; + case "snow": return WeatherType.SNOW; + case "mist": return WeatherType.MIST; + default: return WeatherType.CLEAR_SKY; + } + } + + public static String weatherToString(WeatherType weather) { + if (currentActivity == null || weather == null) return ""; + + int id = 0; + switch (weather) { + case FEW_CLOUDS: id = R.string.few_clouds; break; + case SCATTERED_CLOUDS: id = R.string.scattered_clouds; break; + case BROKEN_CLOUDS: id = R.string.broken_clouds; break; + case SHOWER_RAIN: id = R.string.shower_rain; break; + case RAIN: id = R.string.rain; break; + case THUNDERSTORM: id = R.string.thunderstorm; break; + case SNOW: id = R.string.snow; break; + case MIST: id = R.string.mist; break; + default: id = R.string.clear_sky; break; + } + return currentActivity.getResources().getString(id); + } + + private static String getWeatherIconURL(WeatherType type) { + String link = "http://openweathermap.org/img/wn/<code>@2x.png"; + switch (type) { + case FEW_CLOUDS: link = link.replace("<code>", "02d"); break; + case SCATTERED_CLOUDS: link = link.replace("<code>", "03d"); break; + case BROKEN_CLOUDS: link = link.replace("<code>", "04d"); break; + case SHOWER_RAIN: link = link.replace("<code>", "09d"); break; + case RAIN: link = link.replace("<code>", "10d"); break; + case THUNDERSTORM: link = link.replace("<code>", "11d"); break; + case SNOW: link = link.replace("<code>", "13d"); break; + case MIST: link = link.replace("<code>", "50d"); break; + default: link = link.replace("<code>", "01d"); break; + } + return link; + } + + private static String api_key = "10266719b995c965d1b45db201ae8a90"; + private static boolean hasRequestedPermissions = false; + transient private static Activity currentActivity = null; + transient private static Date last_update = null; + transient private static MeteoInfo last_infos = null; + transient private static FusedLocationProviderClient fusedLocationClient; + + private static final List<Callback> resolve_callbacks = new ArrayList<>(); + private static final List<Callback> reject_callbacks = new ArrayList<>(); + + private static double K2C(double x) { + return x - 273.15d; + } + + private static JSONObject readStream(InputStream in) { + StringBuilder sb = new StringBuilder(); + BufferedReader r = new BufferedReader(new InputStreamReader(in), 1024); + JSONObject res = null; + try { + String l = ""; + while (l != null) { + l = r.readLine(); + sb.append(l); + } + in.close(); + res = new JSONObject(sb.toString()); + } catch (Exception e) {} + return res; + } + + private static void get_position(Callback onResolve, Callback onReject) { + boolean hasPerm = currentActivity.getPackageManager().checkPermission( + Manifest.permission.ACCESS_COARSE_LOCATION, + BuildingManager.getContext().getPackageName() + ) == PackageManager.PERMISSION_GRANTED; + + if (!hasPerm) { + if (!hasRequestedPermissions) { + ActivityCompat.requestPermissions( + currentActivity, + new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, + 926 + ); + hasRequestedPermissions = true; + } else { + onReject.call("No GPS permission"); + } + return; + } + + if (fusedLocationClient == null) + fusedLocationClient = new FusedLocationProviderClient(currentActivity); + + try { + fusedLocationClient.getLastLocation().addOnSuccessListener(location -> { + if (location != null) { + onResolve.call(new Position(location)); + } else { + onReject.call("\nLocation is null"); + } + }); + } catch (SecurityException e) { + onReject.call(e.getMessage()); + } + } + + private static void call_api(Position pos, Callback onResolve, Callback onReject) { + String link = "https://api.openweathermap.org/data/2.5/weather?lat="+ pos.getLatitude() +"&lon="+ pos.getLongitude() +"&appid="+ api_key; + + ExecutorService service = Executors.newSingleThreadExecutor(); + service.execute(() -> { + InputStream is; + try { + URL url = new URL(link); + is = url.openStream(); + } catch (Exception e) { + onReject.call("\nCannot call API:\n" + e.getMessage()); + return; + } + + JSONObject res = readStream(is); + if (res == null) { + onReject.call("\nError while reading api data stream"); + } else { + onResolve.call(res); + } + }); + } + + private static void process_meteo_data(JSONObject data, Callback onResolve, Callback onReject) { + try { + String weatherType = data.getJSONArray("weather").getJSONObject(0).getString("main"); + data = data.getJSONObject("main"); + double temp = K2C( data.getDouble("temp") ); + double pressure = data.getDouble("pressure") / 1000.0d; + double humidity = data.getDouble("humidity"); + + MeteoInfo info = new MeteoInfo(WeatherFromString(weatherType), (float) temp, (float)humidity, (float)pressure); + onResolve.call(info); + + } catch (Exception e) { + onReject.call("\nCannot parse data:\n" + e.getMessage()); + } + + resolve_callbacks.clear(); + reject_callbacks.clear(); + } + + private static void retreive_meteo() { + Log.i("furwaz:debug", "Retreiving meteo data"); + get_position(position -> { + Log.i("furwaz:debug", "Position - Resolve"); + call_api((Position) position, data -> { + Log.i("furwaz:debug", "API - Resolve"); + process_meteo_data((JSONObject) data, info -> { + Log.i("furwaz:debug", "Data - Resolve (size = "+resolve_callbacks.size()+")"); + last_infos = (MeteoInfo) info; + last_update = new Date(); + + for (Callback c : resolve_callbacks) c.call(info); + resolve_callbacks.clear(); + reject_callbacks.clear(); + return null; + }, e -> { + Log.i("furwaz:debug", "Data - Reject"); + for (Callback c : reject_callbacks) c.call(e); + resolve_callbacks.clear(); + reject_callbacks.clear(); + return null; + }); + return null; + }, err -> { + Log.i("furwaz:debug", "API - Reject"); + for (Callback c : reject_callbacks) + c.call("API Error: data is null"); + + resolve_callbacks.clear(); + reject_callbacks.clear(); + return null; + }); + return null; + }, reject -> { + Log.i("furwaz:debug", "Position - Reject"); + for (Callback c : reject_callbacks) + c.call("\nCannot get location:\n" + reject); + + resolve_callbacks.clear(); + reject_callbacks.clear(); + return null; + }); + } + + public static void SetCurrentActivity(Activity activity) { + currentActivity = activity; + } + + public static void SetPermissionResult(boolean res) { + retreive_meteo(); + } + + public static void GetCurrentMeteo(Activity activity, Callback onResolve, Callback onReject) { + SetCurrentActivity(activity); + Date now = new Date(); + if (last_update != null && (now.getTime() - last_update.getTime()) < 60000) { // update toutes les 1 minutes + if (last_infos != null) { + onResolve.call(last_infos); + } else { + onReject.call("Last infos is null"); + } + return; + } + + resolve_callbacks.add(onResolve); + reject_callbacks.add(onReject); + retreive_meteo(); } float temperature = 0f; float humidity = 0f; float pressure = 1000f; + transient Bitmap icon = null; + WeatherType weather = WeatherType.CLEAR_SKY; public MeteoInfo() { } - public MeteoInfo(float temp, float humi, float pres) { + public MeteoInfo(WeatherType weather, float temp, float humi, float pres) { + this.weather = weather; this.temperature = temp; this.humidity = humi; this.pressure = pres; @@ -34,6 +295,25 @@ public class MeteoInfo implements Serializable { return pressure; } + public WeatherType getWeather() { + return weather; + } + + public String getWeatherIconURL() { + return getWeatherIconURL(weather); + } + + public void getWeatherIcon(Callback onResolve, Callback onReject) { + if (icon != null) { + onResolve.call(icon); + return; + } + ImageManager.bitmapFromURL(image -> { + icon = (Bitmap) image; + return onResolve.call(image); + }, onReject, this.getWeatherIconURL()); + } + public void setTemperature(float temperature) { this.temperature = temperature; } @@ -45,4 +325,8 @@ public class MeteoInfo implements Serializable { public void setPressure(float pressure) { this.pressure = pressure; } + + public void setWeather(WeatherType weather) { + this.weather = weather; + } } diff --git a/Sources/app/src/main/java/Structures/PhotoInfo.java b/Sources/app/src/main/java/Structures/PhotoInfo.java index 9aa41f6f8de0a50a921267dd32ebd6ee8fcc4fb5..27f9bafc177da3a9483579b3c82321580fcf0c9a 100644 --- a/Sources/app/src/main/java/Structures/PhotoInfo.java +++ b/Sources/app/src/main/java/Structures/PhotoInfo.java @@ -3,6 +3,7 @@ package Structures; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; +import android.widget.Toast; import java.io.Serializable; import java.util.ArrayList; @@ -28,7 +29,6 @@ public class PhotoInfo implements Serializable { protected void setPicture(byte[] im) { this.image = im; this.date = new Date(); - this.meteo = MeteoInfo.GetCurrentMeteo(); } public PhotoInfo() { diff --git a/Sources/app/src/main/java/com/furwaz/roomview/MainActivity.java b/Sources/app/src/main/java/com/furwaz/roomview/MainActivity.java index 3d5db8a05bd8fb341707fa2f08be008a1c9ce942..980c8ca35550007118dadb5e0b916d191543d62d 100644 --- a/Sources/app/src/main/java/com/furwaz/roomview/MainActivity.java +++ b/Sources/app/src/main/java/com/furwaz/roomview/MainActivity.java @@ -46,7 +46,6 @@ public class MainActivity extends AppCompatActivity { setContentView(R.layout.activity_main); BuildingManager.setContext(getBaseContext()); - ImageManager.setContext(getBaseContext()); ListView building_lv = findViewById(R.id.building_list); LinearLayout noDataLayout = findViewById(R.id.no_building_layout); diff --git a/Sources/app/src/main/java/com/furwaz/roomview/PhotoActivity.java b/Sources/app/src/main/java/com/furwaz/roomview/PhotoActivity.java index 7f0cbca3cf1ea88460daaaf7bdcaea552aba81a2..669ffa55d6706350503e14b8fd31e6156ae85243 100644 --- a/Sources/app/src/main/java/com/furwaz/roomview/PhotoActivity.java +++ b/Sources/app/src/main/java/com/furwaz/roomview/PhotoActivity.java @@ -8,8 +8,10 @@ import androidx.core.content.ContextCompat; import android.Manifest; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.graphics.Bitmap; import android.hardware.Camera; import android.hardware.Sensor; import android.hardware.SensorEvent; @@ -37,6 +39,7 @@ import Common.Callback; import Common.ImageManager; import Popups.WalkPopup; import Structures.BuildingInfo; +import Structures.MeteoInfo; import Structures.Orientation; import Structures.PhotoInfo; import Structures.RoomInfo; @@ -64,10 +67,12 @@ public class PhotoActivity extends AppCompatActivity implements SensorEventListe RoomInfo room = null; ZoneInfo zone = null; PhotoInfo photo = null; + MeteoInfo currentMeteo = null; Orientation displayed_orient = Orientation.NORTH; LinearLayout orient_layout = null; + @SuppressLint("SourceLockedOrientationActivity") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -110,6 +115,7 @@ public class PhotoActivity extends AppCompatActivity implements SensorEventListe } } + @SuppressLint("SetTextI18n") protected void setupPhotoMode() { if (!checkCameraHardware()) { Toast.makeText(this, "Error : no camera detected on this device", Toast.LENGTH_SHORT).show(); @@ -132,6 +138,9 @@ public class PhotoActivity extends AppCompatActivity implements SensorEventListe btn_foto.setOnClickListener(view -> { camera.takePicture(null, null, (bytes, cam) -> { photo.setImage(bytes); + if (currentMeteo != null) { + photo.setMeteo(currentMeteo); + } setViewMode(MODE_EDIT); }); }); @@ -150,6 +159,34 @@ public class PhotoActivity extends AppCompatActivity implements SensorEventListe magnet = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); register(); } + + MeteoInfo.GetCurrentMeteo(this, meteo -> { + currentMeteo = (MeteoInfo) meteo; + runOnUiThread(() -> { + ((TextView) findViewById(R.id.temperature)).setText(Math.round(currentMeteo.getTemperature()) + "°C"); + ((TextView) findViewById(R.id.humidity)).setText((int)currentMeteo.getHumidity() + "%"); + }); + currentMeteo.getWeatherIcon(icon -> { + runOnUiThread(() -> { + ImageView weather_icon = findViewById(R.id.weather_icon); + weather_icon.setImageBitmap((Bitmap) icon); + }); + return null; + }, error -> { + runOnUiThread(() -> { + Toast.makeText(this, getResources().getString(R.string.error)+" : "+error, Toast.LENGTH_SHORT).show(); + ((TextView) findViewById(R.id.humidity)).setText(R.string.error); + }); + return null; + }); + return null; + }, error -> { + runOnUiThread(() -> { + Toast.makeText(this, getResources().getString(R.string.error)+" : "+error, Toast.LENGTH_SHORT).show(); + ((TextView) findViewById(R.id.humidity)).setText(R.string.error); + }); + return null; + }); } protected void setupEditMode() { @@ -258,7 +295,12 @@ public class PhotoActivity extends AppCompatActivity implements SensorEventListe if (sensorEvent.sensor == magnet) { magnetValues = sensorEvent.values; float[] res = new float[9]; - SensorManager.getRotationMatrix(res, null, accelValues, magnetValues); + SensorManager.getRotationMatrix( + res, + null, + new float[]{accelValues[0], -accelValues[2], accelValues[1]}, + new float[]{magnetValues[0], -magnetValues[2], magnetValues[1]} + ); float[] values = new float[3]; SensorManager.getOrientation(res, values); int angle = ((int)(values[0] * 180 / Math.PI) + 135) % 360; @@ -294,20 +336,21 @@ public class PhotoActivity extends AppCompatActivity implements SensorEventListe @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (requestCode != 621) return; - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - getCamera(_on_resolve_callback, _on_reject_callback); - } else { - if (_on_reject_callback != null) _on_reject_callback.call( getResources().getString(R.string.camera_error) ); + switch (requestCode) { + case 621: + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + getCamera(_on_resolve_callback, _on_reject_callback); + } else { + if (_on_reject_callback != null) _on_reject_callback.call( getResources().getString(R.string.camera_error) ); + } + break; + case 926: + MeteoInfo.SetPermissionResult(grantResults[0] == PackageManager.PERMISSION_GRANTED); } } private boolean checkCameraHardware() { - if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)){ - return true; - } else { - return false; - } + return getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY); } protected void showAddWalkPopup() { diff --git a/Sources/app/src/main/res/drawable/ic_baseline_cloud_24.xml b/Sources/app/src/main/res/drawable/ic_baseline_cloud_24.xml new file mode 100644 index 0000000000000000000000000000000000000000..235c7abc23bedaaa12646643ab1a9de93ed86814 --- /dev/null +++ b/Sources/app/src/main/res/drawable/ic_baseline_cloud_24.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="@color/slate_700" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z"/> +</vector> diff --git a/Sources/app/src/main/res/layout/activity_photo.xml b/Sources/app/src/main/res/layout/activity_photo.xml index db9260b5a1d727bca382d47916fbba4dea3e079f..bf4d83cf8fa70214cfd6db6dcdacb4224c05b4a8 100644 --- a/Sources/app/src/main/res/layout/activity_photo.xml +++ b/Sources/app/src/main/res/layout/activity_photo.xml @@ -149,6 +149,7 @@ android:layout_weight="1" android:layout_height="wrap_content" android:orientation="horizontal" + android:layout_gravity="center" android:gravity="center" android:padding="6dp"> @@ -167,6 +168,7 @@ android:layout_weight="1" android:layout_height="wrap_content" android:orientation="horizontal" + android:layout_gravity="center" android:gravity="center"> <ImageButton @@ -183,7 +185,27 @@ android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" - android:orientation="horizontal" /> + android:layout_gravity="center" + android:gravity="center" + android:orientation="vertical"> + + <TextView + android:id="@+id/temperature" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + /> + <TextView + android:id="@+id/humidity" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/loading" + /> + <ImageView + android:id="@+id/weather_icon" + android:layout_width="50dp" + android:layout_height="50dp" + android:src="@drawable/ic_baseline_cloud_24" /> + </LinearLayout> </LinearLayout> </LinearLayout> </LinearLayout> diff --git a/Sources/app/src/main/res/layout/photo_info_popup.xml b/Sources/app/src/main/res/layout/photo_info_popup.xml index 5f2bd20244f0f4c0f07399b6994cdcd43abb71f8..190882691564b6509e6a6c09b7a54b0354548d6e 100644 --- a/Sources/app/src/main/res/layout/photo_info_popup.xml +++ b/Sources/app/src/main/res/layout/photo_info_popup.xml @@ -14,8 +14,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:background="@color/blue_500" - android:layout_marginBottom="20dp"> + android:background="@color/blue_500"> <TextView android:id="@+id/info_title" @@ -31,6 +30,36 @@ /> </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginTop="20dp"> + <LinearLayout + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="4dp" + android:layout_gravity="center" + android:background="@color/slate_200"/> + <TextView + android:layout_width="0dp" + android:layout_weight="2" + android:layout_height="wrap_content" + android:text="@string/informations" + android:textAlignment="center" + android:textStyle="bold" + android:textColor="@color/slate_300" + android:textSize="16sp" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp"/> + <LinearLayout + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="4dp" + android:layout_gravity="center" + android:background="@color/slate_200"/> + </LinearLayout> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -81,6 +110,136 @@ android:layout_marginEnd="8sp"/> </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginTop="20dp"> + <LinearLayout + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="4dp" + android:layout_gravity="center" + android:background="@color/slate_200"/> + <TextView + android:layout_width="0dp" + android:layout_weight="2" + android:layout_height="wrap_content" + android:text="@string/meteo" + android:textAlignment="center" + android:textStyle="bold" + android:textColor="@color/slate_300" + android:textSize="16sp" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp"/> + <LinearLayout + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="4dp" + android:layout_gravity="center" + android:background="@color/slate_200"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/temperature" + android:textStyle="bold" + android:textColor="@color/slate_600" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + <TextView + android:id="@+id/photo_temp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="" + android:textStyle="normal" + android:textColor="@color/blue_500" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/humidity" + android:textStyle="bold" + android:textColor="@color/slate_600" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + <TextView + android:id="@+id/photo_humidity" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="" + android:textStyle="normal" + android:textColor="@color/blue_500" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/pressure" + android:textStyle="bold" + android:textColor="@color/slate_600" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + <TextView + android:id="@+id/photo_pressure" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="" + android:textStyle="normal" + android:textColor="@color/blue_500" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/weather" + android:textStyle="bold" + android:textColor="@color/slate_600" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + <TextView + android:layout_width="match_parent" + android:id="@+id/photo_weather" + android:layout_height="wrap_content" + android:text="" + android:textStyle="normal" + android:textColor="@color/blue_500" + android:textSize="16sp" + android:layout_marginStart="8sp" + android:layout_marginEnd="8sp"/> + </LinearLayout> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/Sources/app/src/main/res/values-fr/strings.xml b/Sources/app/src/main/res/values-fr/strings.xml index 18571299173bc15b8924e316256b98506523cf17..ec092b155ab3c2f5505fe00493cc97efa60a2a0e 100644 --- a/Sources/app/src/main/res/values-fr/strings.xml +++ b/Sources/app/src/main/res/values-fr/strings.xml @@ -103,4 +103,21 @@ <string name="stair">Escalier</string> <string name="not_defined">Vous ne pouvez pas aller là. Ce chemin n\'est pas encore défini.</string> <string name="no_photo_yet">Vous ne pouvez pas aller là. Cette pièce n\'a pas encore de zone.</string> + <string name="loading">Chargement ...</string> + <string name="error">Erreur</string> + <string name="informations">Informations</string> + <string name="meteo">Météo</string> + <string name="temperature">Température</string> + <string name="humidity">Humidité</string> + <string name="pressure">Pression</string> + <string name="weather">Météo</string> + <string name="few_clouds">Peu nuageux</string> + <string name="scattered_clouds">Nuageux</string> + <string name="broken_clouds">Très nuageux</string> + <string name="shower_rain">Très Pluvieux</string> + <string name="rain">Pluvieux</string> + <string name="thunderstorm">Orageux</string> + <string name="snow">Enneigé</string> + <string name="mist">Brumeux</string> + <string name="clear_sky">Ciel dégagé</string> </resources> \ No newline at end of file diff --git a/Sources/app/src/main/res/values/strings.xml b/Sources/app/src/main/res/values/strings.xml index 0c5a90b25bf1a5f7a9273a52cd85408c8c90547d..20681026dcec26a64bcb9523dd888bf3834fa33a 100644 --- a/Sources/app/src/main/res/values/strings.xml +++ b/Sources/app/src/main/res/values/strings.xml @@ -103,4 +103,21 @@ <string name="stair">Stair</string> <string name="not_defined">You can\'t go here. This pathway is not defined yet.</string> <string name="no_photo_yet">You can\'t go here. This room doesn\'t have any zone.</string> + <string name="loading">Loading ...</string> + <string name="error">Error</string> + <string name="informations">Informations</string> + <string name="meteo">Meteo</string> + <string name="temperature">Temperature</string> + <string name="humidity">Humidity</string> + <string name="pressure">Pressure</string> + <string name="weather">Weather</string> + <string name="few_clouds">A little bit cloudy</string> + <string name="scattered_clouds">Cloudy</string> + <string name="broken_clouds">Very cloudy</string> + <string name="shower_rain">Very Raining</string> + <string name="rain">Raining</string> + <string name="thunderstorm">Stormy</string> + <string name="snow">Snowy</string> + <string name="mist">Foggy</string> + <string name="clear_sky">Clear</string> </resources> \ No newline at end of file