working on user settings

This commit is contained in:
leca 2024-10-31 04:03:33 +03:00
parent a0d96da9e4
commit 2feb2c1b5e
11 changed files with 246 additions and 73 deletions

View File

@ -1,6 +1,5 @@
package org.foxarmy.barcodescannerforemployees package org.foxarmy.barcodescannerforemployees
import android.util.Log
import okhttp3.* import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
@ -124,4 +123,52 @@ class Net {
return responseText return responseText
} }
fun changeUsername(server: String, token: String, newUsername: String): String {
lateinit var response: Response
thread {
val client = OkHttpClient()
val body = FormBody.Builder()
body.add("username", newUsername)
val requestBody = body.build()
val request = Request.Builder().url("https://$server/api/user/changeUsername")
.post(requestBody)
.addHeader("Authorization", "Bearer $token")
.build()
response = client.newCall(request).execute()
}.join()
val responseText = response.body!!.string()
return responseText
}
fun changePassword(server: String, token: String, newPassword: String): String {
lateinit var response: Response
thread {
val client = OkHttpClient()
val body = FormBody.Builder()
body.add("password", newPassword)
val requestBody = body.build()
val request = Request.Builder().url("https://$server/api/user/changePassword")
.post(requestBody)
.addHeader("Authorization", "Bearer $token")
.build()
response = client.newCall(request).execute()
}.join()
val responseText = response.body!!.string()
return responseText
}
} }

View File

@ -0,0 +1,44 @@
package org.foxarmy.barcodescannerforemployees.activities
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys
import org.foxarmy.barcodescannerforemployees.Net
import org.foxarmy.barcodescannerforemployees.databinding.ActivityAccountSettingsBinding
class AccountSettingsActivity : AppCompatActivity() {
private lateinit var binding: ActivityAccountSettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAccountSettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val sharedPreferences = EncryptedSharedPreferences.create(
"sensitive",
masterKeyAlias,
applicationContext,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
val server = sharedPreferences.getString("server", "bsfe.foxarmy.org")
val token = sharedPreferences.getString("token", "")
val net = Net()
binding.saveUsernameButton.setOnClickListener {
Toast.makeText(this, net.changeUsername(server!!, token!!, binding.newUsernameTextEdit.text.toString()), Toast.LENGTH_LONG).show()
}
binding.savePasswordButton.setOnClickListener {
Toast.makeText(this, net.changePassword(server!!, token!!, binding.newPasswordTextEdit.text.toString()), Toast.LENGTH_LONG).show()
}
}
}

View File

