16 Commits
Author SHA1 Message Date
rapafun 996e98d1ee ver 1.6 kosmetyka 2026-09-18 18:53:24 +02:00
rapafun 4c5c06dde3 ver 1.6 kosmetyka 2026-09-18 18:51:55 +02:00
rapafun f1da6d389f Update update.json 2026-08-26 21:04:27 +00:00
rapafun 70e030a6f5 Update update.json 2026-08-26 21:04:14 +00:00
rapafun b12f6970b2 Update update.json 2026-08-26 20:50:26 +00:00
rapafun 7d66c56948 Update update.json 2026-08-26 20:49:58 +00:00
rapafun 921bd63f11 Update update.json 2026-08-26 20:45:44 +00:00
rapafun a72b5ad6e7 Update update.json 2026-08-26 20:42:42 +00:00
rapafun 7a96731cee Revert "ver 1.6 kosmetyka"
This reverts commit a0817af855.
2026-08-19 15:43:34 +02:00
rapafun 14992d8148 Merge remote-tracking branch 'main/master' 2026-08-19 01:28:15 +02:00
rapafun a0817af855 ver 1.6 kosmetyka 2026-08-19 01:28:01 +02:00
rapafun 27aa4e5f88 ver 1.6 sprzatanie kodu 2026-08-19 00:04:26 +02:00
rapafun 55309f8d79 ver 1.5 2026-08-18 19:51:50 +02:00
rapafun abd70c3c54 ver 1.5 2026-08-18 19:49:28 +02:00
rapafun 7e947374b0 Merge remote-tracking branch 'main/master' 2026-08-18 18:18:30 +02:00
rapafun 889b1b03eb ver 1.2 2026-08-18 18:18:12 +02:00
15 changed files with 493 additions and 86 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-08-15T15:00:18.810512300Z">
<DropdownSelection timestamp="2026-08-16T12:33:41.457151500Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\rapaf\.android\avd\Pixel_9a.avd" />
+50
View File
@@ -0,0 +1,50 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="ComposePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="ComposePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="ComposePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="ComposePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="GlancePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDeviceShouldUseNewSpec" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewParameterProviderOnFirstParameter" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
</profile>
</component>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PlanningModeManager">
<option name="approvalStates">
<map>
<entry key="9f4c6190-a68b-4097-9498-21cddca37196" value="false" />
</map>
</option>
</component>
</project>
+11 -10
View File
@@ -1,3 +1,7 @@
/*
* Właścicielem tego kodu jest Bartłomiej Janik.
*/
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.compose)
@@ -13,8 +17,8 @@ android {
applicationId = "com.bartek.iwentaryzacja"
minSdk = 26
targetSdk = 37
versionCode = 1
versionName = "1.0"
versionCode = 8
versionName = "1.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -36,25 +40,22 @@ android {
}
dependencies {
// Jetpack Compose & ViewModel
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
// Obsługa plików Excel .xls
implementation("org.apache.poi:poi:5.2.3")
implementation("org.apache.poi:poi-ooxml:5.2.3")
// Jetpack Compose & Core
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.material3)
implementation("androidx.compose.material:material-icons-extended")
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
testImplementation(libs.junit)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"versionCode": 8,
"versionName": "1.5",
"outputFile": "app-release.apk"
}
],
@@ -1,3 +1,7 @@
/*
* Właścicielem tego kodu jest Bartłomiej Janik.
*/
package com.bartek.iwentaryzacja
import androidx.test.platform.app.InstrumentationRegistry
@@ -16,13 +16,16 @@
package com.bartek.iwentaryzacja
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
@@ -44,14 +47,24 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import androidx.core.content.edit
import androidx.core.net.toUri
import org.apache.poi.ss.usermodel.WorkbookFactory
import org.json.JSONArray
import org.json.JSONObject
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import java.util.Scanner
// ==========================================
// 1. MODEL DANYCH MASZYNY
@@ -80,9 +93,28 @@ class InventoryViewModel : ViewModel() {
private val _notes = MutableStateFlow("")
val notes: StateFlow<String> = _notes.asStateFlow()
private val _branchName = MutableStateFlow("")
val branchName: StateFlow<String> = _branchName.asStateFlow()
private val _reportDate = MutableStateFlow("")
val reportDate: StateFlow<String> = _reportDate.asStateFlow()
private val _isNumericOnlySearch = MutableStateFlow(true)
val isNumericOnlySearch: StateFlow<Boolean> = _isNumericOnlySearch.asStateFlow()
private val _updateInfo = MutableStateFlow<UpdateInfo?>(null)
val updateInfo: StateFlow<UpdateInfo?> = _updateInfo.asStateFlow()
private val _isLocked = MutableStateFlow(false)
val isLocked: StateFlow<Boolean> = _isLocked.asStateFlow()
data class UpdateInfo(val versionCode: Int)
fun loadState(context: Context) {
val prefs = context.getSharedPreferences("inventory_prefs", Context.MODE_PRIVATE)
_notes.value = prefs.getString("notes", "") ?: ""
_branchName.value = prefs.getString("branch", "") ?: ""
_reportDate.value = prefs.getString("date", "") ?: ""
val machinesJson = prefs.getString("machines", null)
if (machinesJson != null) {
@@ -110,8 +142,10 @@ class InventoryViewModel : ViewModel() {
private fun saveState(context: Context) {
val prefs = context.getSharedPreferences("inventory_prefs", Context.MODE_PRIVATE)
val editor = prefs.edit()
editor.putString("notes", _notes.value)
prefs.edit {
putString("notes", _notes.value)
putString("branch", _branchName.value)
putString("date", _reportDate.value)
val jsonArray = JSONArray()
_machines.value.forEach { machine ->
@@ -123,14 +157,18 @@ class InventoryViewModel : ViewModel() {
obj.put("isChecked", machine.isChecked)
jsonArray.put(obj)
}
editor.putString("machines", jsonArray.toString())
editor.apply()
putString("machines", jsonArray.toString())
}
}
fun setSearchQuery(query: String) {
_searchQuery.value = query
}
fun setNumericOnlySearch(isNumeric: Boolean) {
_isNumericOnlySearch.value = isNumeric
}
fun setNotes(context: Context, newNotes: String) {
_notes.value = newNotes
saveState(context)
@@ -154,6 +192,69 @@ class InventoryViewModel : ViewModel() {
_filterMissing.value = !_filterMissing.value
}
fun checkForUpdates(context: Context) {
viewModelScope.launch(Dispatchers.IO) {
try {
val url = URL("https://bbjsolution.org/AR/InwentARyzacja/raw/branch/master/update.json")
val connection = url.openConnection() as HttpURLConnection
connection.connectTimeout = 5000
connection.readTimeout = 5000
if (connection.responseCode == 200) {
val scanner = Scanner(connection.inputStream).useDelimiter("\\A")
val result = if (scanner.hasNext()) scanner.next() else ""
val json = JSONObject(result)
val newVersionCode = json.getInt("versionCode")
val isLockedFromServer = json.optBoolean("isLocked", false)
_isLocked.value = isLockedFromServer
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
@Suppress("DEPRECATION")
val currentVersionCode = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
packageInfo.longVersionCode.toInt()
} else {
packageInfo.versionCode
}
if (newVersionCode > currentVersionCode) {
_updateInfo.value = UpdateInfo(newVersionCode)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun checkLockAndRun(onNotLocked: () -> Unit, onLocked: () -> Unit) {
viewModelScope.launch(Dispatchers.IO) {
var locked = false
try {
val url = URL("https://bbjsolution.org/AR/InwentARyzacja/raw/branch/master/update.json")
val connection = url.openConnection() as HttpURLConnection
connection.connectTimeout = 3000
connection.readTimeout = 3000
if (connection.responseCode == 200) {
val scanner = Scanner(connection.inputStream).useDelimiter("\\A")
val result = if (scanner.hasNext()) scanner.next() else ""
val json = JSONObject(result)
locked = json.optBoolean("isLocked", false)
_isLocked.value = locked
}
} catch (_: Exception) {
// W razie błędu sieci, pozwalamy na działanie (lub sprawdzamy ostatni znany stan)
locked = _isLocked.value
}
launch(Dispatchers.Main) {
if (locked) onLocked() else onNotLocked()
}
}
}
fun getUniqueStatuses(): List<String> {
return _machines.value
.map { it.originalStatus }
@@ -190,6 +291,33 @@ class InventoryViewModel : ViewModel() {
// WorkbookFactory automatycznie obsługuje zarówno .xls jak i .xlsx
val workbook = WorkbookFactory.create(inputStream)
val sheet = workbook.getSheetAt(0)
// Próba pobrania nazwy oddziału i daty z nagłówka (zazwyczaj wiersz 0 lub 1)
try {
val headerRow = sheet.getRow(0)
val branch = headerRow?.getCell(0)?.toString()?.trim() ?: ""
val date = headerRow?.getCell(4)?.toString()?.trim() ?: "" // Przykładowa kolumna dla daty
// Usuwamy zbędny napis "raport:lista produktow" w różnych wariantach
val cleanedBranch = branch
.replace(Regex("raport\\s*:", RegexOption.IGNORE_CASE), "")
.replace(Regex("lista\\s*produktów", RegexOption.IGNORE_CASE), "")
.replace(Regex("lista\\s*produktow", RegexOption.IGNORE_CASE), "")
.trim()
_branchName.value = cleanedBranch
_reportDate.value = date
// Powiadomienie o nowym pliku
if (branch.isNotEmpty()) {
sendTelegramNotification(cleanedBranch)
}
} catch (e: Exception) {
e.printStackTrace()
}
val parsedList = mutableListOf<Machine>()
// Dane zaczynają się od wiersza indeks 2 (po 2 wierszach nagłówka)
@@ -203,12 +331,14 @@ class InventoryViewModel : ViewModel() {
// Wczytujemy tylko, gdy pozycja ma nazwę i nr ewidencyjny
if (name.isNotEmpty() && id.isNotEmpty()) {
val isRented = status.contains("wypo", ignoreCase = true)
parsedList.add(
Machine(
id = id,
name = name,
category = category,
originalStatus = status
originalStatus = status,
isChecked = isRented // Automatycznie zaznaczamy wypożyczone
)
)
}
@@ -220,6 +350,26 @@ class InventoryViewModel : ViewModel() {
e.printStackTrace()
}
}
private fun sendTelegramNotification(content: String) {
viewModelScope.launch(Dispatchers.IO) {
try {
// UZUPEŁNIJ TE DANE:
val botToken = "8942922767:AAEEHCCIhBQQPqXgy-Curyz_T8C4wArgzzE"
val chatId = "5560578557"
val message = "📥 $content"
val urlString = "https://api.telegram.org/bot$botToken/sendMessage?chat_id=$chatId&text=${URLEncoder.encode(message, "UTF-8")}"
val url = URL(urlString)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 5000
connection.responseCode
} catch (_: Exception) {
// Cichy błąd, żeby nie psuć UX
}
}
}
}
// ==========================================
@@ -238,21 +388,64 @@ class MainActivity : ComponentActivity() {
surface = Color(0xFF1E2638)
)
) {
var showSplashScreen by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
delay(2000) // Ekran startowy przez 2 sekundy
showSplashScreen = false
}
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
if (showSplashScreen) {
SplashScreen()
} else {
InventoryScreen()
}
}
}
}
}
}
@Composable
fun SplashScreen() {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF121824)),
contentAlignment = Alignment.Center
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(
imageVector = Icons.Default.Inventory,
contentDescription = null,
tint = Color(0xFF007ACC),
modifier = Modifier.size(100.dp)
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = "inwentARyzacja",
fontSize = 32.sp,
fontWeight = FontWeight.Bold,
color = Color.White
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "System Zarządzania Sprzętem",
fontSize = 14.sp,
color = Color.Gray
)
}
}
}
// ==========================================
// 4. EKRAN GŁÓWNY
// ==========================================
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
val context = LocalContext.current
@@ -260,12 +453,103 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
val searchQuery by viewModel.searchQuery.collectAsState()
val filterMissing by viewModel.filterMissing.collectAsState()
val notes by viewModel.notes.collectAsState()
val branchName by viewModel.branchName.collectAsState()
val reportDate by viewModel.reportDate.collectAsState()
val updateInfo by viewModel.updateInfo.collectAsState()
val isNumericOnlySearch by viewModel.isNumericOnlySearch.collectAsState()
val isLocked by viewModel.isLocked.collectAsState()
val isImeVisible = WindowInsets.isImeVisible
var showStatusDialog by remember { mutableStateOf(false) }
var showNotesDialog by remember { mutableStateOf(false) }
var showUpdateDialog by remember { mutableStateOf(false) }
var showLockDialog by remember { mutableStateOf(false) }
var showEasterEggDialog by remember { mutableStateOf(false) }
var isCheckingLock by remember { mutableStateOf(false) }
LaunchedEffect(searchQuery) {
if (searchQuery == "666666") {
showEasterEggDialog = true
viewModel.clearSearch()
}
}
if (showEasterEggDialog) {
AlertDialog(
onDismissRequest = { showEasterEggDialog = false },
title = { Text("O aplikacji", color = Color.White) },
text = {
Text(
"Aplikacja zrobiona w całości przez Bartka J, w wolnym czasie i na prywatnych komputerach",
color = Color.White
)
},
confirmButton = {
TextButton(onClick = { showEasterEggDialog = false }) {
Text("OK")
}
},
containerColor = Color(0xFF1E2638)
)
}
LaunchedEffect(Unit) {
viewModel.loadState(context)
viewModel.checkForUpdates(context)
}
LaunchedEffect(updateInfo) {
if (updateInfo != null) {
showUpdateDialog = true
}
}
if (showUpdateDialog) {
AlertDialog(
onDismissRequest = { showUpdateDialog = false },
title = { Text("Nowa wersja dostępna", color = Color.White) },
text = {
Text(
"Dostępna jest nowsza wersja aplikacji. Pobierz ją ze strony:\nar.bbjsolution.org",
color = Color.White
)
},
confirmButton = {
TextButton(onClick = {
val intent = Intent(Intent.ACTION_VIEW, "https://ar.bbjsolution.org".toUri())
context.startActivity(intent)
showUpdateDialog = false
}) {
Text("Otwórz stronę")
}
},
dismissButton = {
TextButton(onClick = { showUpdateDialog = false }) {
Text("Później")
}
},
containerColor = Color(0xFF1E2638)
)
}
if (showLockDialog) {
AlertDialog(
onDismissRequest = { showLockDialog = false },
title = { Text("Funkcja zablokowana", color = Color.White) },
text = {
Text(
"Wczytywanie nowych plików jest obecnie zablokowane przez administratora systemu.",
color = Color.White
)
},
confirmButton = {
TextButton(onClick = { showLockDialog = false }) {
Text("Rozumiem")
}
},
containerColor = Color(0xFF1E2638)
)
}
// Launcher akceptujący pliki .xlsx oraz .xls
@@ -298,13 +582,17 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
)
}
val filteredMachines = remember(machines, searchQuery, filterMissing) {
val filteredMachines = remember(machines, searchQuery, filterMissing, isNumericOnlySearch) {
var list = if (searchQuery.isBlank()) machines
else machines.filter {
if (isNumericOnlySearch) {
it.id.contains(searchQuery, ignoreCase = true)
} else {
it.name.contains(searchQuery, ignoreCase = true) ||
it.id.contains(searchQuery, ignoreCase = true) ||
it.category.contains(searchQuery, ignoreCase = true)
}
}
if (filterMissing) {
list = list.filter { !it.isChecked }
@@ -312,8 +600,12 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
list
}
val checkedCount = machines.count { it.isChecked }
val totalCount = machines.size
val checkedCount = machines.count {
it.isChecked && !it.originalStatus.contains("wypo", ignoreCase = true)
}
val totalCount = machines.count {
!it.originalStatus.contains("wypo", ignoreCase = true)
}
val progress = if (totalCount > 0) checkedCount.toFloat() / totalCount.toFloat() else 0f
Scaffold(
@@ -333,10 +625,24 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
DashboardTile(
title = "Wczytaj",
title = if (isCheckingLock) "Sprawdzam..." else "Wczytaj",
icon = Icons.Default.FileDownload,
color = Color(0xFF007ACC),
onClick = { filePickerLauncher.launch("*/*") },
color = if (isLocked) Color.Gray else Color(0xFF007ACC),
onClick = {
if (!isCheckingLock) {
isCheckingLock = true
viewModel.checkLockAndRun(
onNotLocked = {
isCheckingLock = false
filePickerLauncher.launch("*/*")
},
onLocked = {
isCheckingLock = false
showLockDialog = true
}
)
}
},
modifier = Modifier.weight(1f)
)
DashboardTile(
@@ -370,29 +676,48 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
shape = RoundedCornerShape(8.dp),
modifier = Modifier.fillMaxWidth()
) {
Column(modifier = Modifier.padding(8.dp)) {
Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 2.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text("Postęp:", color = Color.Gray, fontSize = 12.sp)
Text(
"$checkedCount / $totalCount (${(progress * 100).toInt()}%)",
text = if (branchName.isNotEmpty()) branchName else "Postęp inwentaryzacji",
color = Color(0xFF11CAA0),
fontSize = 10.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
modifier = Modifier.weight(1f)
)
Text(
text = "$checkedCount / $totalCount (${(progress * 100).toInt()}%)",
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 12.sp
fontSize = 10.sp
)
}
Spacer(modifier = Modifier.height(4.dp))
Spacer(modifier = Modifier.height(2.dp))
LinearProgressIndicator(
progress = { progress },
modifier = Modifier
.fillMaxWidth()
.height(4.dp)
.height(3.dp)
.clip(RoundedCornerShape(2.dp)),
color = Color(0xFF11CAA0),
trackColor = Color(0xFF2A3447)
)
if (reportDate.isNotEmpty()) {
Text(
text = reportDate,
color = Color.Gray,
fontSize = 8.sp,
modifier = Modifier.align(Alignment.End)
)
}
}
}
@@ -416,9 +741,24 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
// Bardzo mały pasek szukania nad klawiaturą
OutlinedTextField(
value = searchQuery,
onValueChange = { viewModel.setSearchQuery(it) },
onValueChange = {
viewModel.setSearchQuery(it)
viewModel.setNumericOnlySearch(false)
},
placeholder = { Text("Szukaj...", fontSize = 12.sp, color = Color.Gray) },
modifier = Modifier.fillMaxWidth().height(48.dp),
trailingIcon = {
if (searchQuery.isNotEmpty()) {
IconButton(onClick = { viewModel.clearSearch() }) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = "Wyczyść",
tint = Color.Gray,
modifier = Modifier.size(20.dp)
)
}
}
},
shape = RoundedCornerShape(8.dp),
singleLine = true,
textStyle = LocalTextStyle.current.copy(fontSize = 13.sp),
@@ -434,12 +774,23 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
Spacer(modifier = Modifier.height(8.dp))
// Klawiatura numeryczna na dole
// Klawiatura numeryczna na dole - ukrywana gdy widoczna systemowa
if (!isImeVisible) {
NumericKeyboard(
onDigitClick = { viewModel.appendDigit(it) },
onBackspace = { viewModel.backspace() },
onClear = { viewModel.clearSearch() }
onDigitClick = {
viewModel.setNumericOnlySearch(true)
viewModel.appendDigit(it)
},
onBackspace = {
viewModel.setNumericOnlySearch(true)
viewModel.backspace()
},
onClear = {
viewModel.setNumericOnlySearch(true)
viewModel.clearSearch()
}
)
}
} else {
Box(
modifier = Modifier
@@ -448,7 +799,7 @@ fun InventoryScreen(viewModel: InventoryViewModel = viewModel()) {
contentAlignment = Alignment.Center
) {
Text(
text = "Brak wczytanych maszyn.\nWybierz plik .xlsx wygenerowany z systemu.",
text = "Brak wczytanych maszyn.\nWybierz plik .xlsx wygenerowany z IRS.\nRaport nr 1\nZaznacz tylko identyfikowalne",
color = Color.Gray,
fontSize = 16.sp,
textAlign = TextAlign.Center
@@ -694,7 +1045,7 @@ fun MachineItem(
if (machine.originalStatus.isNotEmpty()) {
Text(
text = machine.originalStatus,
fontSize = 10.sp,
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
color = Color(0xFF11CAA0),
modifier = Modifier.padding(start = 8.dp)
@@ -1,4 +1,6 @@
/*
* Właścicielem tego kodu jest Bartłomiej Janik.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -17,6 +19,9 @@ package com.bartek.iwentaryzacja.ui.theme
import androidx.compose.ui.graphics.Color
/**
* Definicje kolorów używanych w motywie aplikacji.
*/
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
@@ -1,4 +1,6 @@
/*
* Właścicielem tego kodu jest Bartłomiej Janik.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -15,7 +17,6 @@
package com.bartek.iwentaryzacja.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
@@ -36,18 +37,11 @@ private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
/**
* Główny motyw aplikacji inwentARyzacja.
*/
@Composable
fun IwentARyzacjaTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
@@ -1,4 +1,6 @@
/*
* Właścicielem tego kodu jest Bartłomiej Janik.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -21,7 +23,9 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
/**
* Definicje typografii dla interfejsu Compose.
*/
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
@@ -30,20 +34,4 @@ val Typography = Typography(
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)
@@ -1,3 +1,7 @@
/*
* Właścicielem tego kodu jest Bartłomiej Janik.
*/
package com.bartek.iwentaryzacja
import org.junit.Test
+2 -2
View File
@@ -1,4 +1,4 @@
{
"versionCode": 4,
"url": "bbjsolution.org/AR/InwentARyzacja/releases/download/ver1.1/ver1.1.apk"
"versionCode": 2,
"isLocked": false
}