diff --git a/.idea/misc.xml b/.idea/misc.xml index 1af431a..90fb734 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,6 +7,7 @@ + diff --git a/app/build.gradle b/app/build.gradle index a8b9649..5358535 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { applicationId "it.danieleverducci.ojo" - minSdkVersion 17 + minSdkVersion 21 targetSdkVersion 30 versionCode 3 versionName "0.0.3" diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 5346148..358fea4 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -10,8 +10,8 @@ { "type": "SINGLE", "filters": [], - "versionCode": 1, - "versionName": "0.0.1", + "versionCode": 2, + "versionName": "0.0.2", "outputFile": "app-release.apk" } ] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1edacc3..aa10715 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,8 +14,8 @@ - + android:theme="@style/Theme.Ojo" + android:configChanges="orientation|screenSize"> diff --git a/app/src/main/java/it/danieleverducci/ojo/Settings.java b/app/src/main/java/it/danieleverducci/ojo/CamerasSettings.java similarity index 90% rename from app/src/main/java/it/danieleverducci/ojo/Settings.java rename to app/src/main/java/it/danieleverducci/ojo/CamerasSettings.java index 84dcad3..eca7fe0 100644 --- a/app/src/main/java/it/danieleverducci/ojo/Settings.java +++ b/app/src/main/java/it/danieleverducci/ojo/CamerasSettings.java @@ -13,27 +13,26 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import java.util.Set; import it.danieleverducci.ojo.entities.Camera; /** * Manages the settings persistence */ -public class Settings implements Serializable { +public class CamerasSettings implements Serializable { private static final String FILENAME = "settings.bin"; private static final String TAG = "Settings"; private volatile String settingsFilePath; private List cameras = new ArrayList<>(); - public static Settings fromDisk(Context context) { + public static CamerasSettings fromDisk(Context context) { String filePath = context.getFilesDir() + File.separator + FILENAME; - Settings s = new Settings(); + CamerasSettings s = new CamerasSettings(); try { FileInputStream fin = new FileInputStream(filePath); ObjectInputStream ois = new ObjectInputStream(fin); - s = (Settings) ois.readObject(); + s = (CamerasSettings) ois.readObject(); } catch (FileNotFoundException e) { Log.d(TAG, "No saved settings found, will create a new one"); } catch (IOException e) { diff --git a/app/src/main/java/it/danieleverducci/ojo/SharedPreferencesManager.java b/app/src/main/java/it/danieleverducci/ojo/SharedPreferencesManager.java new file mode 100644 index 0000000..02ab136 --- /dev/null +++ b/app/src/main/java/it/danieleverducci/ojo/SharedPreferencesManager.java @@ -0,0 +1,18 @@ +package it.danieleverducci.ojo; + +import android.content.Context; +import android.content.SharedPreferences; + +public class SharedPreferencesManager { + private static final String SP_ROTATION_ENABLED = "rot_en"; + + public static void saveRotationEnabled(Context ctx, boolean enabled) { + SharedPreferences sharedPref = ctx.getSharedPreferences(SP_ROTATION_ENABLED, Context.MODE_PRIVATE); + sharedPref.edit().putBoolean(SP_ROTATION_ENABLED, enabled).apply(); + } + + public static boolean loadRotationEnabled(Context ctx) { + SharedPreferences sharedPref = ctx.getSharedPreferences(SP_ROTATION_ENABLED, Context.MODE_PRIVATE); + return sharedPref.getBoolean(SP_ROTATION_ENABLED, false); + } +} diff --git a/app/src/main/java/it/danieleverducci/ojo/ui/InfoFragment.java b/app/src/main/java/it/danieleverducci/ojo/ui/InfoFragment.java new file mode 100644 index 0000000..6394b64 --- /dev/null +++ b/app/src/main/java/it/danieleverducci/ojo/ui/InfoFragment.java @@ -0,0 +1,18 @@ +package it.danieleverducci.ojo.ui; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.fragment.app.Fragment; + +import it.danieleverducci.ojo.databinding.FragmentInfoBinding; + + +public class InfoFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return FragmentInfoBinding.inflate(inflater, container, false).getRoot(); + } +} diff --git a/app/src/main/java/it/danieleverducci/ojo/ui/MainActivity.java b/app/src/main/java/it/danieleverducci/ojo/ui/MainActivity.java index 157826c..50d4d8b 100644 --- a/app/src/main/java/it/danieleverducci/ojo/ui/MainActivity.java +++ b/app/src/main/java/it/danieleverducci/ojo/ui/MainActivity.java @@ -1,5 +1,6 @@ package it.danieleverducci.ojo.ui; +import android.content.pm.ActivityInfo; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; @@ -11,6 +12,7 @@ import androidx.navigation.NavController; import androidx.navigation.Navigation; import it.danieleverducci.ojo.R; +import it.danieleverducci.ojo.SharedPreferencesManager; import it.danieleverducci.ojo.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { @@ -18,11 +20,15 @@ public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; private NavController navController; + private boolean rotationEnabledSetting; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + rotationEnabledSetting = SharedPreferencesManager.loadRotationEnabled(this); + this.setRequestedOrientation(this.rotationEnabledSetting ? ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); @@ -58,4 +64,13 @@ public class MainActivity extends AppCompatActivity { else navController.navigate(actionId); } + + public boolean getRotationEnabledSetting() { + return this.rotationEnabledSetting; + } + + public void toggleRotationEnabledSetting() { + this.rotationEnabledSetting = !this.rotationEnabledSetting; + this.setRequestedOrientation(this.rotationEnabledSetting ? ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } } \ No newline at end of file diff --git a/app/src/main/java/it/danieleverducci/ojo/ui/SettingsFragment.java b/app/src/main/java/it/danieleverducci/ojo/ui/SettingsFragment.java index a4b35d8..2acaf34 100644 --- a/app/src/main/java/it/danieleverducci/ojo/ui/SettingsFragment.java +++ b/app/src/main/java/it/danieleverducci/ojo/ui/SettingsFragment.java @@ -1,13 +1,14 @@ package it.danieleverducci.ojo.ui; -import android.content.Context; +import android.app.AlertDialog; +import android.app.Dialog; +import android.graphics.Color; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -20,7 +21,8 @@ import android.view.ViewGroup; import java.util.List; import it.danieleverducci.ojo.R; -import it.danieleverducci.ojo.Settings; +import it.danieleverducci.ojo.CamerasSettings; +import it.danieleverducci.ojo.SharedPreferencesManager; import it.danieleverducci.ojo.databinding.FragmentSettingsItemListBinding; import it.danieleverducci.ojo.entities.Camera; import it.danieleverducci.ojo.ui.adapters.SettingsRecyclerViewAdapter; @@ -32,7 +34,7 @@ import it.danieleverducci.ojo.utils.ItemMoveCallback; public class SettingsFragment extends Fragment { private FragmentSettingsItemListBinding binding; - private Settings settings; + private CamerasSettings camerasSettings; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -44,14 +46,28 @@ public class SettingsFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - // Setup toolbar and register for item click + // Setup toolbar + binding.settingsToolbar.getOverflowIcon().setTint(Color.WHITE); binding.settingsToolbar.inflateMenu(R.menu.settings_menu); + MenuItem rotMenuItem = binding.settingsToolbar.getMenu().findItem(R.id.menuitem_allow_rotation); + rotMenuItem.setTitle(((MainActivity)getActivity()).getRotationEnabledSetting() ? R.string.menuitem_deny_rotation : R.string.menuitem_allow_rotation); + + // Register for item click binding.settingsToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - if (item.getItemId() == R.id.menuitem_add_camera) { - ((MainActivity)getActivity()).navigateToFragment(R.id.action_settingsToCameraUrl); - return true; + switch (item.getItemId()) { + case R.id.menuitem_add_camera: + ((MainActivity)getActivity()).navigateToFragment(R.id.action_settingsToCameraUrl); + return true; + case R.id.menuitem_allow_rotation: + ((MainActivity)getActivity()).toggleRotationEnabledSetting(); + SharedPreferencesManager.saveRotationEnabled(getContext(), ((MainActivity)getActivity()).getRotationEnabledSetting()); + item.setTitle(((MainActivity)getActivity()).getRotationEnabledSetting() ? R.string.menuitem_deny_rotation : R.string.menuitem_allow_rotation); + return true; + case R.id.menuitem_info: + ((MainActivity)getActivity()).navigateToFragment(R.id.action_SettingsToInfoFragment); + return true; } return false; } @@ -63,8 +79,8 @@ public class SettingsFragment extends Fragment { super.onResume(); // Load cameras - settings = Settings.fromDisk(getContext()); - List cams = settings.getCameras(); + camerasSettings = CamerasSettings.fromDisk(getContext()); + List cams = camerasSettings.getCameras(); // Set the adapter RecyclerView recyclerView = binding.list; @@ -93,7 +109,7 @@ public class SettingsFragment extends Fragment { // Save cameras List cams = ((SettingsRecyclerViewAdapter)binding.list.getAdapter()).getItems(); - this.settings.setCameras(cams); - this.settings.save(); + this.camerasSettings.setCameras(cams); + this.camerasSettings.save(); } } \ No newline at end of file diff --git a/app/src/main/java/it/danieleverducci/ojo/ui/StreamUrlFragment.java b/app/src/main/java/it/danieleverducci/ojo/ui/StreamUrlFragment.java index 75a2a27..c0a1ea5 100644 --- a/app/src/main/java/it/danieleverducci/ojo/ui/StreamUrlFragment.java +++ b/app/src/main/java/it/danieleverducci/ojo/ui/StreamUrlFragment.java @@ -13,7 +13,7 @@ import androidx.navigation.fragment.NavHostFragment; import com.google.android.material.snackbar.Snackbar; import it.danieleverducci.ojo.R; -import it.danieleverducci.ojo.Settings; +import it.danieleverducci.ojo.CamerasSettings; import it.danieleverducci.ojo.databinding.FragmentAddStreamBinding; import it.danieleverducci.ojo.entities.Camera; @@ -21,7 +21,7 @@ public class StreamUrlFragment extends Fragment { public static final String ARG_CAMERA = "arg_camera"; private FragmentAddStreamBinding binding; - private Settings settings; + private CamerasSettings camerasSettings; private Integer selectedCamera = null; @Override @@ -29,7 +29,7 @@ public class StreamUrlFragment extends Fragment { super.onCreate(savedInstanceState); // Load existing settings (if any) - settings = Settings.fromDisk(getContext()); + camerasSettings = CamerasSettings.fromDisk(getContext()); } @Override @@ -45,7 +45,7 @@ public class StreamUrlFragment extends Fragment { if (args != null && args.containsKey(ARG_CAMERA)) { this.selectedCamera = args.getInt(ARG_CAMERA); - Camera c = settings.getCameras().get(this.selectedCamera); + Camera c = camerasSettings.getCameras().get(this.selectedCamera); binding.streamName.setText(c.getName()); binding.streamName.setHint(getContext().getString(R.string.stream_list_default_camera_name).replace("{camNo}", (this.selectedCamera+1)+"")); binding.streamUrl.setText(c.getRtspUrl()); @@ -74,16 +74,16 @@ public class StreamUrlFragment extends Fragment { if (StreamUrlFragment.this.selectedCamera != null) { // Update camera - Camera c = settings.getCameras().get(StreamUrlFragment.this.selectedCamera); + Camera c = camerasSettings.getCameras().get(StreamUrlFragment.this.selectedCamera); c.setName(name); c.setRtspUrl(url); } else { // Add stream to list - settings.addCamera(new Camera(name, url)); + camerasSettings.addCamera(new Camera(name, url)); } // Save - if (!settings.save()) { + if (!camerasSettings.save()) { Snackbar.make(view, R.string.add_stream_error_saving, Snackbar.LENGTH_LONG).show(); return; } diff --git a/app/src/main/java/it/danieleverducci/ojo/ui/SurveillanceFragment.java b/app/src/main/java/it/danieleverducci/ojo/ui/SurveillanceFragment.java index 88e66bf..753ddc2 100644 --- a/app/src/main/java/it/danieleverducci/ojo/ui/SurveillanceFragment.java +++ b/app/src/main/java/it/danieleverducci/ojo/ui/SurveillanceFragment.java @@ -28,7 +28,7 @@ import java.util.Arrays; import java.util.List; import it.danieleverducci.ojo.R; -import it.danieleverducci.ojo.Settings; +import it.danieleverducci.ojo.CamerasSettings; import it.danieleverducci.ojo.databinding.FragmentSurveillanceBinding; import it.danieleverducci.ojo.entities.Camera; import it.danieleverducci.ojo.utils.DpiUtils; @@ -123,7 +123,7 @@ public class SurveillanceFragment extends Fragment { private void addAllCameras() { - Settings settings = Settings.fromDisk(getContext()); + CamerasSettings settings = CamerasSettings.fromDisk(getContext()); List cc = settings.getCameras(); int elemsPerSide = calcGridSideElements(cc.size()); diff --git a/app/src/main/res/layout/fragment_add_stream.xml b/app/src/main/res/layout/fragment_add_stream.xml index ae7db5d..1d48507 100644 --- a/app/src/main/res/layout/fragment_add_stream.xml +++ b/app/src/main/res/layout/fragment_add_stream.xml @@ -57,48 +57,6 @@ android:layout_marginTop="30dp" android:text="@string/add_stream_save"/> - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_info.xml b/app/src/main/res/layout/fragment_info.xml new file mode 100644 index 0000000..318a66b --- /dev/null +++ b/app/src/main/res/layout/fragment_info.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings_item_list.xml b/app/src/main/res/layout/fragment_settings_item_list.xml index df78bee..cc757cc 100644 --- a/app/src/main/res/layout/fragment_settings_item_list.xml +++ b/app/src/main/res/layout/fragment_settings_item_list.xml @@ -11,13 +11,14 @@ android:layout_height="wrap_content" android:id="@+id/settingsToolbar" app:title="@string/app_name" - style="@style/ToolBarStyle"/> + style="@style/ToolBarStyle" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 9ee6946..42a12ed 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -36,5 +36,12 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index c0d3625..142cb26 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -10,13 +10,15 @@ rtsp://username:password@192.168.1.123:554 Nome della IP Camera Nome della IP Camera - Inserisci l\'url dello stream RTSP della tua IP Camera. Nota che questo differisce tra un modello e l\'altro. Consulta il pannello di configurazione o il manuale della tua IP Camera. Salva L\'URL RTSP non è valido Chiudi Si è verificato un errore durante il salvataggio della configurazione. - - Aggiungi + Inserisci l\'url dello stream RTSP della tua IP Camera. Nota che questo differisce tra un modello e l\'altro. Consulta il pannello di configurazione o il manuale della tua IP Camera. + Allow screen rotation + Landscape only + Info + Aggiungi Informazioni su Ojo Creato da Daniele Verducci. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 08ba789..e222c51 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,13 +9,15 @@ rtsp://username:password@192.168.1.123:554 Camera name Camera name - Please insert your camera\'s RTSP stream. Note that the URL differs from camera to camera: you can find the complete URL in your camera\'s settings or user manual. Save Invalid RTSP url Dismiss An error has occurred while saving configuration - - Add + Please insert your camera\'s RTSP stream. Note that the URL differs from camera to camera: you can find the complete URL in your camera\'s settings or user manual. + Allow screen rotation + Landscape only + Info + Add About Ojo Created by Daniele Verducci. diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 5e96b3c..19c3f4a 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -12,9 +12,11 @@ @color/purple_500 @color/purple_700 @color/white + + @color/white -