@ -19,14 +19,12 @@ import androidx.security.crypto.MasterKeys
import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions import com.journeyapps.barcodescanner.ScanOptions
import okhttp3.internal.http.hasBody
import org.foxarmy.barcodescannerforemployees.* import org.foxarmy.barcodescannerforemployees.*
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.StandardCopyOption import java.nio.file.StandardCopyOption
import kotlin.concurrent.thread import kotlin.concurrent.thread
import kotlin.math.abs
class AddAbstractProductActivity : AppCompatActivity() { class AddAbstractProductActivity : AppCompatActivity() {
private lateinit var imageView: ImageView private lateinit var imageView: ImageView
@ -157,7 +155,6 @@ class AddAbstractProductActivity : AppCompatActivity() {
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val sharedPreferences = EncryptedSharedPreferences.create( val sharedPreferences = EncryptedSharedPreferences.create(
// passing a file name to share a preferences
"sensitive", "sensitive",
masterKeyAlias, masterKeyAlias,
applicationContext, applicationContext,
@ -166,6 +163,8 @@ class AddAbstractProductActivity : AppCompatActivity() {
) )
val token = sharedPreferences.getString("token", "") val token = sharedPreferences.getString("token", "")
val response = n.uploadAbstractProduct("bsfe.foxarmy.org", 1, abstractProduct, File(pictureFile.absolutePath), token!!); val response = n.uploadAbstractProduct("bsfe.foxarmy.org", 1, abstractProduct, File(pictureFile.absolutePath), token!!);
Toast.makeText(this, response, Toast.LENGTH_LONG).show()
} }
finish() finish()

View File

@ -23,7 +23,6 @@ class LoginActivity : AppCompatActivity() {
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val sharedPreferences = EncryptedSharedPreferences.create( val sharedPreferences = EncryptedSharedPreferences.create(
// passing a file name to share a preferences
"sensitive", "sensitive",
masterKeyAlias, masterKeyAlias,
applicationContext, applicationContext,
@ -39,7 +38,7 @@ class LoginActivity : AppCompatActivity() {
val n = Net() val n = Net()
val response = n.login(server, username, password) val response = n.login(server, username, password)
//TODO: handle it properly when server will support Accept-Language header
if (response == "Wrong password") { if (response == "Wrong password") {
Toast.makeText(this, getString(R.string.wrong_password), Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.wrong_password), Toast.LENGTH_SHORT).show()
} else { } else {
@ -58,11 +57,12 @@ class LoginActivity : AppCompatActivity() {
val n = Net() val n = Net()
val response = n.registerAccount(server, username, password); val response = n.registerAccount(server, username, password);
//TODO: handle it properly when server will support Accept-Language header
if (response == "Such username exists") { if (response == "Such username exists") {
Toast.makeText(this, getString(R.string.username_already_exists), Toast.LENGTH_SHORT).show(); Toast.makeText(this, getString(R.string.username_already_exists), Toast.LENGTH_SHORT).show();
} else { } else {
sharedPreferences.edit().putString("token", response).apply() sharedPreferences.edit().putString("token", response).apply()
sharedPreferences.edit().putString("server", server).apply()
val intent = Intent(this, MainActivity::class.java) val intent = Intent(this, MainActivity::class.java)
startActivity(intent) startActivity(intent)
finish() finish()

View File

@ -1,14 +1,18 @@
package org.foxarmy.barcodescannerforemployees.activities package org.foxarmy.barcodescannerforemployees.activities
//import android.R
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import com.google.android.material.navigation.NavigationView
import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter
import org.foxarmy.barcodescannerforemployees.databinding.ActivityMainBinding import org.foxarmy.barcodescannerforemployees.databinding.ActivityMainBinding
@ -17,10 +21,13 @@ import org.foxarmy.barcodescannerforemployees.fragments.CategoriesFragment
import org.foxarmy.barcodescannerforemployees.fragments.ShelfFragment import org.foxarmy.barcodescannerforemployees.fragments.ShelfFragment
import org.foxarmy.barcodescannerforemployees.fragments.StorageFragment import org.foxarmy.barcodescannerforemployees.fragments.StorageFragment
class MainActivity : AppCompatActivity() {
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
lateinit var adapter: ViewPagerAdapter lateinit var adapter: ViewPagerAdapter
var drawerLayout: DrawerLayout? = null
var actionBarDrawerToggle: ActionBarDrawerToggle? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -32,6 +39,16 @@ class MainActivity : AppCompatActivity() {
setupViewPager(binding.tabViewpager) setupViewPager(binding.tabViewpager)
binding.tabTablayout.setupWithViewPager(binding.tabViewpager) binding.tabTablayout.setupWithViewPager(binding.tabViewpager)
drawerLayout = binding.drawerLayout
actionBarDrawerToggle = ActionBarDrawerToggle(this, drawerLayout, R.string.nav_open, R.string.nav_close)
drawerLayout!!.addDrawerListener(actionBarDrawerToggle!!)
actionBarDrawerToggle!!.syncState()
binding.navView.setNavigationItemSelectedListener(this)
// to make the Navigation drawer icon always appear on the action bar
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
binding.expiryCalendarFab.setOnClickListener { _ -> binding.expiryCalendarFab.setOnClickListener { _ ->
val expiryCalendarIntent = Intent(this, ExpiryCalendarActivity::class.java) val expiryCalendarIntent = Intent(this, ExpiryCalendarActivity::class.java)
val extras = Bundle() val extras = Bundle()
@ -82,7 +99,7 @@ class MainActivity : AppCompatActivity() {
adapter.addFragment(ShelfFragment(), getString(R.string.shelf_title)) adapter.addFragment(ShelfFragment(), getString(R.string.shelf_title))
adapter.addFragment(CategoriesFragment(), getString(R.string.categories_title)) adapter.addFragment(CategoriesFragment(), getString(R.string.categories_title))
//TODO: settings fragments //TODO: Settings
// setting adapter to view pager. // setting adapter to view pager.
viewpager.adapter = adapter viewpager.adapter = adapter
@ -90,76 +107,100 @@ class MainActivity : AppCompatActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu) menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
lateinit var intent: Intent
when (item.itemId) {
R.id.nav_account -> {
intent = Intent(this, AccountSettingsActivity::class.java)
}
R.id.nav_groups -> {
intent = Intent(this, AccountSettingsActivity::class.java)
}
R.id.nav_settings -> {
//TODO: Settings
return false
}
}
startActivity(intent)
return true return true
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
val currentPosition = binding.tabTablayout.selectedTabPosition if (actionBarDrawerToggle!!.onOptionsItemSelected(item)) {
val fragment = adapter.getItem(currentPosition) return true
} else {
return when (item.itemId) { val currentPosition = binding.tabTablayout.selectedTabPosition
val fragment = adapter.getItem(currentPosition)
return when (item.itemId) {
R.id.action_settings -> { R.id.action_settings -> {
true true
}
R.id.action_delete -> {
when (fragment::class.simpleName.toString()) {
"StorageFragment" -> {
AlertDialog.Builder(this)
.setMessage(getString(R.string.deleting_abstract_product_warning))
.setPositiveButton(getString(R.string.yes)) { _: DialogInterface, _: Int ->
val storageFragment = fragment as StorageFragment
storageFragment.removeSelected()
}
.setNegativeButton(getString(R.string.no)) { _: DialogInterface, _: Int ->
}.show()
}
"CategoriesFragment" -> {
AlertDialog.Builder(this)
.setMessage(getString(R.string.deleting_category_warning))
.setPositiveButton(getString(R.string.yes)) { _: DialogInterface, _: Int ->
val categoriesFragment = fragment as CategoriesFragment
categoriesFragment.removeSelected()
}
.setNegativeButton(getString(R.string.no)) { _: DialogInterface, _: Int ->
}.show()
}
"ShelfFragment" -> {
val shelfFragment = fragment as ShelfFragment
shelfFragment.removeSelected()
}
} }
true
}
R.id.action_update -> { R.id.action_delete -> {
when (fragment::class.simpleName.toString()) {
"StorageFragment" -> {
val storageFragment = fragment as StorageFragment
storageFragment.updateSelected()
}
"CategoriesFragment" -> { when (fragment::class.simpleName.toString()) {
val categoriesFragment = fragment as CategoriesFragment "StorageFragment" -> {
categoriesFragment.updateSelected() AlertDialog.Builder(this)
} .setMessage(getString(R.string.deleting_abstract_product_warning))
.setPositiveButton(getString(R.string.yes)) { _: DialogInterface, _: Int ->
val storageFragment = fragment as StorageFragment
storageFragment.removeSelected()
}
.setNegativeButton(getString(R.string.no)) { _: DialogInterface, _: Int ->
"ShelfFragment" -> { }.show()
val shelfFragment = fragment as ShelfFragment }
shelfFragment.updateSelected()
"CategoriesFragment" -> {
AlertDialog.Builder(this)
.setMessage(getString(R.string.deleting_category_warning))
.setPositiveButton(getString(R.string.yes)) { _: DialogInterface, _: Int ->
val categoriesFragment = fragment as CategoriesFragment
categoriesFragment.removeSelected()
}
.setNegativeButton(getString(R.string.no)) { _: DialogInterface, _: Int ->
}.show()
}
"ShelfFragment" -> {
val shelfFragment = fragment as ShelfFragment
shelfFragment.removeSelected()
}
} }
true
} }
true
}
else -> super.onOptionsItemSelected(item) R.id.action_update -> {
when (fragment::class.simpleName.toString()) {
"StorageFragment" -> {
val storageFragment = fragment as StorageFragment
storageFragment.updateSelected()
}
"CategoriesFragment" -> {
val categoriesFragment = fragment as CategoriesFragment
categoriesFragment.updateSelected()
}
"ShelfFragment" -> {
val shelfFragment = fragment as ShelfFragment
shelfFragment.updateSelected()
}
}
true
}
else -> super.onOptionsItemSelected(item)
}
} }
} }
fun filterAbstractProductsByCategory(id: Int) { fun filterAbstractProductsByCategory(id: Int) {

View File

@ -20,7 +20,7 @@ class NavigatorActivity : Activity() {
finish(); finish();
} }
fun isAuthenticated(): Boolean { private fun isAuthenticated(): Boolean {
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val sharedPreferences = EncryptedSharedPreferences.create( val sharedPreferences = EncryptedSharedPreferences.create(

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:ems="10"
android:id="@+id/newPasswordTextEdit"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.497" android:hint="@string/new_password"
app:layout_constraintTop_toBottomOf="@+id/saveUsernameButton" android:layout_marginTop="64dp"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text"
android:ems="10"
android:id="@+id/newUsernameTextEdit"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
android:hint="@string/new_name" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="48dp"/>
<Button
android:text="@string/saveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/saveUsernameButton"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/newUsernameTextEdit" android:layout_marginTop="16dp"/>
<Button
android:text="@string/saveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/savePasswordButton"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/newPasswordTextEdit"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".activities.MainActivity" tools:context=".activities.MainActivity"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true" android:id="@+id/drawer_layout">
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -69,6 +69,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="start" android:layout_gravity="start"
app:menu="@menu/drawer_menu" /> app:menu="@menu/drawer_menu" android:id="@+id/nav_view"/>
</androidx.drawerlayout.widget.DrawerLayout> </androidx.drawerlayout.widget.DrawerLayout>

View File

@ -7,10 +7,9 @@
android:title="@string/my_account" /> android:title="@string/my_account" />
<item <item
android:id="@+id/nav_settings" android:id="@+id/nav_groups"
android:title="@string/settings" />
<item
android:id="@+id/nav_logout"
android:title="@string/my_groups" /> android:title="@string/my_groups" />
<item
android:id="@+id/nav_settings"
android:title="@string/settings"/>
</menu> </menu>

View File

@ -99,4 +99,8 @@
<string name="server">Сервер</string> <string name="server">Сервер</string>
<string name="my_account">Мой аккаунт</string> <string name="my_account">Мой аккаунт</string>
<string name="my_groups">Мои группы</string> <string name="my_groups">Мои группы</string>
<string name="nav_open">navigation open</string>
<string name="nav_close">Navigation close</string>
<string name="new_name">New name</string>
<string name="new_password">New password</string>
</resources> </resources>

View File

@ -97,4 +97,8 @@
<string name="server">Server</string> <string name="server">Server</string>
<string name="my_account">My account</string> <string name="my_account">My account</string>
<string name="my_groups">My groups</string> <string name="my_groups">My groups</string>
<string name="nav_open">navigation open</string>
<string name="nav_close">Navigation close</string>
<string name="new_name">New name</string>
<string name="new_password">New password</string>
</resources> </resources>