Просмотр исходного кода

Added settings page, persistence library and dark mode.

Paula Pereyra 1 год назад
Родитель
Сommit
7857da6515

+ 4 - 0
Stores/app/build.gradle

@@ -52,6 +52,10 @@ dependencies {
     implementation("androidx.room:room-ktx:$room_version")
     kapt("androidx.room:room-compiler:$room_version")
 
+    // Persistencia de datos - Tutorial arisdev
+    implementation "androidx.datastore:datastore-preferences:1.0.0"
+    // Crea como una base de datos: https://developer.android.com/jetpack/androidx/releases/datastore?hl=es-419
+
     implementation "org.jetbrains.anko:anko-commons:0.10.8"
     implementation 'com.github.bumptech.glide:glide:4.16.0'
 }

+ 23 - 15
Stores/app/src/main/AndroidManifest.xml

@@ -2,9 +2,23 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools">
 
-    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+
+    <queries>
+        <intent>
+            <action android:name="android.intent.action.DIAL"/>
+        </intent>
+        <intent>
+            <action android:name="android.intent.action.VIEW"/>
+
+            <data android:scheme="https"/>
+
+            <category android:name="android.intent.category.BROWSABLE"/>
+        </intent>
+    </queries>
 
     <application
+            android:name=".StoreApplication"
             android:allowBackup="true"
             android:dataExtractionRules="@xml/data_extraction_rules"
             android:fullBackupContent="@xml/backup_rules"
@@ -13,9 +27,14 @@
             android:roundIcon="@mipmap/ic_app_round"
             android:supportsRtl="true"
             android:theme="@style/Theme.Stores"
-            tools:targetApi="31"
-            android:name=".StoreApplication"
-    >
+            tools:targetApi="31">
+        <activity
+                android:name=".SettingsActivity"
+                android:exported="false">
+            <meta-data
+                    android:name="android.app.lib_name"
+                    android:value=""/>
+        </activity>
         <activity
                 android:name=".MainActivity"
                 android:exported="true">
@@ -31,15 +50,4 @@
         </activity>
     </application>
 
-    <queries>
-        <intent>
-            <action android:name="android.intent.action.DIAL"></action>
-        </intent>
-        <intent>
-            <action android:name="android.intent.action.VIEW"></action>
-            <data android:scheme="https"></data>
-            <category android:name="android.intent.category.BROWSABLE"/>
-        </intent>
-    </queries>
-
 </manifest>

+ 18 - 1
Stores/app/src/main/java/com/example/stores/MainActivity.kt

@@ -6,6 +6,8 @@ import android.net.Uri
 import androidx.appcompat.app.AppCompatActivity
 import android.os.Bundle
 import android.util.Log
+import android.view.Menu
+import android.view.MenuItem
 import android.widget.Toast
 import androidx.recyclerview.widget.GridLayoutManager
 import com.example.stores.databinding.ActivityMainBinding
