Skip to content

Commit

Permalink
Merge pull request #107 from Semper-Viventem/improve-ui
Browse files Browse the repository at this point in the history
Fix some UI problems
  • Loading branch information
Semper-Viventem authored Feb 10, 2024
2 parents 799bdb1 + a2a65b9 commit ac5f7d9
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 76 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ android {

// This version code will be applied only for F-Droid builds, for other builds version code will be generated by gradle dynamically
// For some reason F-Droid requires version code to be hardcoded in the build.gradle file
versionCode = 1705859021
versionName = "0.22.6-beta"
versionCode = 1705859023
versionName = "0.22.7-beta"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object BleScanErrorMapper {
fun map(errorCode: Int): String {
return when (errorCode) {
ScanCallback.SCAN_FAILED_ALREADY_STARTED -> "Scan already started"
ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> "Application registration failed"
ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> "Application registration failed. Possible solution is to restart the device."
ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED -> "Feature unsupported"
ScanCallback.SCAN_FAILED_INTERNAL_ERROR -> "Internal error"
ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES -> "Out of hardware resources"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ abstract class FilterChecker<T : RadarProfile.Filter>(
if (useCache() && cacheValue != null
&& System.currentTimeMillis() - cacheValue.time < powerModeHelper.powerMode(useCached = true).filterCacheExpirationTime
) {
// Timber.d("Cache hit for $key")
return cacheValue.value
}
val result = checkInternal(deviceData, filter)
Expand All @@ -39,6 +38,6 @@ abstract class FilterChecker<T : RadarProfile.Filter>(
)

companion object {
private const val MAX_CACHE_SIZE = 5000
private const val MAX_CACHE_SIZE = 5_000
}
}
95 changes: 48 additions & 47 deletions app/src/main/java/f/cking/software/service/BgScanService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
import timber.log.Timber
import java.util.concurrent.atomic.AtomicInteger


class BgScanService : Service() {
Expand All @@ -43,7 +44,7 @@ class BgScanService : Service() {
private val saveReportInteractor: SaveReportInteractor by inject()

private val handler = Handler(Looper.getMainLooper())
private var failureScanCounter: Int = 0
private var failureScanCounter: AtomicInteger = AtomicInteger(0)
private var locationDisabledWasReported: Boolean = false
private var bluetoothDisabledWasReported: Boolean = false
private val nextScanRunnable = Runnable {
Expand All @@ -68,12 +69,10 @@ class BgScanService : Service() {
}

private fun handleError(exception: Throwable) {
failureScanCounter++

reportError(exception)

if (failureScanCounter >= MAX_FAILURE_SCANS_TO_CLOSE) {
reportError(RuntimeException("Ble Scan service was stopped after $MAX_FAILURE_SCANS_TO_CLOSE errors"))
if (failureScanCounter.incrementAndGet() >= MAX_FAILURE_SCANS_TO_CLOSE) {
reportError(RuntimeException("Ble Scan service has been stopped after $MAX_FAILURE_SCANS_TO_CLOSE errors"))
stopSelf()
} else {
scheduleNextScan()
Expand Down Expand Up @@ -105,7 +104,7 @@ class BgScanService : Service() {
reportError(IllegalStateException("BLE Service is started but permissins are not granted"))
stopSelf()
},
onPermissionGranted = {
onPermissionGranted = {
locationProvider.startLocationFetching()
scan()
}
Expand Down Expand Up @@ -133,7 +132,7 @@ class BgScanService : Service() {
private fun scan() {
scope.launch {
try {
bleScannerHelper.scan(scanListener = bleListener,)
bleScannerHelper.scan(scanListener = bleListener)
} catch (e: BleScannerHelper.BluetoothIsNotInitialized) {
handleBleIsTurnedOffError()
notificationsHelper.updateNotification(
Expand All @@ -150,58 +149,60 @@ class BgScanService : Service() {

private fun handleScanResult(batch: List<BleScanDevice>) {
scope.launch {

val notificationContent: NotificationsHelper.ServiceNotificationContent =
if (batch.isEmpty() && !locationProvider.isLocationAvailable() && !locationDisabledWasReported) {
notificationsHelper.notifyLocationIsTurnedOff()
reportError(IllegalStateException("The BLE scanner did not return anything. This may happen if geolocation is turned off at the system level. Location access is required to work with BLE on Android."))
locationDisabledWasReported = true
NotificationsHelper.ServiceNotificationContent.LocationIsTurnedOff
} else if (batch.isEmpty() && !bleScannerHelper.isBluetoothEnabled()) {
handleBleIsTurnedOffError()
NotificationsHelper.ServiceNotificationContent.BluetoothIsTurnedOff
} else if (batch.isNotEmpty()) {
locationDisabledWasReported = false
bluetoothDisabledWasReported = false


try {
val analyseResult = analyseScanBatchInteractor.execute(batch)
withContext(Dispatchers.Default) {
saveScanBatchInteractor.execute(batch)
}

withContext(Dispatchers.Main) {
handleAnalysResult(analyseResult)
}

failureScanCounter = 0

if (analyseResult.knownDevicesCount > 0) {
NotificationsHelper.ServiceNotificationContent.KnownDevicesAround(analyseResult.knownDevicesCount)
} else {
NotificationsHelper.ServiceNotificationContent.TotalDevicesAround(batch.size)
}
} catch (exception: Throwable) {
handleError(exception)
NotificationsHelper.ServiceNotificationContent.NoDataYet
}
} else {
NotificationsHelper.ServiceNotificationContent.NoDataYet
}
val notificationContent: NotificationsHelper.ServiceNotificationContent = when {
batch.isEmpty() && !locationProvider.isLocationAvailable() && !locationDisabledWasReported -> handleLocationDisabled()
batch.isEmpty() && !bleScannerHelper.isBluetoothEnabled() -> handleBleIsTurnedOffError()
batch.isNotEmpty() -> handleNonEmptyBatch(batch)
else -> NotificationsHelper.ServiceNotificationContent.NoDataYet
}

notificationsHelper.updateNotification(notificationContent, createCloseServiceIntent(this@BgScanService))

scheduleNextScan()
}
}

private fun handleBleIsTurnedOffError() {
private fun handleLocationDisabled(): NotificationsHelper.ServiceNotificationContent {
notificationsHelper.notifyLocationIsTurnedOff()
reportError(IllegalStateException("The BLE scanner did not return anything. This may happen if geolocation is turned off at the system level. Location access is required to work with BLE on Android."))
locationDisabledWasReported = true
return NotificationsHelper.ServiceNotificationContent.LocationIsTurnedOff
}

private fun handleBleIsTurnedOffError(): NotificationsHelper.ServiceNotificationContent {
if (!bluetoothDisabledWasReported) {
notificationsHelper.notifyBluetoothIsTurnedOff()
reportError(BleScannerHelper.BluetoothIsNotInitialized())
bluetoothDisabledWasReported = true
}
return NotificationsHelper.ServiceNotificationContent.BluetoothIsTurnedOff
}

private suspend fun handleNonEmptyBatch(batch: List<BleScanDevice>): NotificationsHelper.ServiceNotificationContent {
locationDisabledWasReported = false
bluetoothDisabledWasReported = false

return try {
val analyseResult = analyseScanBatchInteractor.execute(batch)
withContext(Dispatchers.Default) {
saveScanBatchInteractor.execute(batch)
}

withContext(Dispatchers.Main) {
handleAnalysResult(analyseResult)
}

failureScanCounter.set(0)

if (analyseResult.knownDevicesCount > 0) {
NotificationsHelper.ServiceNotificationContent.KnownDevicesAround(analyseResult.knownDevicesCount)
} else {
NotificationsHelper.ServiceNotificationContent.TotalDevicesAround(batch.size)
}
} catch (exception: Throwable) {
handleError(exception)
NotificationsHelper.ServiceNotificationContent.NoDataYet
}
}

private fun handleProfileCheckingResult(profiles: List<CheckProfileDetectionInteractor.ProfileResult>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ object FilterScreen {
Spacer(modifier = Modifier.width(2.dp))
ClearIcon {
filter.toDate = null
filter.toDate = null
filter.toTime = null
}
}
}
Expand Down
32 changes: 16 additions & 16 deletions app/src/main/java/f/cking/software/ui/filter/FilterType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ package f.cking.software.ui.filter
import androidx.annotation.StringRes
import f.cking.software.R

enum class FilterType(@StringRes val displayNameRes: Int) {
NAME(R.string.filter_by_name),
ADDRESS(R.string.filter_by_address),
BY_FIRST_DETECTION(R.string.filter_by_first_detection_period),
BY_LAST_DETECTION(R.string.filter_by_last_detection_period),
BY_IS_FAVORITE(R.string.filter_by_is_favorite),
BY_MANUFACTURER(R.string.filter_by_manufacturer),
BY_MIN_DETECTION_TIME(R.string.filter_by_min_lost_period),
AIRDROP_CONTACT(R.string.filter_apple_airdrop_contact),
IS_FOLLOWING(R.string.filter_device_is_following_me),
BY_DEVICE_LOCATION(R.string.filter_device_location),
BY_USER_LOCATION(R.string.filter_user_location),
BY_TAG(R.string.filter_by_tag),
BY_LOGIC_ANY(R.string.filter_any_of),
BY_LOGIC_ALL(R.string.filter_all_of),
BY_LOGIC_NOT(R.string.filter_not),
enum class FilterType(@StringRes val displayNameRes: Int, @StringRes val displayDescription: Int) {
BY_LOGIC_ANY(R.string.filter_any_of, R.string.filter_any_of_description),
BY_LOGIC_ALL(R.string.filter_all_of, R.string.filter_all_of_description),
BY_LOGIC_NOT(R.string.filter_not, R.string.filter_not_description),
NAME(R.string.filter_by_name, R.string.filter_by_name_description),
ADDRESS(R.string.filter_by_address, R.string.filter_by_address_description),
BY_TAG(R.string.filter_by_tag, R.string.filter_by_tag_description),
BY_MIN_DETECTION_TIME(R.string.filter_by_min_lost_period, R.string.filter_by_min_lost_period_description),
BY_FIRST_DETECTION(R.string.filter_by_first_detection_period, R.string.filter_by_first_detection_period_description),
BY_LAST_DETECTION(R.string.filter_by_last_detection_period, R.string.filter_by_last_detection_period_description),
BY_IS_FAVORITE(R.string.filter_by_is_favorite, R.string.filter_by_is_favorite_description),
BY_MANUFACTURER(R.string.filter_by_manufacturer, R.string.filter_by_manufacturer_description),
IS_FOLLOWING(R.string.filter_device_is_following_me, R.string.filter_device_is_following_me_description),
BY_DEVICE_LOCATION(R.string.filter_device_location, R.string.filter_device_location_description),
BY_USER_LOCATION(R.string.filter_user_location, R.string.filter_user_location_description),
AIRDROP_CONTACT(R.string.filter_apple_airdrop_contact, R.string.filter_apple_airdrop_contact_description),
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package f.cking.software.ui.filter

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.MaterialTheme
Expand All @@ -11,6 +14,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.vanpra.composematerialdialogs.MaterialDialogState
Expand All @@ -27,7 +31,10 @@ object SelectFilterTypeScreen {
ThemedDialog(
dialogState = dialogState,
buttons = {
negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { dialogState.hide() }
negativeButton(
stringResource(R.string.cancel),
textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)
) { dialogState.hide() }
}
) {
LazyColumn {
Expand All @@ -50,11 +57,22 @@ object SelectFilterTypeScreen {
.fillMaxWidth()
.clickable { onClickListener.invoke() }
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
text = stringResource(item.displayNameRes),
fontSize = 18.sp
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
Text(
text = stringResource(item.displayNameRes),
fontSize = 18.sp
)
Spacer(modifier = Modifier.height(2.dp))
Text(
text = stringResource(item.displayDescription),
fontSize = 14.sp,
fontWeight = FontWeight.Light,
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import org.osmdroid.views.MapView
import java.time.LocalDate
import java.time.LocalTime
import kotlin.math.abs
import kotlin.random.Random

@Composable
fun rememberDateDialog(
Expand Down Expand Up @@ -507,7 +508,7 @@ private val colorsDark = listOf(
@Composable
fun colorByHash(hash: Int): Color {
val colors = if (isSystemInDarkTheme()) colorsDark else colorsLight
return colors[abs(hash % colors.size)]
return colors[abs(Random(hash).nextInt() % colors.size)]
}

@Composable
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,35 @@
<!-- Select filter -->
<string name="select_filter">Select filter</string>
<string name="filter_by_name">By name</string>
<string name="filter_by_name_description">Triggers when the device name matches</string>
<string name="filter_by_address">By address</string>
<string name="filter_by_address_description">Triggers when the device address matches</string>
<string name="filter_by_first_detection_period">By first detection period</string>
<string name="filter_by_first_detection_period_description">Triggers if the found device was first time detected in the selected period</string>
<string name="filter_by_last_detection_period">By last detection period</string>
<string name="filter_by_last_detection_period_description">Triggers if the found device was last time detected in the selected period</string>
<string name="filter_by_is_favorite">By is favorite</string>
<string name="filter_by_is_favorite_description">Triggers if the device is marked as a favorite</string>
<string name="filter_by_manufacturer">By manufacturer</string>
<string name="filter_by_manufacturer_description">Triggers when the device manufacturer matches</string>
<string name="filter_by_min_lost_period">By min lost period</string>
<string name="filter_by_min_lost_period_description">Triggers if the device was lost for the selected period. Might be helpful to avoid constant profile detection if the matched device is online for a long time</string>
<string name="filter_apple_airdrop_contact">Apple airdrop contact</string>
<string name="filter_apple_airdrop_contact_description">[DEPRECATED] Triggers when the device is an Apple device and the airdrop contact matches</string>
<string name="filter_device_is_following_me">Device is following me</string>
<string name="filter_device_is_following_me_description">Triggers if the device is following you during your move for a selected period of time.</string>
<string name="filter_any_of">Any of</string>
<string name="filter_any_of_description">Logical operator OR with group of filters inside</string>
<string name="filter_all_of">All of</string>
<string name="filter_all_of_description">Logical operator AND with group of filters inside</string>
<string name="filter_not">Not</string>
<string name="filter_not_description">Logical operator NOT</string>
<string name="filter_device_location">By device location</string>
<string name="filter_device_location_description">Triggers when the device has been previously seen in the particular location in the selected time period</string>
<string name="filter_user_location">By your location</string>
<string name="filter_user_location_description">Triggers if you are currently in a particular location. It might be helpful to avoid some filters triggering if you are at home or at the office</string>
<string name="filter_by_tag">By tag</string>
<string name="filter_by_tag_description">Triggers if the device has a selected tag</string>

<!-- Profiles list -->
<string name="create_new">Create new</string>
Expand Down

0 comments on commit ac5f7d9

Please sign in to comment.