diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml
new file mode 100644
index 0000000..91f9558
--- /dev/null
+++ b/.idea/deviceManager.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/dano/test1/MainActivity.kt b/app/src/main/java/com/dano/test1/MainActivity.kt
index fe96e8b..99646fe 100644
--- a/app/src/main/java/com/dano/test1/MainActivity.kt
+++ b/app/src/main/java/com/dano/test1/MainActivity.kt
@@ -13,7 +13,11 @@ import android.widget.ProgressBar
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
-import java.io.File
+import com.dano.test1.network.DatabaseDownloader
+import com.dano.test1.network.LoginManager
+import com.dano.test1.network.TokenStore
+import com.dano.test1.questionnaire.QuestionnaireBase
+import com.dano.test1.ui.HandlerOpeningScreen
class MainActivity : AppCompatActivity() {
diff --git a/app/src/main/java/com/dano/test1/AppDatabase.kt b/app/src/main/java/com/dano/test1/data/AppDatabase.kt
similarity index 100%
rename from app/src/main/java/com/dano/test1/AppDatabase.kt
rename to app/src/main/java/com/dano/test1/data/AppDatabase.kt
diff --git a/app/src/main/java/com/dano/test1/Daos.kt b/app/src/main/java/com/dano/test1/data/Daos.kt
similarity index 100%
rename from app/src/main/java/com/dano/test1/Daos.kt
rename to app/src/main/java/com/dano/test1/data/Daos.kt
diff --git a/app/src/main/java/com/dano/test1/Entities.kt b/app/src/main/java/com/dano/test1/data/Entities.kt
similarity index 100%
rename from app/src/main/java/com/dano/test1/Entities.kt
rename to app/src/main/java/com/dano/test1/data/Entities.kt
diff --git a/app/src/main/java/com/dano/test1/ExcelExportService.kt b/app/src/main/java/com/dano/test1/data/ExcelExportService.kt
similarity index 96%
rename from app/src/main/java/com/dano/test1/ExcelExportService.kt
rename to app/src/main/java/com/dano/test1/data/ExcelExportService.kt
index 744f8af..2b0536d 100644
--- a/app/src/main/java/com/dano/test1/ExcelExportService.kt
+++ b/app/src/main/java/com/dano/test1/data/ExcelExportService.kt
@@ -1,4 +1,4 @@
-package com.dano.test1
+package com.dano.test1.data
import android.content.ContentValues
import android.content.Context
@@ -7,8 +7,12 @@ import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
+import com.dano.test1.LanguageManager
+import com.dano.test1.MyApp
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.xssf.usermodel.XSSFWorkbook
+import java.io.ByteArrayOutputStream
+import java.io.File
/*
Aufgabe:
@@ -83,7 +87,7 @@ class ExcelExportService(
}
}
- val bytes = java.io.ByteArrayOutputStream().use { bos ->
+ val bytes = ByteArrayOutputStream().use { bos ->
wb.write(bos); bos.toByteArray()
}
wb.close()
@@ -112,7 +116,7 @@ class ExcelExportService(
} else {
val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
if (!downloadsDir.exists()) downloadsDir.mkdirs()
- val outFile = java.io.File(downloadsDir, filename)
+ val outFile = File(downloadsDir, filename)
outFile.writeBytes(bytes)
MediaScannerConnection.scanFile(
context,
@@ -175,4 +179,4 @@ class ExcelExportService(
for (key in candidates) localizeEnglishNoBrackets(key)?.let { return it }
return raw
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dano/test1/HeaderOrderRepository.kt b/app/src/main/java/com/dano/test1/data/HeaderOrderRepository.kt
similarity index 86%
rename from app/src/main/java/com/dano/test1/HeaderOrderRepository.kt
rename to app/src/main/java/com/dano/test1/data/HeaderOrderRepository.kt
index a9df8ea..b42db5c 100644
--- a/app/src/main/java/com/dano/test1/HeaderOrderRepository.kt
+++ b/app/src/main/java/com/dano/test1/data/HeaderOrderRepository.kt
@@ -1,8 +1,11 @@
-package com.dano.test1
+package com.dano.test1.data
import android.content.Context
import android.util.Log
import android.widget.Toast
+import com.dano.test1.LanguageManager
+import org.apache.poi.ss.usermodel.CellType
+import org.apache.poi.ss.usermodel.DateUtil
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.json.JSONArray
import java.nio.charset.Charset
@@ -63,16 +66,16 @@ class HeaderOrderRepository(
for (i in first until last) {
val cell = row.getCell(i) ?: continue
val value = when (cell.cellType) {
- org.apache.poi.ss.usermodel.CellType.STRING -> cell.stringCellValue
- org.apache.poi.ss.usermodel.CellType.NUMERIC ->
- if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))
+ CellType.STRING -> cell.stringCellValue
+ CellType.NUMERIC ->
+ if (DateUtil.isCellDateFormatted(cell))
cell.dateCellValue.time.toString()
else {
val n = cell.numericCellValue
if (n % 1.0 == 0.0) n.toLong().toString() else n.toString()
}
- org.apache.poi.ss.usermodel.CellType.BOOLEAN -> cell.booleanCellValue.toString()
- org.apache.poi.ss.usermodel.CellType.FORMULA -> cell.richStringCellValue.string
+ CellType.BOOLEAN -> cell.booleanCellValue.toString()
+ CellType.FORMULA -> cell.richStringCellValue.string
else -> ""
}.trim()
diff --git a/app/src/main/java/com/dano/test1/DatabaseDownloader.kt b/app/src/main/java/com/dano/test1/network/DatabaseDownloader.kt
similarity index 97%
rename from app/src/main/java/com/dano/test1/DatabaseDownloader.kt
rename to app/src/main/java/com/dano/test1/network/DatabaseDownloader.kt
index 39aa418..178c5d9 100644
--- a/app/src/main/java/com/dano/test1/DatabaseDownloader.kt
+++ b/app/src/main/java/com/dano/test1/network/DatabaseDownloader.kt
@@ -1,7 +1,8 @@
-package com.dano.test1
+package com.dano.test1.network
import android.content.Context
import android.util.Log
+import com.dano.test1.AES256Helper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
diff --git a/app/src/main/java/com/dano/test1/DatabaseUploader.kt b/app/src/main/java/com/dano/test1/network/DatabaseUploader.kt
similarity index 99%
rename from app/src/main/java/com/dano/test1/DatabaseUploader.kt
rename to app/src/main/java/com/dano/test1/network/DatabaseUploader.kt
index b054f7c..09814e9 100644
--- a/app/src/main/java/com/dano/test1/DatabaseUploader.kt
+++ b/app/src/main/java/com/dano/test1/network/DatabaseUploader.kt
@@ -1,4 +1,4 @@
-package com.dano.test1
+package com.dano.test1.network
import android.content.Context
import android.database.sqlite.SQLiteDatabase
@@ -8,6 +8,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import android.database.Cursor
+import com.dano.test1.AES256Helper
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.asRequestBody
diff --git a/app/src/main/java/com/dano/test1/LoginManager.kt b/app/src/main/java/com/dano/test1/network/LoginManager.kt
similarity index 95%
rename from app/src/main/java/com/dano/test1/LoginManager.kt
rename to app/src/main/java/com/dano/test1/network/LoginManager.kt
index ce7b22d..8e3732f 100644
--- a/app/src/main/java/com/dano/test1/LoginManager.kt
+++ b/app/src/main/java/com/dano/test1/network/LoginManager.kt
@@ -1,9 +1,9 @@
-package com.dano.test1
+package com.dano.test1.network
import android.app.AlertDialog
import android.content.Context
+import android.text.InputType
import android.util.Log
-import android.view.LayoutInflater
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.Toast
@@ -96,13 +96,13 @@ object LoginManager {
}
val etNew = EditText(context).apply {
hint = "Neues Passwort"
- inputType = android.text.InputType.TYPE_CLASS_TEXT or
- android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD
+ inputType = InputType.TYPE_CLASS_TEXT or
+ InputType.TYPE_TEXT_VARIATION_PASSWORD
}
val etRepeat = EditText(context).apply {
hint = "Neues Passwort (wiederholen)"
- inputType = android.text.InputType.TYPE_CLASS_TEXT or
- android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD
+ inputType = InputType.TYPE_CLASS_TEXT or
+ InputType.TYPE_TEXT_VARIATION_PASSWORD
}
container.addView(etNew)
container.addView(etRepeat)
diff --git a/app/src/main/java/com/dano/test1/NetworkUtilis.kt b/app/src/main/java/com/dano/test1/network/NetworkUtilis.kt
similarity index 97%
rename from app/src/main/java/com/dano/test1/NetworkUtilis.kt
rename to app/src/main/java/com/dano/test1/network/NetworkUtilis.kt
index a59405a..0a2bb0e 100644
--- a/app/src/main/java/com/dano/test1/NetworkUtilis.kt
+++ b/app/src/main/java/com/dano/test1/network/NetworkUtilis.kt
@@ -1,4 +1,4 @@
-package com.dano.test1
+package com.dano.test1.network
import android.content.Context
import android.net.ConnectivityManager
diff --git a/app/src/main/java/com/dano/test1/TokenStore.kt b/app/src/main/java/com/dano/test1/network/TokenStore.kt
similarity index 98%
rename from app/src/main/java/com/dano/test1/TokenStore.kt
rename to app/src/main/java/com/dano/test1/network/TokenStore.kt
index 44b950a..86a8d1f 100644
--- a/app/src/main/java/com/dano/test1/TokenStore.kt
+++ b/app/src/main/java/com/dano/test1/network/TokenStore.kt
@@ -1,4 +1,4 @@
-package com.dano.test1
+package com.dano.test1.network
import android.content.Context
diff --git a/app/src/main/java/com/dano/test1/QuestionHandler.kt b/app/src/main/java/com/dano/test1/questionnaire/QuestionHandler.kt
similarity index 80%
rename from app/src/main/java/com/dano/test1/QuestionHandler.kt
rename to app/src/main/java/com/dano/test1/questionnaire/QuestionHandler.kt
index 63f8d51..9660676 100644
--- a/app/src/main/java/com/dano/test1/QuestionHandler.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/QuestionHandler.kt
@@ -1,4 +1,4 @@
-package com.dano.test1
+package com.dano.test1.questionnaire
import android.view.View
interface QuestionHandler {
diff --git a/app/src/main/java/com/dano/test1/QuestionnaireBase.kt b/app/src/main/java/com/dano/test1/questionnaire/QuestionnaireBase.kt
similarity index 90%
rename from app/src/main/java/com/dano/test1/QuestionnaireBase.kt
rename to app/src/main/java/com/dano/test1/questionnaire/QuestionnaireBase.kt
index f97b609..466f6d7 100644
--- a/app/src/main/java/com/dano/test1/QuestionnaireBase.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/QuestionnaireBase.kt
@@ -1,10 +1,23 @@
-package com.dano.test1
+package com.dano.test1.questionnaire
+import android.R
import android.app.Activity
import android.util.Log
import android.view.View
import android.widget.*
+import com.dano.test1.LanguageManager
+import com.dano.test1.MainActivity
+import com.dano.test1.MyApp
import com.dano.test1.data.*
+import com.dano.test1.questionnaire.handlers.HandlerClientCoachCode
+import com.dano.test1.questionnaire.handlers.HandlerClientNotSigned
+import com.dano.test1.questionnaire.handlers.HandlerDateSpinner
+import com.dano.test1.questionnaire.handlers.HandlerGlassScaleQuestion
+import com.dano.test1.questionnaire.handlers.HandlerLastPage
+import com.dano.test1.questionnaire.handlers.HandlerMultiCheckboxQuestion
+import com.dano.test1.questionnaire.handlers.HandlerRadioQuestion
+import com.dano.test1.questionnaire.handlers.HandlerStringSpinner
+import com.dano.test1.questionnaire.handlers.HandlerValueSpinner
import com.google.gson.Gson
import com.google.gson.JsonParser
import kotlinx.coroutines.*
@@ -61,8 +74,8 @@ abstract class QuestionnaireBase {
}
protected fun setupSpinner(spinner: Spinner, spinnerValues: List, selectedValue: Any?) {
- val adapter = ArrayAdapter(context, android.R.layout.simple_spinner_item, spinnerValues).apply {
- setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ val adapter = ArrayAdapter(context, R.layout.simple_spinner_item, spinnerValues).apply {
+ setDropDownViewResource(R.layout.simple_spinner_dropdown_item)
}
spinner.adapter = adapter
selectedValue?.let { value ->
@@ -75,7 +88,7 @@ abstract class QuestionnaireBase {
protected fun navigateTo(layoutResId: Int, setup: (View) -> Unit) {
context.setContentView(layoutResId)
- val rootView = context.findViewById(android.R.id.content)
+ val rootView = context.findViewById(R.id.content)
setup(rootView)
}
@@ -85,7 +98,7 @@ abstract class QuestionnaireBase {
protected fun showEmptyScreen() {
navigateTo(getLayoutResId("empty")) {
- setupPrevButton(R.id.Qprev) { goToPreviousQuestion() }
+ setupPrevButton(com.dano.test1.R.id.Qprev) { goToPreviousQuestion() }
}
}
diff --git a/app/src/main/java/com/dano/test1/QuestionnaireGeneric.kt b/app/src/main/java/com/dano/test1/questionnaire/QuestionnaireGeneric.kt
similarity index 91%
rename from app/src/main/java/com/dano/test1/QuestionnaireGeneric.kt
rename to app/src/main/java/com/dano/test1/questionnaire/QuestionnaireGeneric.kt
index 36f1c03..3e95693 100644
--- a/app/src/main/java/com/dano/test1/QuestionnaireGeneric.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/QuestionnaireGeneric.kt
@@ -1,6 +1,8 @@
-package com.dano.test1
+package com.dano.test1.questionnaire
import android.widget.Button
+import com.dano.test1.LocalizationHelper
+import com.dano.test1.R
open class QuestionnaireGeneric(private val questionnaireFileName: String) : QuestionnaireBase() {
diff --git a/app/src/main/java/com/dano/test1/QuestionnaireItem.kt b/app/src/main/java/com/dano/test1/questionnaire/QuestionnaireItem.kt
similarity index 99%
rename from app/src/main/java/com/dano/test1/QuestionnaireItem.kt
rename to app/src/main/java/com/dano/test1/questionnaire/QuestionnaireItem.kt
index 1710b22..bc15005 100644
--- a/app/src/main/java/com/dano/test1/QuestionnaireItem.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/QuestionnaireItem.kt
@@ -1,4 +1,4 @@
-package com.dano.test1
+package com.dano.test1.questionnaire
data class Option(
val key: String, // Must always be set
diff --git a/app/src/main/java/com/dano/test1/HandlerClientCoachCode.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerClientCoachCode.kt
similarity index 78%
rename from app/src/main/java/com/dano/test1/HandlerClientCoachCode.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerClientCoachCode.kt
index 3103ba9..e4d0525 100644
--- a/app/src/main/java/com/dano/test1/HandlerClientCoachCode.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerClientCoachCode.kt
@@ -1,9 +1,15 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.view.View
import android.widget.*
-import android.util.TypedValue
-import androidx.core.widget.TextViewCompat
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.network.TokenStore
+import com.dano.test1.utils.ViewUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -38,10 +44,10 @@ class HandlerClientCoachCode(
questionTextView.text = question.question?.let { LanguageManager.getText(languageID, it) } ?: ""
- setTextSizePercentOfScreenHeight(titleTextView, 0.03f)
- setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
- setTextSizePercentOfScreenHeight(clientCodeField, 0.025f)
- setTextSizePercentOfScreenHeight(coachCodeField, 0.025f)
+ ViewUtils.setTextSizePercentOfScreenHeight(titleTextView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(clientCodeField, 0.025f)
+ ViewUtils.setTextSizePercentOfScreenHeight(coachCodeField, 0.025f)
// Client-Code: nur verwenden, wenn bereits geladen
val loadedClientCode = GlobalValues.LOADED_CLIENT_CODE
@@ -57,7 +63,7 @@ class HandlerClientCoachCode(
val coachFromLogin = TokenStore.getUsername(layout.context)
if (!coachFromLogin.isNullOrBlank()) {
coachCodeField.setText(coachFromLogin)
- lockCoachField(coachCodeField) // optisch & technisch gesperrt
+ ViewUtils.lockEditField(coachCodeField) // optisch & technisch gesperrt
} else {
// Falls (theoretisch) kein Login-Username vorhanden ist, verhalten wie bisher
coachCodeField.setText(answers["coach_code"] as? String ?: "")
@@ -72,13 +78,6 @@ class HandlerClientCoachCode(
}
}
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = layout.resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
-
private fun onNextClicked(clientCodeField: EditText, coachCodeField: EditText) {
val loadedClientCode = GlobalValues.LOADED_CLIENT_CODE
@@ -143,19 +142,4 @@ class HandlerClientCoachCode(
// Not used
}
- private fun lockCoachField(field: EditText) {
- field.isFocusable = false
- field.isFocusableInTouchMode = false
- field.isCursorVisible = false
- field.keyListener = null
- field.isLongClickable = false
- field.isClickable = false
- field.setBackgroundResource(R.drawable.bg_field_locked)
- field.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_lock_24, 0)
- field.compoundDrawablePadding = dp(8)
- field.alpha = 0.95f
- }
-
- private fun dp(v: Int): Int =
- (v * layout.resources.displayMetrics.density).toInt()
}
diff --git a/app/src/main/java/com/dano/test1/HandlerClientNotSigned.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerClientNotSigned.kt
similarity index 92%
rename from app/src/main/java/com/dano/test1/HandlerClientNotSigned.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerClientNotSigned.kt
index 34b91f8..3fbb290 100644
--- a/app/src/main/java/com/dano/test1/HandlerClientNotSigned.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerClientNotSigned.kt
@@ -1,7 +1,11 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.view.View
import android.widget.*
+import com.dano.test1.LanguageManager
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
/*
Zweck:
diff --git a/app/src/main/java/com/dano/test1/HandlerDateSpinner.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerDateSpinner.kt
similarity index 66%
rename from app/src/main/java/com/dano/test1/HandlerDateSpinner.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerDateSpinner.kt
index 55ceede..3823a9d 100644
--- a/app/src/main/java/com/dano/test1/HandlerDateSpinner.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerDateSpinner.kt
@@ -1,15 +1,21 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.content.Context
import android.view.View
-import android.view.ViewGroup
import android.widget.*
import kotlinx.coroutines.*
import java.text.SimpleDateFormat
import java.util.*
-import android.util.TypedValue
-import androidx.core.widget.TextViewCompat
-import android.widget.AbsListView
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.questionnaire.MAX_VALUE_YEAR
+import com.dano.test1.ui.Month
+import com.dano.test1.ui.Months
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.utils.ViewUtils
/*
Zweck:
@@ -52,12 +58,11 @@ class HandlerDateSpinner(
textView.text = question.textKey?.let { LanguageManager.getText(languageID, it) } ?: ""
// Schriftgrößen pro Bildschirmhöhe
- setTextSizePercentOfScreenHeight(textView, 0.03f) // oben
- setTextSizePercentOfScreenHeight(questionTextView, 0.03f) // frage
- setTextSizePercentOfScreenHeight(labelDay, 0.025f)
- setTextSizePercentOfScreenHeight(labelMonth, 0.025f)
- setTextSizePercentOfScreenHeight(labelYear, 0.025f)
- //
+ ViewUtils.setTextSizePercentOfScreenHeight(textView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(labelDay, 0.025f)
+ ViewUtils.setTextSizePercentOfScreenHeight(labelMonth, 0.025f)
+ ViewUtils.setTextSizePercentOfScreenHeight(labelYear, 0.025f)
// gespeicherte Antwort (YYYY-MM-DD) lesen
val (savedYear, savedMonthIndex, savedDay) = question.question?.let {
@@ -75,9 +80,9 @@ class HandlerDateSpinner(
val defaultYear = savedYear ?: today.get(Calendar.YEAR)
// Spinner responsiv aufsetzen (Schrift + Zeilenhöhe ohne Abschneiden)
- setupSpinner(spinnerDay, days, defaultDay)
- setupSpinner(spinnerMonth, months, defaultMonth)
- setupSpinner(spinnerYear, years, defaultYear)
+ ViewUtils.setupResponsiveSpinner(context, spinnerDay, days, defaultDay)
+ ViewUtils.setupResponsiveSpinner(context, spinnerMonth, months, defaultMonth)
+ ViewUtils.setupResponsiveSpinner(context, spinnerYear, years, defaultYear)
// DB-Abfrage, falls noch nicht im answers-Map
val answerMapKey = question.question ?: (question.id ?: "")
@@ -207,71 +212,4 @@ class HandlerDateSpinner(
return sdf.parse(dateString)
}
- // Textgröße prozentual zur Bildschirmhöhe (in sp)
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = (view.context ?: layout.context).resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
-
- // Spinner-Adapter: Schrift & Zeilenhöhe dynamisch, kein Abschneiden
- private fun setupSpinner(spinner: Spinner, items: List, defaultSelection: T?) {
- val dm = context.resources.displayMetrics
-
- fun spFromScreenHeight(percent: Float): Float =
- (dm.heightPixels * percent) / dm.scaledDensity
- fun pxFromSp(sp: Float): Int = (sp * dm.scaledDensity).toInt()
-
- val textSp = spFromScreenHeight(0.0275f) // ~2.75% der Bildschirmhöhe
- val textPx = pxFromSp(textSp)
- val vPadPx = (textPx * 0.50f).toInt() // vertikales Padding
- val rowHeight = (textPx * 2.20f + 2 * vPadPx).toInt() // feste Zeilenhöhe
-
- val adapter = object : ArrayAdapter(context, android.R.layout.simple_spinner_item, items) {
- private fun styleRow(tv: TextView, forceHeight: Boolean) {
- tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSp)
- tv.includeFontPadding = true
- tv.setLineSpacing(0f, 1.2f)
- tv.gravity = (tv.gravity and android.view.Gravity.HORIZONTAL_GRAVITY_MASK) or android.view.Gravity.CENTER_VERTICAL
- tv.setPadding(tv.paddingLeft, vPadPx, tv.paddingRight, vPadPx)
- tv.minHeight = rowHeight
- tv.isSingleLine = true
- if (forceHeight) {
- val lp = tv.layoutParams
- if (lp == null || lp.height <= 0) {
- tv.layoutParams = AbsListView.LayoutParams(
- AbsListView.LayoutParams.MATCH_PARENT, rowHeight
- )
- } else {
- lp.height = rowHeight
- }
- }
- }
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val v = super.getView(position, convertView, parent) as TextView
- styleRow(v, forceHeight = false)
- return v
- }
-
- override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
- val v = super.getDropDownView(position, convertView, parent) as TextView
- styleRow(v, forceHeight = true)
- return v
- }
- }
-
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
- spinner.adapter = adapter
-
- spinner.setPadding(spinner.paddingLeft, vPadPx, spinner.paddingRight, vPadPx)
- spinner.minimumHeight = rowHeight
- spinner.requestLayout()
-
- defaultSelection?.let {
- val index = items.indexOf(it)
- if (index >= 0) spinner.setSelection(index)
- }
- }
}
diff --git a/app/src/main/java/com/dano/test1/HandlerGlassScaleQuestion.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerGlassScaleQuestion.kt
similarity index 94%
rename from app/src/main/java/com/dano/test1/HandlerGlassScaleQuestion.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerGlassScaleQuestion.kt
index 503b757..32d9825 100644
--- a/app/src/main/java/com/dano/test1/HandlerGlassScaleQuestion.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerGlassScaleQuestion.kt
@@ -1,11 +1,16 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.content.Context
-import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.widget.*
-import androidx.core.widget.TextViewCompat
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.utils.ViewUtils
import kotlinx.coroutines.*
/*
@@ -67,8 +72,8 @@ class HandlerGlassScaleQuestion(
titleTv.text = question.textKey?.let { LanguageManager.getText(languageID, it) } ?: ""
questionTv.text = question.question?.let { LanguageManager.getText(languageID, it) } ?: ""
- setTextSizePercentOfScreenHeight(titleTv, 0.03f)
- setTextSizePercentOfScreenHeight(questionTv, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(titleTv, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTv, 0.03f)
// Header Icons
val header = layout.findViewById(R.id.glass_header)
@@ -150,7 +155,7 @@ class HandlerGlassScaleQuestion(
text = LanguageManager.getText(languageID, symptomKey)
layoutParams = TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 4f)
setPadding(4, 16, 4, 16)
- setTextSizePercentOfScreenHeight(this, 0.022f)
+ ViewUtils.setTextSizePercentOfScreenHeight(this, 0.022f)
}
row.addView(symptomText)
@@ -277,10 +282,4 @@ class HandlerGlassScaleQuestion(
else -> null
}
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = (view.context ?: layout.context).resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/dano/test1/HandlerLastPage.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerLastPage.kt
similarity index 89%
rename from app/src/main/java/com/dano/test1/HandlerLastPage.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerLastPage.kt
index 55c28d9..a4c6e20 100644
--- a/app/src/main/java/com/dano/test1/HandlerLastPage.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerLastPage.kt
@@ -1,12 +1,18 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
+import android.util.TypedValue
import android.view.View
import android.widget.*
import android.text.Html
-import kotlinx.coroutines.*
-import android.util.TypedValue
-import android.widget.TextView
import androidx.core.widget.TextViewCompat
+import kotlinx.coroutines.*
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.MainActivity
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.utils.ViewUtils
import com.google.android.material.button.MaterialButton
/*
@@ -58,8 +64,8 @@ class HandlerLastPage(
applyResponsiveTextSizing(finishBtn)
// Überschriften responsiv skalieren (wie zuvor)
- setTextSizePercentOfScreenHeight(titleTv, 0.03f)
- setTextSizePercentOfScreenHeight(questionTv, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(titleTv, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTv, 0.03f)
// Buttons
prevBtn.setOnClickListener { goToPreviousQuestion() }
@@ -128,14 +134,6 @@ class HandlerLastPage(
}
// ----------------------------------------------------------------
- // Helper: Textgröße prozentual zur Bildschirmhöhe setzen (in sp)
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = (view.context ?: layout.context).resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
-
private fun sumPoints(): Int =
answers.filterKeys { it.endsWith("_points") }
.values.mapNotNull { it as? Int }
diff --git a/app/src/main/java/com/dano/test1/HandlerMultiCheckboxQuestion.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerMultiCheckboxQuestion.kt
similarity index 93%
rename from app/src/main/java/com/dano/test1/HandlerMultiCheckboxQuestion.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerMultiCheckboxQuestion.kt
index e24aa26..d4721e5 100644
--- a/app/src/main/java/com/dano/test1/HandlerMultiCheckboxQuestion.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerMultiCheckboxQuestion.kt
@@ -1,11 +1,18 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.content.Context
+import android.util.TypedValue
import android.view.View
import android.widget.*
-import kotlinx.coroutines.*
-import android.util.TypedValue
import androidx.core.widget.TextViewCompat
+import kotlinx.coroutines.*
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.utils.ViewUtils
/*
Zweck:
@@ -38,8 +45,8 @@ class HandlerMultiCheckboxQuestion(
questionTitle.text = this.question.question?.let { LanguageManager.getText(languageID, it) } ?: ""
// Textgrößen pro Bildschirmhöhe (wie bei deinen anderen Handlern)
- setTextSizePercentOfScreenHeight(questionTextView, 0.03f) // Überschrift
- setTextSizePercentOfScreenHeight(questionTitle, 0.03f) // Frage
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTitle, 0.03f)
container.removeAllViews()
@@ -204,10 +211,4 @@ class HandlerMultiCheckboxQuestion(
}
}
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = (view.context ?: layout.context).resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
}
diff --git a/app/src/main/java/com/dano/test1/HandlerRadioQuestion.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerRadioQuestion.kt
similarity index 85%
rename from app/src/main/java/com/dano/test1/HandlerRadioQuestion.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerRadioQuestion.kt
index 59bf3a0..c6431d5 100644
--- a/app/src/main/java/com/dano/test1/HandlerRadioQuestion.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerRadioQuestion.kt
@@ -1,12 +1,17 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.content.Context
import android.view.View
import android.text.Html
import android.widget.*
import kotlinx.coroutines.*
-import android.util.TypedValue
-import androidx.core.widget.TextViewCompat // <— hinzugefügt
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.utils.ViewUtils
/*
Zweck:
@@ -41,11 +46,8 @@ class HandlerRadioQuestion(
Html.fromHtml(LanguageManager.getText(languageID, it), Html.FROM_HTML_MODE_LEGACY)
} ?: ""
- //
- // Titel/Frage: 3% der Bildschirmhöhe
- setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
- setTextSizePercentOfScreenHeight(questionTitle, 0.03f)
- // ===================================================
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTitle, 0.03f)
radioGroup.removeAllViews()
@@ -55,7 +57,7 @@ class HandlerRadioQuestion(
tag = option.key
// RadioButton-Text analog zu EditTexts: 2.5% der Bildschirmhöhe
- setTextSizePercentOfScreenHeight(this, 0.025f)
+ ViewUtils.setTextSizePercentOfScreenHeight(this, 0.025f)
layoutParams = RadioGroup.LayoutParams(
RadioGroup.LayoutParams.MATCH_PARENT,
@@ -137,15 +139,6 @@ class HandlerRadioQuestion(
}
}
- // setzt Textgröße prozentual zur Bildschirmhöhe (in sp)
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = (view.context ?: layout.context).resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
- // ————————————————————————————————————————————————————————————————
-
private fun restorePreviousAnswer(radioGroup: RadioGroup) {
question.question?.let { questionKey ->
val savedAnswer = answers[questionKey] as? String
diff --git a/app/src/main/java/com/dano/test1/HandlerStringSpinner.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerStringSpinner.kt
similarity index 51%
rename from app/src/main/java/com/dano/test1/HandlerStringSpinner.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerStringSpinner.kt
index b101569..aad8f74 100644
--- a/app/src/main/java/com/dano/test1/HandlerStringSpinner.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerStringSpinner.kt
@@ -1,13 +1,17 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.content.Context
import android.view.View
-import android.view.ViewGroup
import android.widget.*
import kotlinx.coroutines.*
-import android.util.TypedValue
-import android.widget.TextView
-import androidx.core.widget.TextViewCompat
+import com.dano.test1.ui.Countries
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.utils.ViewUtils
/*
Zweck:
@@ -42,9 +46,9 @@ class HandlerStringSpinner(
questionTextView.text = question.question?.let { LanguageManager.getText(languageID, it) } ?: ""
textView.text = question.textKey?.let { LanguageManager.getText(languageID, it) } ?: ""
- // Textgrößen prozentual zur Bildschirmhöhe (wie im HandlerRadioQuestion)
- setTextSizePercentOfScreenHeight(textView, 0.03f)
- setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
+ // Textgrößen prozentual zur Bildschirmhöhe
+ ViewUtils.setTextSizePercentOfScreenHeight(textView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
val options = buildOptionsList()
@@ -52,7 +56,7 @@ class HandlerStringSpinner(
val savedSelection = question.question?.let { answers[it] as? String }
// Spinner aufsetzen
- setupSpinner(spinner, options, savedSelection)
+ ViewUtils.setupResponsiveSpinner(context, spinner, options, savedSelection)
// Falls noch keine Antwort im Map: aus DB laden
val answerMapKey = question.question ?: (question.id ?: "")
@@ -119,73 +123,4 @@ class HandlerStringSpinner(
}
}
- // Textgröße prozentual zur Bildschirmhöhe setzen und AutoSize deaktivieren
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = (view.context ?: layout.context).resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
-
- // Spinner-Adapter mit dynamischer Schrift & stabiler Dropdown-Zeilenhöhe (kein Abschneiden)
- private fun setupSpinner(spinner: Spinner, items: List, selectedItem: T?) {
- val dm = context.resources.displayMetrics
-
- fun spFromScreenHeight(percent: Float): Float =
- (dm.heightPixels * percent) / dm.scaledDensity
- fun pxFromSp(sp: Float): Int = (sp * dm.scaledDensity).toInt()
-
- // Schrift & abgeleitete Höhen (wie beim Value-Spinner-Fix)
- val textSp = spFromScreenHeight(0.0275f) // ~2.75% der Bildschirmhöhe
- val textPx = pxFromSp(textSp)
- val vPadPx = (textPx * 0.50f).toInt() // vertikales Padding
- val rowHeight = (textPx * 2.20f + 2 * vPadPx).toInt() // feste Zeilenhöhe, verhindert Abschneiden
-
- val adapter = object : ArrayAdapter(context, android.R.layout.simple_spinner_item, items) {
- private fun styleRow(tv: TextView, forceHeight: Boolean) {
- tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSp)
- tv.includeFontPadding = true
- tv.setLineSpacing(0f, 1.2f)
- tv.gravity = (tv.gravity and android.view.Gravity.HORIZONTAL_GRAVITY_MASK) or android.view.Gravity.CENTER_VERTICAL
- tv.setPadding(tv.paddingLeft, vPadPx, tv.paddingRight, vPadPx)
- tv.minHeight = rowHeight
- tv.isSingleLine = true
- if (forceHeight) {
- val lp = tv.layoutParams
- if (lp == null || lp.height <= 0) {
- tv.layoutParams = AbsListView.LayoutParams(
- AbsListView.LayoutParams.MATCH_PARENT, rowHeight
- )
- } else {
- lp.height = rowHeight
- }
- }
- }
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val v = super.getView(position, convertView, parent) as TextView
- styleRow(v, forceHeight = false) // ausgewählte Ansicht
- return v
- }
-
- override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
- val v = super.getDropDownView(position, convertView, parent) as TextView
- styleRow(v, forceHeight = true) // Dropdown-Zeilen: Höhe erzwingen
- return v
- }
- }
-
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
- spinner.adapter = adapter
-
- // Spinner selbst ausreichend hoch machen
- spinner.setPadding(spinner.paddingLeft, vPadPx, spinner.paddingRight, vPadPx)
- spinner.minimumHeight = rowHeight
- spinner.requestLayout()
-
- selectedItem?.let {
- val index = items.indexOf(it)
- if (index >= 0) spinner.setSelection(index)
- }
- }
}
diff --git a/app/src/main/java/com/dano/test1/HandlerValueSpinner.kt b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerValueSpinner.kt
similarity index 55%
rename from app/src/main/java/com/dano/test1/HandlerValueSpinner.kt
rename to app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerValueSpinner.kt
index d831d64..98eb66e 100644
--- a/app/src/main/java/com/dano/test1/HandlerValueSpinner.kt
+++ b/app/src/main/java/com/dano/test1/questionnaire/handlers/HandlerValueSpinner.kt
@@ -1,12 +1,16 @@
-package com.dano.test1
+package com.dano.test1.questionnaire.handlers
import android.content.Context
import android.view.View
-import android.view.ViewGroup
import android.widget.*
import kotlinx.coroutines.*
-import android.util.TypedValue
-import androidx.core.widget.TextViewCompat // <- NEU
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.LanguageManager
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.QuestionHandler
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.R
+import com.dano.test1.utils.ViewUtils
/*
Zweck:
@@ -43,10 +47,8 @@ class HandlerValueSpinner(
questionTextView.text = question.question?.let { LanguageManager.getText(languageID, it) } ?: ""
textView.text = question.textKey?.let { LanguageManager.getText(languageID, it) } ?: ""
-// Schriftgrößen wie im HandlerRadioQuestion
- // Titel/Frage: 3% der Bildschirmhöhe
- setTextSizePercentOfScreenHeight(textView, 0.03f)
- setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(textView, 0.03f)
+ ViewUtils.setTextSizePercentOfScreenHeight(questionTextView, 0.03f)
val prompt = LanguageManager.getText(languageID, "choose_answer")
val spinnerItems: List = listOf(prompt) + if (question.range != null) {
@@ -56,7 +58,7 @@ class HandlerValueSpinner(
}
val savedValue = question.question?.let { answers[it] as? String }
- setupSpinner(spinner, spinnerItems, savedValue)
+ ViewUtils.setupResponsiveSpinner(context, spinner, spinnerItems, savedValue)
//DB-Abfrage falls noch keine Antwort im Map existiert
val answerMapKey = question.question ?: (question.id ?: "")
@@ -127,72 +129,4 @@ class HandlerValueSpinner(
}
}
- // setzt Textgröße prozentual zur Bildschirmhöhe (in sp)
- private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
- val dm = (view.context ?: layout.context).resources.displayMetrics
- val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
- TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
- view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
- }
-
- private fun setupSpinner(spinner: Spinner, items: List, selectedItem: T?) {
- val dm = context.resources.displayMetrics
-
- fun spFromScreenHeight(percent: Float): Float =
- (dm.heightPixels * percent) / dm.scaledDensity
- fun pxFromSp(sp: Float): Int = (sp * dm.scaledDensity).toInt()
-
- // Schrift & abgeleitete Höhen
- val textSp = spFromScreenHeight(0.0275f) // ~2.75% der Bildschirmhöhe
- val textPx = pxFromSp(textSp)
- val vPadPx = (textPx * 0.50f).toInt() // vertikales Padding
- val rowHeight = (textPx * 2.20f + 2 * vPadPx).toInt() // feste Zeilenhöhe
-
- val adapter = object : ArrayAdapter(context, android.R.layout.simple_spinner_item, items) {
- private fun styleRow(tv: TextView, forceHeight: Boolean) {
- tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSp)
- tv.includeFontPadding = true
- tv.setLineSpacing(0f, 1.2f)
- tv.gravity = (tv.gravity and android.view.Gravity.HORIZONTAL_GRAVITY_MASK) or android.view.Gravity.CENTER_VERTICAL
- tv.setPadding(tv.paddingLeft, vPadPx, tv.paddingRight, vPadPx)
- tv.minHeight = rowHeight
- tv.isSingleLine = true
- if (forceHeight) {
- val lp = tv.layoutParams
- if (lp == null || lp.height <= 0) {
- tv.layoutParams = AbsListView.LayoutParams(
- AbsListView.LayoutParams.MATCH_PARENT, rowHeight
- )
- } else {
- lp.height = rowHeight
- }
- }
- }
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val v = super.getView(position, convertView, parent) as TextView
- styleRow(v, forceHeight = false) // ausgewählte Ansicht
- return v
- }
-
- override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
- val v = super.getDropDownView(position, convertView, parent) as TextView
- styleRow(v, forceHeight = true) // Dropdown-Zeilen: Höhe erzwingen
- return v
- }
- }
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
- spinner.adapter = adapter
-
- // Spinner selbst ausreichend hoch machen
- spinner.setPadding(spinner.paddingLeft, vPadPx, spinner.paddingRight, vPadPx)
- spinner.minimumHeight = rowHeight
- spinner.requestLayout()
-
- selectedItem?.let {
- val index = items.indexOf(it)
- if (index >= 0) spinner.setSelection(index)
- }
- }
-
}
diff --git a/app/src/main/java/com/dano/test1/CountriesSpinner.kt b/app/src/main/java/com/dano/test1/ui/CountriesSpinner.kt
similarity index 98%
rename from app/src/main/java/com/dano/test1/CountriesSpinner.kt
rename to app/src/main/java/com/dano/test1/ui/CountriesSpinner.kt
index 439d171..4350e7d 100644
--- a/app/src/main/java/com/dano/test1/CountriesSpinner.kt
+++ b/app/src/main/java/com/dano/test1/ui/CountriesSpinner.kt
@@ -1,4 +1,6 @@
-package com.dano.test1
+package com.dano.test1.ui
+
+import com.dano.test1.LanguageManager
object Countries {
fun getAllCountries(languageID: String): List {
diff --git a/app/src/main/java/com/dano/test1/DatabaseButtonHandler.kt b/app/src/main/java/com/dano/test1/ui/DatabaseButtonHandler.kt
similarity index 97%
rename from app/src/main/java/com/dano/test1/DatabaseButtonHandler.kt
rename to app/src/main/java/com/dano/test1/ui/DatabaseButtonHandler.kt
index ce50a2b..f4a0a74 100644
--- a/app/src/main/java/com/dano/test1/DatabaseButtonHandler.kt
+++ b/app/src/main/java/com/dano/test1/ui/DatabaseButtonHandler.kt
@@ -1,13 +1,21 @@
-package com.dano.test1
+package com.dano.test1.ui
+import android.graphics.Color
+import android.graphics.Typeface
import android.util.Log
import android.view.View
import android.widget.*
+import com.dano.test1.data.ExcelExportService
+import com.dano.test1.utils.ViewUtils
+import com.dano.test1.LanguageManager
+import com.dano.test1.MainActivity
+import com.dano.test1.MyApp
+import com.dano.test1.R
import com.dano.test1.data.Client
+import com.dano.test1.data.HeaderOrderRepository
import com.dano.test1.data.Question
import com.dano.test1.data.Questionnaire
import kotlinx.coroutines.*
-import kotlin.math.roundToInt
import org.json.JSONArray
class DatabaseButtonHandler(
@@ -361,7 +369,7 @@ class DatabaseButtonHandler(
val row = TableRow(activity).apply {
isClickable = true
isFocusable = true
- setBackgroundColor(android.graphics.Color.TRANSPARENT)
+ setBackgroundColor(Color.TRANSPARENT)
setOnClickListener { onClick() }
}
cells.forEachIndexed { index, text ->
@@ -396,7 +404,7 @@ class DatabaseButtonHandler(
this.text = text
setPadding(dp(12), dp(10), dp(12), dp(10))
textSize = 16f
- setTypeface(typeface, android.graphics.Typeface.BOLD)
+ setTypeface(typeface, Typeface.BOLD)
}
private fun makeBodyCell(
@@ -412,10 +420,7 @@ class DatabaseButtonHandler(
bgColor?.let { setBackgroundColor(it) }
}
- private fun dp(value: Int): Int {
- val density = activity.resources.displayMetrics.density
- return (value * density).roundToInt()
- }
+ private fun dp(value: Int): Int = ViewUtils.dp(activity, value)
private fun requireView(id: Int, name: String): T {
val v = activity.findViewById(id)
diff --git a/app/src/main/java/com/dano/test1/EditButtonHandler.kt b/app/src/main/java/com/dano/test1/ui/EditButtonHandler.kt
similarity index 95%
rename from app/src/main/java/com/dano/test1/EditButtonHandler.kt
rename to app/src/main/java/com/dano/test1/ui/EditButtonHandler.kt
index f0fa422..af170ea 100644
--- a/app/src/main/java/com/dano/test1/EditButtonHandler.kt
+++ b/app/src/main/java/com/dano/test1/ui/EditButtonHandler.kt
@@ -1,10 +1,14 @@
-package com.dano.test1
+package com.dano.test1.ui
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
+import com.dano.test1.LanguageManager
+import com.dano.test1.MainActivity
+import com.dano.test1.MyApp
import kotlinx.coroutines.*
import com.dano.test1.data.CompletedQuestionnaire
+import com.dano.test1.questionnaire.GlobalValues
class EditButtonHandler(
private val activity: MainActivity,
diff --git a/app/src/main/java/com/dano/test1/HandlerOpeningScreen.kt b/app/src/main/java/com/dano/test1/ui/HandlerOpeningScreen.kt
similarity index 95%
rename from app/src/main/java/com/dano/test1/HandlerOpeningScreen.kt
rename to app/src/main/java/com/dano/test1/ui/HandlerOpeningScreen.kt
index f3909f8..d6f86c3 100644
--- a/app/src/main/java/com/dano/test1/HandlerOpeningScreen.kt
+++ b/app/src/main/java/com/dano/test1/ui/HandlerOpeningScreen.kt
@@ -1,19 +1,33 @@
-package com.dano.test1
+package com.dano.test1.ui
+import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
import android.os.Handler
import android.os.Looper
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.widget.*
+import com.dano.test1.LanguageManager
+import com.dano.test1.MainActivity
+import com.dano.test1.R
+import com.dano.test1.network.DatabaseUploader
+import com.dano.test1.network.LoginManager
+import com.dano.test1.network.NetworkUtils
+import com.dano.test1.network.TokenStore
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.questionnaire.QuestionItem
+import com.dano.test1.questionnaire.QuestionnaireBase
+import com.dano.test1.questionnaire.QuestionnaireGeneric
import com.google.android.material.button.MaterialButton
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.util.concurrent.TimeUnit
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.dano.test1.utils.ViewUtils
var RHS_POINTS: Int? = null
@@ -559,7 +573,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
}
}
- private fun dp(v: Int): Int = (v * activity.resources.displayMetrics.density).toInt()
+ private fun dp(v: Int): Int = ViewUtils.dp(activity, v)
private fun isCompleted(button: Button): Boolean {
val fileName = questionnaireFiles[button] ?: return false
@@ -651,16 +665,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
}
private fun lockCoachCodeField() {
- coachEditText.isFocusable = false
- coachEditText.isFocusableInTouchMode = false
- coachEditText.isCursorVisible = false
- coachEditText.keyListener = null
- coachEditText.isLongClickable = false
- coachEditText.isClickable = false
- coachEditText.setBackgroundResource(R.drawable.bg_field_locked)
- coachEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_lock_24, 0)
- coachEditText.compoundDrawablePadding = dp(8)
- coachEditText.alpha = 0.95f
+ ViewUtils.lockEditField(coachEditText)
}
private fun applySessionAgeHighlight(ageMs: Long) {
@@ -682,22 +687,22 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
- private fun showRedToast(ctx: android.content.Context, message: String) {
- val tv = android.widget.TextView(ctx).apply {
+ private fun showRedToast(ctx: Context, message: String) {
+ val tv = TextView(ctx).apply {
text = message
- setTextColor(android.graphics.Color.WHITE)
+ setTextColor(Color.WHITE)
textSize = 16f
setPadding(32, 20, 32, 20)
- background = android.graphics.drawable.GradientDrawable().apply {
- shape = android.graphics.drawable.GradientDrawable.RECTANGLE
+ background = GradientDrawable().apply {
+ shape = GradientDrawable.RECTANGLE
cornerRadius = 24f
- setColor(android.graphics.Color.parseColor("#D32F2F")) // kräftiges Rot
+ setColor(Color.parseColor("#D32F2F")) // kräftiges Rot
}
}
- android.widget.Toast(ctx).apply {
- duration = android.widget.Toast.LENGTH_LONG
+ Toast(ctx).apply {
+ duration = Toast.LENGTH_LONG
view = tv
- setGravity(android.view.Gravity.TOP or android.view.Gravity.CENTER_HORIZONTAL, 0, 120)
+ setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL, 0, 120)
}.show()
}
diff --git a/app/src/main/java/com/dano/test1/LoadButtonHandler.kt b/app/src/main/java/com/dano/test1/ui/LoadButtonHandler.kt
similarity index 96%
rename from app/src/main/java/com/dano/test1/LoadButtonHandler.kt
rename to app/src/main/java/com/dano/test1/ui/LoadButtonHandler.kt
index dd2b699..8cde1c2 100644
--- a/app/src/main/java/com/dano/test1/LoadButtonHandler.kt
+++ b/app/src/main/java/com/dano/test1/ui/LoadButtonHandler.kt
@@ -1,10 +1,15 @@
-package com.dano.test1
+package com.dano.test1.ui
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
+import com.dano.test1.LanguageManager
+import com.dano.test1.MainActivity
+import com.dano.test1.MyApp
import kotlinx.coroutines.*
import com.dano.test1.data.CompletedQuestionnaire
+import com.dano.test1.questionnaire.GlobalValues
+import com.dano.test1.questionnaire.QuestionItem
class LoadButtonHandler(
private val activity: MainActivity,
diff --git a/app/src/main/java/com/dano/test1/MonthsSpinner.kt b/app/src/main/java/com/dano/test1/ui/MonthsSpinner.kt
similarity index 93%
rename from app/src/main/java/com/dano/test1/MonthsSpinner.kt
rename to app/src/main/java/com/dano/test1/ui/MonthsSpinner.kt
index 8d30a82..1e25bf7 100644
--- a/app/src/main/java/com/dano/test1/MonthsSpinner.kt
+++ b/app/src/main/java/com/dano/test1/ui/MonthsSpinner.kt
@@ -1,4 +1,6 @@
-package com.dano.test1
+package com.dano.test1.ui
+
+import com.dano.test1.LanguageManager
data class Month(val name: String) {
override fun toString(): String = name
diff --git a/app/src/main/java/com/dano/test1/SaveButtonHandler.kt b/app/src/main/java/com/dano/test1/ui/SaveButtonHandler.kt
similarity index 82%
rename from app/src/main/java/com/dano/test1/SaveButtonHandler.kt
rename to app/src/main/java/com/dano/test1/ui/SaveButtonHandler.kt
index 47812fc..4077eb7 100644
--- a/app/src/main/java/com/dano/test1/SaveButtonHandler.kt
+++ b/app/src/main/java/com/dano/test1/ui/SaveButtonHandler.kt
@@ -1,12 +1,21 @@
-package com.dano.test1
+package com.dano.test1.ui
+import android.content.ActivityNotFoundException
+import android.content.ContentUris
+import android.content.ContentValues
+import android.content.Intent
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.pdf.PdfDocument
+import android.provider.MediaStore
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
+import com.dano.test1.LanguageManager
+import com.dano.test1.MainActivity
+import com.dano.test1.MyApp
+import com.dano.test1.questionnaire.GlobalValues
import kotlinx.coroutines.*
class SaveButtonHandler(
@@ -105,19 +114,19 @@ class SaveButtonHandler(
val resolver = activity.contentResolver
val deleteIfExists: (String) -> Unit = { name ->
- val projection = arrayOf(android.provider.MediaStore.MediaColumns._ID)
- val selection = "${android.provider.MediaStore.MediaColumns.DISPLAY_NAME} = ?"
+ val projection = arrayOf(MediaStore.MediaColumns._ID)
+ val selection = "${MediaStore.MediaColumns.DISPLAY_NAME} = ?"
val selectionArgs = arrayOf(name)
val query = resolver.query(
- android.provider.MediaStore.Downloads.EXTERNAL_CONTENT_URI,
+ MediaStore.Downloads.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null
)
query?.use { cursor ->
if (cursor.moveToFirst()) {
- val idColumn = cursor.getColumnIndexOrThrow(android.provider.MediaStore.MediaColumns._ID)
+ val idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)
val id = cursor.getLong(idColumn)
- val deleteUri = android.content.ContentUris.withAppendedId(
- android.provider.MediaStore.Downloads.EXTERNAL_CONTENT_URI, id
+ val deleteUri = ContentUris.withAppendedId(
+ MediaStore.Downloads.EXTERNAL_CONTENT_URI, id
)
resolver.delete(deleteUri, null, null)
}
@@ -129,20 +138,20 @@ class SaveButtonHandler(
try {
val pdfUri = resolver.insert(
- android.provider.MediaStore.Downloads.EXTERNAL_CONTENT_URI,
- android.content.ContentValues().apply {
- put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, pdfFileName)
- put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "application/pdf")
- put(android.provider.MediaStore.MediaColumns.RELATIVE_PATH, "Download/")
+ MediaStore.Downloads.EXTERNAL_CONTENT_URI,
+ ContentValues().apply {
+ put(MediaStore.MediaColumns.DISPLAY_NAME, pdfFileName)
+ put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf")
+ put(MediaStore.MediaColumns.RELATIVE_PATH, "Download/")
}
)
val csvUri = resolver.insert(
- android.provider.MediaStore.Downloads.EXTERNAL_CONTENT_URI,
- android.content.ContentValues().apply {
- put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, csvFileName)
- put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "text/csv")
- put(android.provider.MediaStore.MediaColumns.RELATIVE_PATH, "Download/")
+ MediaStore.Downloads.EXTERNAL_CONTENT_URI,
+ ContentValues().apply {
+ put(MediaStore.MediaColumns.DISPLAY_NAME, csvFileName)
+ put(MediaStore.MediaColumns.MIME_TYPE, "text/csv")
+ put(MediaStore.MediaColumns.RELATIVE_PATH, "Download/")
}
)
@@ -162,13 +171,13 @@ class SaveButtonHandler(
Toast.makeText(activity, msg, Toast.LENGTH_LONG).show()
pdfUri?.let {
- val intent = android.content.Intent(android.content.Intent.ACTION_VIEW).apply {
+ val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(it, "application/pdf")
- addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION or android.content.Intent.FLAG_ACTIVITY_NO_HISTORY)
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NO_HISTORY)
}
try {
activity.startActivity(intent)
- } catch (e: android.content.ActivityNotFoundException) {
+ } catch (e: ActivityNotFoundException) {
val noViewer = LanguageManager.getText(languageIDProvider(), "no_pdf_viewer")
Toast.makeText(activity, noViewer, Toast.LENGTH_SHORT).show()
}
diff --git a/app/src/main/java/com/dano/test1/AES256Helper.kt b/app/src/main/java/com/dano/test1/utils/AES256Helper.kt
similarity index 100%
rename from app/src/main/java/com/dano/test1/AES256Helper.kt
rename to app/src/main/java/com/dano/test1/utils/AES256Helper.kt
diff --git a/app/src/main/java/com/dano/test1/LanguageManager.kt b/app/src/main/java/com/dano/test1/utils/LanguageManager.kt
similarity index 99%
rename from app/src/main/java/com/dano/test1/LanguageManager.kt
rename to app/src/main/java/com/dano/test1/utils/LanguageManager.kt
index f8e2415..619040e 100644
--- a/app/src/main/java/com/dano/test1/LanguageManager.kt
+++ b/app/src/main/java/com/dano/test1/utils/LanguageManager.kt
@@ -1,6 +1,8 @@
package com.dano.test1
-import java.util.Calendar
+import com.dano.test1.questionnaire.MAX_VALUE_AGE
+import com.dano.test1.questionnaire.MAX_VALUE_YEAR
+import com.dano.test1.ui.RHS_POINTS
object LanguageManager {
fun getTextFormatted(languageId: String, key: String, vararg args: Any): String {
@@ -61,14 +63,14 @@ object LanguageManager {
"once" to "einmal",
"year_after_2000" to "Das Jahr muss nach 2000 liegen!",
"year_after_departure" to "Das Jahr muss nach dem Verlassen des Herkunftslandes liegen!",
- "year_max" to "Das Jahr muss kleiner oder gleich $MAX_VALUE_YEAR sein!",
+ "year_max" to "Das Jahr muss kleiner oder gleich ${MAX_VALUE_YEAR} sein!",
"data_final_warning" to "Wichtig: Die Daten können nach dem Abschluss nicht mehr verändert oder bearbeitet werden!",
"multiple_times" to "mehrmals",
"more_than_15_years" to "mehr als 15 Jahre",
"no" to "Nein",
"no_answer" to "keine Angabe",
"other_country" to "anderes Land",
- "value_must_be_less_equal_max" to "Der Wert muss kleiner oder gleich $MAX_VALUE_AGE sein!",
+ "value_must_be_less_equal_max" to "Der Wert muss kleiner oder gleich ${MAX_VALUE_AGE} sein!",
"value_between_1_and_15" to "Der Wert muss zwischen 1 und 15 liegen!",
"invalid_month" to "Ungültige Monatsangabe!",
"invalid_year" to "Ungültige Jahresangabe!",
@@ -438,14 +440,14 @@ object LanguageManager {
"once" to "once",
"year_after_2000" to "The year must be after 2000!",
"year_after_departure" to "The year must be after leaving the country of origin!",
- "year_max" to "The year must be less than or equal to $MAX_VALUE_YEAR!",
+ "year_max" to "The year must be less than or equal to ${MAX_VALUE_YEAR}!",
"data_final_warning" to "Important: The data cannot be changed or edited after completion!",
"multiple_times" to "multiple times",
"more_than_15_years" to "more than 15 years",
"no" to "No",
"no_answer" to "No answer",
"other_country" to "Other country",
- "value_must_be_less_equal_max" to "The value must be less than or equal to $MAX_VALUE_AGE!",
+ "value_must_be_less_equal_max" to "The value must be less than or equal to ${MAX_VALUE_AGE}!",
"value_between_1_and_15" to "The value must be between 1 and 15!",
"invalid_month" to "Invalid month!",
"invalid_year" to "Invalid year!",
@@ -814,14 +816,14 @@ object LanguageManager {
"once" to "une fois",
"year_after_2000" to "L’année doit être après 2000 !",
"year_after_departure" to "L’année doit être après le départ du pays d’origine !",
- "year_max" to "L’année doit être inférieure ou égale à $MAX_VALUE_YEAR !",
+ "year_max" to "L’année doit être inférieure ou égale à ${MAX_VALUE_YEAR} !",
"data_final_warning" to "Important : Les données ne peuvent plus être modifiées ou éditées après la validation !",
"multiple_times" to "plusieurs fois",
"more_than_15_years" to "plus de 15 ans",
"no" to "Non",
"no_answer" to "pas de réponse",
"other_country" to "autre pays",
- "value_must_be_less_equal_max" to "La valeur doit être inférieure ou égale à $MAX_VALUE_AGE !",
+ "value_must_be_less_equal_max" to "La valeur doit être inférieure ou égale à ${MAX_VALUE_AGE} !",
"value_between_1_and_15" to "La valeur doit être comprise entre 1 et 15 !",
"invalid_month" to "Mois invalide !",
"invalid_year" to "Année invalide !",
@@ -1194,14 +1196,14 @@ object LanguageManager {
"once" to "один раз",
"year_after_2000" to "Год должен быть после 2000!",
"year_after_departure" to "Год должен быть после даты выезда из страны происхождения!",
- "year_max" to "Год должен быть меньше или равен $MAX_VALUE_YEAR!",
+ "year_max" to "Год должен быть меньше или равен ${MAX_VALUE_YEAR}!",
"data_final_warning" to "Внимание: Данные нельзя изменять после завершения!",
"multiple_times" to "несколько раз",
"more_than_15_years" to "более 15 лет",
"no" to "Нет",
"no_answer" to "без ответа",
"other_country" to "другая страна",
- "value_must_be_less_equal_max" to "Значение должно быть меньше или равно $MAX_VALUE_AGE!",
+ "value_must_be_less_equal_max" to "Значение должно быть меньше или равно ${MAX_VALUE_AGE}!",
"value_between_1_and_15" to "Значение должно быть между 1 и 15!",
"invalid_month" to "Недопустимый месяц!",
"invalid_year" to "Недопустимый год!",
@@ -1570,14 +1572,14 @@ object LanguageManager {
"once" to "один раз",
"year_after_2000" to "Рік має бути після 2000!",
"year_after_departure" to "Рік має бути після виїзду з країни походження!",
- "year_max" to "Рік має бути меншим або рівним $MAX_VALUE_YEAR!",
+ "year_max" to "Рік має бути меншим або рівним ${MAX_VALUE_YEAR}!",
"data_final_warning" to "Важливо: Дані після завершення не можна змінити або редагувати!",
"multiple_times" to "багато разів",
"more_than_15_years" to "більше 15 років",
"no" to "Ні",
"no_answer" to "немає відповіді",
"other_country" to "інша країна",
- "value_must_be_less_equal_max" to "Значення має бути меншим або рівним $MAX_VALUE_AGE!",
+ "value_must_be_less_equal_max" to "Значення має бути меншим або рівним ${MAX_VALUE_AGE}!",
"value_between_1_and_15" to "Значення має бути від 1 до 15!",
"invalid_month" to "Неправильний місяць!",
"invalid_year" to "Неправильний рік!",
@@ -1950,14 +1952,14 @@ object LanguageManager {
"once" to "bir kez",
"year_after_2000" to "Yıl 2000’den sonra olmalıdır!",
"year_after_departure" to "Yıl, menşe ülkeyi terk ettikten sonra olmalıdır!",
- "year_max" to "Yıl $MAX_VALUE_YEAR’den küçük veya ona eşit olmalıdır!",
+ "year_max" to "Yıl ${MAX_VALUE_YEAR}’den küçük veya ona eşit olmalıdır!",
"data_final_warning" to "Önemli: Veriler tamamlandıktan sonra değiştirilemez veya düzenlenemez!",
"multiple_times" to "birden fazla kez",
"more_than_15_years" to "15 yıldan fazla",
"no" to "Hayır",
"no_answer" to "Cevap yok",
"other_country" to "diğer ülke",
- "value_must_be_less_equal_max" to "Değer $MAX_VALUE_AGE’den küçük veya ona eşit olmalıdır!",
+ "value_must_be_less_equal_max" to "Değer ${MAX_VALUE_AGE}’den küçük veya ona eşit olmalıdır!",
"value_between_1_and_15" to "Değer 1 ile 15 arasında olmalıdır!",
"invalid_month" to "Geçersiz ay girişi!",
"invalid_year" to "Geçersiz yıl girişi!",
@@ -2330,14 +2332,14 @@ object LanguageManager {
"once" to "jeden raz",
"year_after_2000" to "Rok musi być po 2000!",
"year_after_departure" to "Rok musi być po opuszczeniu kraju pochodzenia!",
- "year_max" to "Rok musi być mniejszy lub równy $MAX_VALUE_YEAR!",
+ "year_max" to "Rok musi być mniejszy lub równy ${MAX_VALUE_YEAR}!",
"data_final_warning" to "Ważne: Po zakończeniu dane nie mogą być zmienione ani edytowane!",
"multiple_times" to "kilka razy",
"more_than_15_years" to "więcej niż 15 lat",
"no" to "Nie",
"no_answer" to "brak odpowiedzi",
"other_country" to "inny kraj",
- "value_must_be_less_equal_max" to "Wartość musi być mniejsza lub równa $MAX_VALUE_AGE!",
+ "value_must_be_less_equal_max" to "Wartość musi być mniejsza lub równa ${MAX_VALUE_AGE}!",
"value_between_1_and_15" to "Wartość musi być między 1 a 15!",
"invalid_month" to "Nieprawidłowy miesiąc!",
"invalid_year" to "Nieprawidłowy rok!",
@@ -2710,14 +2712,14 @@ object LanguageManager {
"once" to "مرة واحدة",
"year_after_2000" to "يجب أن تكون السنة بعد 2000!",
"year_after_departure" to "يجب أن تكون السنة بعد مغادرة بلد المنشأ!",
- "year_max" to "يجب أن تكون السنة أقل من أو تساوي $MAX_VALUE_YEAR!",
+ "year_max" to "يجب أن تكون السنة أقل من أو تساوي ${MAX_VALUE_YEAR}!",
"data_final_warning" to "هام: لا يمكن تعديل البيانات بعد الانتهاء!",
"multiple_times" to "عدة مرات",
"more_than_15_years" to "أكثر من 15 سنة",
"no" to "لا",
"no_answer" to "لا يوجد إجابة",
"other_country" to "بلد آخر",
- "value_must_be_less_equal_max" to "يجب أن تكون القيمة أقل من أو تساوي $MAX_VALUE_AGE!",
+ "value_must_be_less_equal_max" to "يجب أن تكون القيمة أقل من أو تساوي ${MAX_VALUE_AGE}!",
"value_between_1_and_15" to "يجب أن تكون القيمة بين 1 و15!",
"invalid_month" to "شهر غير صالح!",
"invalid_year" to "سنة غير صالحة!",
@@ -3090,14 +3092,14 @@ object LanguageManager {
"once" to "o dată",
"year_after_2000" to "Anul trebuie să fie după 2000!",
"year_after_departure" to "Anul trebuie să fie după plecarea din țara de origine!",
- "year_max" to "Anul trebuie să fie mai mic sau egal cu $MAX_VALUE_YEAR!",
+ "year_max" to "Anul trebuie să fie mai mic sau egal cu ${MAX_VALUE_YEAR}!",
"data_final_warning" to "Important: Datele nu mai pot fi modificate după finalizare!",
"multiple_times" to "de mai multe ori",
"more_than_15_years" to "mai mult de 15 ani",
"no" to "Nu",
"no_answer" to "fără răspuns",
"other_country" to "altă țară",
- "value_must_be_less_equal_max" to "Valoarea trebuie să fie mai mică sau egală cu $MAX_VALUE_AGE!",
+ "value_must_be_less_equal_max" to "Valoarea trebuie să fie mai mică sau egală cu ${MAX_VALUE_AGE}!",
"value_between_1_and_15" to "Valoarea trebuie să fie între 1 și 15!",
"invalid_month" to "Lună invalidă!",
"invalid_year" to "An invalid!",
@@ -3470,14 +3472,14 @@ object LanguageManager {
"once" to "una vez",
"year_after_2000" to "¡El año debe ser posterior al 2000!",
"year_after_departure" to "¡El año debe ser posterior a la salida de su país de origen!",
- "year_max" to "¡El año debe ser menor o igual que $MAX_VALUE_YEAR!",
+ "year_max" to "¡El año debe ser menor o igual que ${MAX_VALUE_YEAR}!",
"data_final_warning" to "Importante: Después de finalizar, los datos no podrán cambiarse o editarse.",
"multiple_times" to "varias veces",
"more_than_15_years" to "más de 15 años",
"no" to "No",
"no_answer" to "sin respuesta",
"other_country" to "otro país",
- "value_must_be_less_equal_max" to "¡El valor debe ser menor o igual que $MAX_VALUE_AGE!",
+ "value_must_be_less_equal_max" to "¡El valor debe ser menor o igual que ${MAX_VALUE_AGE}!",
"value_between_1_and_15" to "¡El valor debe estar entre 1 y 15!",
"invalid_month" to "¡Mes no válido!",
"invalid_year" to "¡Año no válido!",
diff --git a/app/src/main/java/com/dano/test1/LocalizationHelper.kt b/app/src/main/java/com/dano/test1/utils/LocalizationHelper.kt
similarity index 100%
rename from app/src/main/java/com/dano/test1/LocalizationHelper.kt
rename to app/src/main/java/com/dano/test1/utils/LocalizationHelper.kt
diff --git a/app/src/main/java/com/dano/test1/utils/ViewUtils.kt b/app/src/main/java/com/dano/test1/utils/ViewUtils.kt
new file mode 100644
index 0000000..c551921
--- /dev/null
+++ b/app/src/main/java/com/dano/test1/utils/ViewUtils.kt
@@ -0,0 +1,110 @@
+package com.dano.test1.utils
+
+import android.content.Context
+import android.util.TypedValue
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.AbsListView
+import android.widget.ArrayAdapter
+import android.widget.EditText
+import android.widget.Spinner
+import android.widget.TextView
+import androidx.core.widget.TextViewCompat
+import com.dano.test1.R
+import kotlin.math.roundToInt
+
+object ViewUtils {
+
+ /**
+ * Sets the text size of a TextView to a percentage of the screen height (in sp).
+ * Disables auto-sizing to prevent conflicts.
+ */
+ fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
+ val dm = view.context.resources.displayMetrics
+ val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
+ TextViewCompat.setAutoSizeTextTypeWithDefaults(view, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE)
+ view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
+ }
+
+ /**
+ * Sets up a Spinner with a responsive, styled adapter.
+ * Font size and row height are derived from screen height to prevent clipping.
+ */
+ fun setupResponsiveSpinner(context: Context, spinner: Spinner, items: List, selectedItem: T?) {
+ val dm = context.resources.displayMetrics
+
+ fun spFromScreenHeight(percent: Float): Float = (dm.heightPixels * percent) / dm.scaledDensity
+ fun pxFromSp(sp: Float): Int = (sp * dm.scaledDensity).toInt()
+
+ val textSp = spFromScreenHeight(0.0275f)
+ val textPx = pxFromSp(textSp)
+ val vPadPx = (textPx * 0.50f).toInt()
+ val rowHeight = (textPx * 2.20f + 2 * vPadPx).toInt()
+
+ val adapter = object : ArrayAdapter(context, android.R.layout.simple_spinner_item, items) {
+ private fun styleRow(tv: TextView, forceHeight: Boolean) {
+ tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSp)
+ tv.includeFontPadding = true
+ tv.setLineSpacing(0f, 1.2f)
+ tv.gravity = (tv.gravity and Gravity.HORIZONTAL_GRAVITY_MASK) or Gravity.CENTER_VERTICAL
+ tv.setPadding(tv.paddingLeft, vPadPx, tv.paddingRight, vPadPx)
+ tv.minHeight = rowHeight
+ tv.isSingleLine = true
+ if (forceHeight) {
+ val lp = tv.layoutParams
+ if (lp == null || lp.height <= 0) {
+ tv.layoutParams = AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, rowHeight)
+ } else {
+ lp.height = rowHeight
+ }
+ }
+ }
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val v = super.getView(position, convertView, parent) as TextView
+ styleRow(v, forceHeight = false)
+ return v
+ }
+
+ override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val v = super.getDropDownView(position, convertView, parent) as TextView
+ styleRow(v, forceHeight = true)
+ return v
+ }
+ }
+
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ spinner.adapter = adapter
+ spinner.setPadding(spinner.paddingLeft, vPadPx, spinner.paddingRight, vPadPx)
+ spinner.minimumHeight = rowHeight
+ spinner.requestLayout()
+
+ selectedItem?.let {
+ val index = items.indexOf(it)
+ if (index >= 0) spinner.setSelection(index)
+ }
+ }
+
+ /**
+ * Locks an EditText field visually and functionally (e.g. for coach code fields).
+ */
+ fun lockEditField(field: EditText, dpPadding: Int = 8) {
+ field.isFocusable = false
+ field.isFocusableInTouchMode = false
+ field.isCursorVisible = false
+ field.keyListener = null
+ field.isLongClickable = false
+ field.isClickable = false
+ field.setBackgroundResource(R.drawable.bg_field_locked)
+ field.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_lock_24, 0)
+ field.compoundDrawablePadding = dp(field.context, dpPadding)
+ field.alpha = 0.95f
+ }
+
+ /**
+ * Converts dp to pixels using the given context.
+ */
+ fun dp(context: Context, value: Int): Int =
+ (value * context.resources.displayMetrics.density).roundToInt()
+}