@@ -24,7 +26,6 @@ class MainActivity : AppCompatActivity(), OnClickListener, MainAux {
         super.onCreate(savedInstanceState)
         mBinding = ActivityMainBinding.inflate(layoutInflater)
         setContentView(mBinding.root)
-
         setupRecyclerView()
 
         /*mBinding.btnSave.setOnClickListener {
@@ -43,6 +44,22 @@ class MainActivity : AppCompatActivity(), OnClickListener, MainAux {
         }
     }
 
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        menuInflater.inflate(R.menu.menu_actions, menu)
+        return true
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        when (item.itemId) {
+            R.id.setting_menu -> {
+                var intent = Intent(this, SettingsActivity::class.java)
+                startActivity(intent)
+                return true
+            }
+            else -> return super.onOptionsItemSelected(item)
+        }
+    }
+
     private fun launchEditFragment(args: Bundle? = null) {
         val fragment = EditStoreFragment()
         if (args !== null) fragment.arguments = args

+ 8 - 0
Stores/app/src/main/java/com/example/stores/SettingModel.kt

@@ -0,0 +1,8 @@
+package com.example.stores
+
+data class SettingModel(
+    var volume: Int,
+    var darkMode: Boolean,
+    var bluetooth: Boolean,
+    var vibration: Boolean
+)

+ 129 - 0
Stores/app/src/main/java/com/example/stores/SettingsActivity.kt

@@ -0,0 +1,129 @@
+package com.example.stores
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.view.MenuItem
+import android.content.Context
+import androidx.appcompat.app.AppCompatDelegate
+import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
+import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.intPreferencesKey
+import androidx.datastore.preferences.preferencesDataStore
+import com.example.stores.databinding.ActivitySettingsBinding
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "Settings")
+
+class SettingsActivity : AppCompatActivity() {
+    companion object {
+        const val VOLUME_LEVEL = "volume_lvl"
+        const val KEY_VIBRATION = "key_vibration"
+        const val KEY_DARK_MODE = "key_darkmode"
+        const val KEY_BLUETOOTH = "key_bluetooth"
+    }
+
+    private lateinit var mBinding: ActivitySettingsBinding
+    private var firstTime: Boolean = true
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        mBinding = ActivitySettingsBinding.inflate(layoutInflater)
+        setContentView(mBinding.root)
+
+        setConfigActionBar(true, getString(R.string.settings_menu))
+        CoroutineScope(Dispatchers.IO).launch {
+            getSettings().filter { firstTime }.collect {settings ->
+                if (settings != null) {
+                    runOnUiThread {
+                        mBinding.rsVolume.setValues(settings.volume.toFloat())
+                        mBinding.switchDarkMode.isChecked = settings.darkMode
+                        mBinding.switchBluetooth.isChecked = settings.bluetooth
+                        mBinding.switchVibration.isChecked = settings.vibration
+                        firstTime = !firstTime
+                    }
+                }
+            }
+        }
+        setUI()
+    }
+
+    /* Methods setup Action Bar  */
+    private fun setConfigActionBar (displayHome: Boolean, title: String) {
+        supportActionBar?.setDisplayHomeAsUpEnabled(displayHome)
+        supportActionBar?.title = title
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        when (item.itemId) {
+            android.R.id.home -> {
+                onBackPressedDispatcher.onBackPressed()
+                return true
+            }
+            else -> return super.onOptionsItemSelected(item)
+        }
+    }
+
+    private fun setUI () {
+        mBinding.rsVolume.addOnChangeListener { _, value, _ ->
+            CoroutineScope(Dispatchers.IO).launch {
+                saveVolumen(value.toInt())
+            }
+        }
+        mBinding.switchDarkMode.setOnCheckedChangeListener { _, value ->
+            if (value) {
+                enableDarkMode()
+            } else {
+                disableDarkMode()
+            }
+            CoroutineScope(Dispatchers.IO).launch { saveOptions(KEY_DARK_MODE, value) }
+        }
+        mBinding.switchBluetooth.setOnCheckedChangeListener { _, value ->
+            CoroutineScope(Dispatchers.IO).launch { saveOptions(KEY_BLUETOOTH, value) }
+        }
+        mBinding.switchVibration.setOnCheckedChangeListener { _, value ->
+            CoroutineScope(Dispatchers.IO).launch { saveOptions(KEY_VIBRATION, value) }
+        }
+    }
+
+    private suspend fun saveVolumen (value: Int) {
+        dataStore.edit { preference ->
+            preference[intPreferencesKey(VOLUME_LEVEL)] = value
+        }
+    }
+
+    private suspend fun saveOptions (key:String, value: Boolean) {
+        dataStore.edit { preference ->
+            preference[booleanPreferencesKey(key)] = value
+        }
+    }
+
+    private fun getSettings (): Flow<SettingModel?> {
+        return dataStore.data.map { preferences ->
+            SettingModel(
+                volume = preferences[intPreferencesKey(VOLUME_LEVEL)] ?: 50,
+                darkMode = preferences[booleanPreferencesKey(KEY_DARK_MODE)] ?: true,
+                bluetooth = preferences[booleanPreferencesKey(KEY_BLUETOOTH)] ?: false,
+                vibration = preferences[booleanPreferencesKey(KEY_VIBRATION)] ?: false
+            )
+        }
+    }
+
+    private fun enableDarkMode () {
+        AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_YES)
+        delegate.applyDayNight()
+    }
+
+    private fun disableDarkMode () {
+        AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_NO)
+        delegate.applyDayNight()
+    }
+}

+ 5 - 0
Stores/app/src/main/res/drawable/ic_bluetooth.xml

@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#555555"
+    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="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>

+ 5 - 0
Stores/app/src/main/res/drawable/ic_sound.xml

@@ -0,0 +1,5 @@
+<vector android:autoMirrored="true" android:height="24dp"
+    android:tint="#555555" 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="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z"/>
+</vector>

+ 5 - 0
Stores/app/src/main/res/drawable/ic_theme.xml

@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#555555"
+    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="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9s9,-4.03 9,-9c0,-0.46 -0.04,-0.92 -0.1,-1.36c-0.98,1.37 -2.58,2.26 -4.4,2.26c-2.98,0 -5.4,-2.42 -5.4,-5.4c0,-1.81 0.89,-3.42 2.26,-4.4C12.92,3.04 12.46,3 12,3L12,3z"/>
+</vector>

+ 5 - 0
Stores/app/src/main/res/drawable/ic_vibration.xml

@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#555555"
+    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="M0,15h2L2,9L0,9v6zM3,17h2L5,7L3,7v10zM22,9v6h2L24,9h-2zM19,17h2L21,7h-2v10zM16.5,3h-9C6.67,3 6,3.67 6,4.5v15c0,0.83 0.67,1.5 1.5,1.5h9c0.83,0 1.5,-0.67 1.5,-1.5v-15c0,-0.83 -0.67,-1.5 -1.5,-1.5zM16,19L8,19L8,5h8v14z"/>
+</vector>

+ 181 - 0
Stores/app/src/main/res/layout/activity_settings.xml

@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        tools:context=".SettingsActivity">
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:paddingVertical="6dp"
+    >
+        <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+
+                android:src="@drawable/ic_theme"
+                android:layout_margin="16dp"
+        />
+
+        <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:layout_weight="1"
+        >
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Modo oscuro"
+                    android:textColor="@color/text"
+            />
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Activa el modo oscuro para un cambio visual"
+                    android:textSize="11sp"
+            />
+        </LinearLayout>
+        
+        <com.google.android.material.switchmaterial.SwitchMaterial
+                android:id="@+id/switchDarkMode"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="16sp"
+        />
+    </LinearLayout>
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:paddingVertical="6dp"
+    >
+        <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+
+                android:src="@drawable/ic_bluetooth"
+                android:layout_margin="16dp"
+        />
+
+        <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:layout_weight="1"
+        >
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Bluetooth"
+                    android:textColor="@color/text"
+            />
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Conecta perisféricos sin cables"
+                    android:textSize="11sp"
+            />
+        </LinearLayout>
+
+        <com.google.android.material.switchmaterial.SwitchMaterial
+                android:id="@+id/switchBluetooth"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="16sp"
+        />
+    </LinearLayout> 
+    
+    <com.google.android.material.divider.MaterialDivider
+            android:layout_width="wrap_content"
+            android:layout_height="1dp"
+            android:layout_marginTop="8dp"
+    />
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:paddingVertical="6dp"
+    >
+        <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/ic_sound"
+                android:layout_margin="16dp"
+        />
+
+        <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:layout_weight="1"
+                android:paddingVertical="6dp"
+        >
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Sonido"
+                    android:textSize="11sp"
+            />
+
+            <com.google.android.material.slider.RangeSlider
+                    android:id="@+id/rsVolume"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:valueFrom="0"
+                    android:valueTo="100"
+                    android:stepSize="1"
+            />
+        </LinearLayout>
+    </LinearLayout>
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:paddingVertical="6dp"
+    >
+        <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/ic_vibration"
+                android:layout_margin="16dp"
+        />
+
+        <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:layout_weight="1"
+                android:paddingVertical="6dp"
+        >
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Vibración en las llamadas"
+                    android:textColor="@color/text"
+            />
+        </LinearLayout>
+
+        <com.google.android.material.switchmaterial.SwitchMaterial
+                android:id="@+id/switchVibration"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="16sp"
+        />
+    </LinearLayout>
+
+</LinearLayout>

+ 5 - 0
Stores/app/src/main/res/menu/menu_actions.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:title="@string/settings_menu" android:id="@+id/setting_menu" />
+</menu>

+ 11 - 0
Stores/app/src/main/res/values-night/colors.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="primaryColor">#4E8CF2</color>
+    <color name="primaryDarkColor">#4E73F2</color>
+    <color name="primaryDarkenColor">#2C46A1</color>
+    <color name="secondaryColor">#FFCC33</color>
+    <color name="secondaryDarkColor">#C89F22</color>
+    <color name="text">#FFFFFF</color>
+    <color name="white">#FFFFFFFF</color>
+    <color name="color_link">#5757BF</color>
+</resources>

+ 17 - 0
Stores/app/src/main/res/values-night/themes.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.Stores" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/primaryColor</item>
+        <item name="colorPrimaryVariant">@color/primaryDarkColor</item>
+        <item name="colorOnPrimary">@color/white</item>
+        <!-- Secondary brand color. -->
+        <item name="colorSecondary">@color/secondaryColor</item>
+        <item name="colorSecondaryVariant">@color/secondaryDarkColor</item>
+        <item name="colorOnSecondary">@color/text</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor">@color/primaryDarkenColor</item>
+        <!-- Customize your theme here. -->
+    </style>
+</resources>

+ 1 - 1
Stores/app/src/main/res/values/colors.xml

@@ -5,7 +5,7 @@
     <color name="primaryDarkenColor">#2C46A1</color>
     <color name="secondaryColor">#FFCC33</color>
     <color name="secondaryDarkColor">#C89F22</color>
-    <color name="black">#FF000000</color>
+    <color name="text">#000000</color> <!-- Se reemplaza en el modo oscuro por el mismo nombre seteado en night/colors -->
     <color name="white">#FFFFFFFF</color>
     <color name="color_link">#0000FF</color>
 </resources>

+ 1 - 0
Stores/app/src/main/res/values/strings.xml

@@ -27,4 +27,5 @@
     <string name="call_title">Call</string>
     <string name="go_web_title">Go to web</string>
     <string name="message_not_valid_website">The url is not valid, please check and try again.</string>
+    <string name="settings_menu">Settings</string>
 </resources>

+ 1 - 1
Stores/app/src/main/res/values/themes.xml

@@ -8,7 +8,7 @@
         <!-- Secondary brand color. -->
         <item name="colorSecondary">@color/secondaryColor</item>
         <item name="colorSecondaryVariant">@color/secondaryDarkColor</item>
-        <item name="colorOnSecondary">@color/black</item>
+        <item name="colorOnSecondary">@color/text</item>
         <!-- Status bar color. -->
         <item name="android:statusBarColor">@color/primaryDarkenColor</item>
         <!-- Customize your theme here. -->