filter saving
This commit is contained in:
parent
5293604ee4
commit
666757922d
|
|
@ -1,9 +1,11 @@
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'org.jetbrains.kotlin.android'
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
id("org.jetbrains.kotlin.plugin.serialization")
|
||||||
id 'kotlin-kapt'
|
id 'kotlin-kapt'
|
||||||
id 'dagger.hilt.android.plugin'
|
id 'dagger.hilt.android.plugin'
|
||||||
id("kotlin-parcelize")
|
id("kotlin-parcelize")
|
||||||
|
|
||||||
id("androidx.room")
|
id("androidx.room")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,8 +19,8 @@ android {
|
||||||
applicationId "llc.arma.ble"
|
applicationId "llc.arma.ble"
|
||||||
minSdk 26
|
minSdk 26
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 39
|
versionCode 41
|
||||||
versionName "1.4.9"
|
versionName "1.4.12"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
|
|
@ -28,11 +30,11 @@ android {
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
minifyEnabled false
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -107,6 +109,9 @@ dependencies {
|
||||||
kapt("androidx.room:room-compiler:2.6.1")
|
kapt("androidx.room:room-compiler:2.6.1")
|
||||||
implementation("androidx.room:room-ktx:2.6.1")
|
implementation("androidx.room:room-ktx:2.6.1")
|
||||||
|
|
||||||
|
implementation("androidx.datastore:datastore-preferences:1.1.1")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3")
|
||||||
|
|
||||||
implementation files('libs/poishadow-all.jar')
|
implementation files('libs/poishadow-all.jar')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -19,3 +19,188 @@
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
-dontwarn org.apache.**
|
||||||
|
-dontwarn org.openxmlformats.schemas.**
|
||||||
|
-dontwarn org.etsi.**
|
||||||
|
-dontwarn org.w3.**
|
||||||
|
-dontwarn com.microsoft.schemas.**
|
||||||
|
-dontwarn com.graphbuilder.**
|
||||||
|
-dontnote org.apache.**
|
||||||
|
-dontnote org.openxmlformats.schemas.**
|
||||||
|
-dontnote org.etsi.**
|
||||||
|
-dontnote org.w3.**
|
||||||
|
-dontnote com.microsoft.schemas.**
|
||||||
|
-dontnote com.graphbuilder.**
|
||||||
|
|
||||||
|
-keeppackagenames org.apache.poi.ss.formula.function
|
||||||
|
|
||||||
|
-keep class com.fasterxml.aalto.stax.InputFactoryImpl
|
||||||
|
-keep class com.fasterxml.aalto.stax.OutputFactoryImpl
|
||||||
|
-keep class com.fasterxml.aalto.stax.EventFactoryImpl
|
||||||
|
|
||||||
|
-keep class schemaorg_apache_xmlbeans.system.sF1327CCA741569E70F9CA8C9AF9B44B2.TypeSystemHolder { public final static *** typeSystem; }
|
||||||
|
|
||||||
|
-keep class org.apache.xmlbeans.impl.schema.BuiltinSchemaTypeSystem { public static *** get(...); public static *** getNoType(...); }
|
||||||
|
-keep class org.apache.xmlbeans.impl.schema.PathResourceLoader { public <init>(...); }
|
||||||
|
-keep class org.apache.xmlbeans.impl.schema.SchemaTypeSystemCompiler { public static *** compile(...); }
|
||||||
|
-keep class org.apache.xmlbeans.impl.schema.SchemaTypeSystemImpl { public <init>(...); public static *** get(...); public static *** getNoType(...); }
|
||||||
|
-keep class org.apache.xmlbeans.impl.schema.SchemaTypeLoaderImpl { public static *** getContextTypeLoader(...); public static *** build(...); }
|
||||||
|
-keep class org.apache.xmlbeans.impl.store.Locale { public static *** streamToNode(...); public static *** nodeTo*(...); }
|
||||||
|
-keep class org.apache.xmlbeans.impl.store.Path { public static *** compilePath(...); }
|
||||||
|
-keep class org.apache.xmlbeans.impl.store.Query { public static *** compileQuery(...); }
|
||||||
|
|
||||||
|
-keep class com.google.errorprone.annotations.MustBeClosed { *; }
|
||||||
|
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CommentsDocument { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBooleanProperty { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookView { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookViews { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorders { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorderPr { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellAlignment { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellStyleXfs { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellXfs { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFill { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFills { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFont { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFonts { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFontName { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFontScheme { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFontSize { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTIntProperty { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTLegacyDrawing { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTNumFmts { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPatternFill { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetDimension { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheets { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSst { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTStylesheet { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType$Enum { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType$Enum { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.STXstring { *; }
|
||||||
|
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CommentsDocumentImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTAuthorsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTBooleanPropertyImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTBookViewImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTBookViewsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTBorderImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTBordersImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTBorderPrImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellAlignmentImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellFormulaImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellStyleXfsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellXfsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTColorImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTColImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTColsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCommentImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCommentsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCommentListImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTDrawingImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFillImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFillsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFontImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFontsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFontNameImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFontSchemeImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTFontSizeImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTIntPropertyImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTLegacyDrawingImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTNumFmtsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTPatternFillImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTPageMarginsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTPaneImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSelectionImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSheetImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSheetDataImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSheetDimensionImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSheetFormatPrImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSheetViewImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSheetViewsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSheetsImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTSstImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTStylesheetImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRstImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTWorkbookImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTWorkbookPrImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTWorksheetImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTXfImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.SstDocumentImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.StyleSheetDocumentImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.STXstringImpl { *; }
|
||||||
|
|
||||||
|
-keep class org.openxmlformats.schemas.officeDocument.x2006.customProperties.impl.CTPropertiesImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.officeDocument.x2006.customProperties.impl.PropertiesDocumentImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.impl.CTPropertiesImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.impl.PropertiesDocumentImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.impl.CTDrawingImpl { *; }
|
||||||
|
-keep class org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.impl.CTMarkerImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.office.office.impl.CTIdMapImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.office.office.impl.CTShapeLayoutImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.vml.impl.CTShadowImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.vml.impl.CTFillImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.vml.impl.CTPathImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.vml.impl.CTShapeImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.vml.impl.CTShapetypeImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.vml.impl.CTStrokeImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.vml.impl.CTTextboxImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.office.excel.impl.CTClientDataImpl { *; }
|
||||||
|
-keep class com.microsoft.schemas.office.excel.impl.STTrueFalseBlankImpl { *; }
|
||||||
|
|
||||||
|
# Keep `Companion` object fields of serializable classes.
|
||||||
|
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
|
||||||
|
-if @kotlinx.serialization.Serializable class **
|
||||||
|
-keepclassmembers class <1> {
|
||||||
|
static <1>$Companion Companion;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
|
||||||
|
-if @kotlinx.serialization.Serializable class ** {
|
||||||
|
static **$* *;
|
||||||
|
}
|
||||||
|
-keepclassmembers class <2>$<3> {
|
||||||
|
kotlinx.serialization.KSerializer serializer(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keep `INSTANCE.serializer()` of serializable objects.
|
||||||
|
-if @kotlinx.serialization.Serializable class ** {
|
||||||
|
public static ** INSTANCE;
|
||||||
|
}
|
||||||
|
-keepclassmembers class <1> {
|
||||||
|
public static <1> INSTANCE;
|
||||||
|
kotlinx.serialization.KSerializer serializer(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
|
||||||
|
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||||
|
|
@ -8,11 +8,13 @@ import llc.arma.ble.data.repository.BleNameRepositoryImpl
|
||||||
import llc.arma.ble.data.repository.BleRepositoryImpl
|
import llc.arma.ble.data.repository.BleRepositoryImpl
|
||||||
import llc.arma.ble.data.repository.EmailRepositoryImpl
|
import llc.arma.ble.data.repository.EmailRepositoryImpl
|
||||||
import llc.arma.ble.data.repository.RotationsRepositoryImpl
|
import llc.arma.ble.data.repository.RotationsRepositoryImpl
|
||||||
|
import llc.arma.ble.data.repository.SettingsRepositoryImpl
|
||||||
import llc.arma.ble.data.repository.XlsxRepositoryImpl
|
import llc.arma.ble.data.repository.XlsxRepositoryImpl
|
||||||
import llc.arma.ble.domain.repository.BleNameRepository
|
import llc.arma.ble.domain.repository.BleNameRepository
|
||||||
import llc.arma.ble.domain.repository.BleRepository
|
import llc.arma.ble.domain.repository.BleRepository
|
||||||
import llc.arma.ble.domain.repository.EmailRepository
|
import llc.arma.ble.domain.repository.EmailRepository
|
||||||
import llc.arma.ble.domain.repository.RotationsRepository
|
import llc.arma.ble.domain.repository.RotationsRepository
|
||||||
|
import llc.arma.ble.domain.repository.SettingsRepository
|
||||||
import llc.arma.ble.domain.repository.XlsxRepository
|
import llc.arma.ble.domain.repository.XlsxRepository
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
|
@ -34,4 +36,7 @@ interface RepositoryBinding {
|
||||||
@Binds
|
@Binds
|
||||||
fun bindXlsxRepository(repository: XlsxRepositoryImpl): XlsxRepository
|
fun bindXlsxRepository(repository: XlsxRepositoryImpl): XlsxRepository
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
fun bindSettingsRepository(repository: SettingsRepositoryImpl): SettingsRepository
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import llc.arma.ble.app.ui.common.ViewSideEffect
|
||||||
import llc.arma.ble.app.ui.common.ViewState
|
import llc.arma.ble.app.ui.common.ViewState
|
||||||
import llc.arma.ble.domain.model.BleInfo
|
import llc.arma.ble.domain.model.BleInfo
|
||||||
import llc.arma.ble.domain.model.ConnectedBleInfo
|
import llc.arma.ble.domain.model.ConnectedBleInfo
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
|
|
||||||
class BleListContract {
|
class BleListContract {
|
||||||
|
|
||||||
|
|
@ -41,11 +42,11 @@ class BleListContract {
|
||||||
) : Event()
|
) : Event()
|
||||||
|
|
||||||
data class OnSortFieldChanged(
|
data class OnSortFieldChanged(
|
||||||
val field: State.Filter.Field
|
val field: BleFilter.Field
|
||||||
) : Event()
|
) : Event()
|
||||||
|
|
||||||
data class OnSortOrderChanged(
|
data class OnSortOrderChanged(
|
||||||
val order: State.Filter.Order
|
val order: BleFilter.Order
|
||||||
) : Event()
|
) : Event()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -53,10 +54,10 @@ class BleListContract {
|
||||||
data class State(
|
data class State(
|
||||||
val connectedBleList: List<ConnectedBleInfo>,
|
val connectedBleList: List<ConnectedBleInfo>,
|
||||||
val bleList: List<BleInfo>,
|
val bleList: List<BleInfo>,
|
||||||
val filter: Filter
|
val bleFilter: BleFilter
|
||||||
) : ViewState {
|
) : ViewState {
|
||||||
|
|
||||||
data class Filter(
|
/*data class Filter(
|
||||||
val sortField: Field = Field.Name,
|
val sortField: Field = Field.Name,
|
||||||
val sortOrder: Order = Order.Asc,
|
val sortOrder: Order = Order.Asc,
|
||||||
val name: String = "",
|
val name: String = "",
|
||||||
|
|
@ -74,7 +75,7 @@ class BleListContract {
|
||||||
Asc, Desc
|
Asc, Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
|
@ -56,6 +57,7 @@ import llc.arma.ble.app.ui.common.SignalLevel
|
||||||
import llc.arma.ble.app.ui.common.rememberBottomDialogState
|
import llc.arma.ble.app.ui.common.rememberBottomDialogState
|
||||||
import llc.arma.ble.domain.model.BleInfo
|
import llc.arma.ble.domain.model.BleInfo
|
||||||
import llc.arma.ble.domain.model.ConnectedBleInfo
|
import llc.arma.ble.domain.model.ConnectedBleInfo
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
@ -79,7 +81,7 @@ fun BleListScreen(
|
||||||
is BleListContract.Effect.ShowFilter -> launch {
|
is BleListContract.Effect.ShowFilter -> launch {
|
||||||
bottomDialog.show {
|
bottomDialog.show {
|
||||||
Filter(
|
Filter(
|
||||||
filter = viewModel.viewState.value.filter,
|
filter = viewModel.viewState.value.bleFilter,
|
||||||
onEvent = {
|
onEvent = {
|
||||||
viewModel.setEvent(it)
|
viewModel.setEvent(it)
|
||||||
}
|
}
|
||||||
|
|
@ -144,32 +146,32 @@ fun BleListScreen(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val filteredData = remember(state.bleList, state.filter) {
|
val filteredData = remember(state.bleList, state.bleFilter) {
|
||||||
|
|
||||||
state.bleList.filter {
|
state.bleList.filter {
|
||||||
(it.type == state.filter.bleType || state.filter.bleType == null) &&
|
(it.type == state.bleFilter.bleType || state.bleFilter.bleType == null) &&
|
||||||
it.name.contains(state.filter.name) &&
|
it.name.contains(state.bleFilter.name) &&
|
||||||
it.serial.contains(state.filter.mac) &&
|
it.serial.contains(state.bleFilter.mac) &&
|
||||||
state.filter.rssi.contains(it.rssi?.toFloat() ?: Float.MIN_VALUE) &&
|
state.bleFilter.rssi.contains(it.rssi?.toFloat() ?: Float.MIN_VALUE) &&
|
||||||
state.filter.battery.contains(it.batteryLevel.toFloat())
|
state.bleFilter.battery.contains(it.batteryLevel.toFloat())
|
||||||
}.let {
|
}.let {
|
||||||
when (state.filter.sortField) {
|
when (state.bleFilter.sortField) {
|
||||||
BleListContract.State.Filter.Field.Name -> it.sortedBy { it.name }
|
BleFilter.Field.Name -> it.sortedBy { it.name }
|
||||||
BleListContract.State.Filter.Field.Mac -> it.sortedBy { it.serial }
|
BleFilter.Field.Mac -> it.sortedBy { it.serial }
|
||||||
BleListContract.State.Filter.Field.Distance -> it.sortedBy {
|
BleFilter.Field.Distance -> it.sortedBy {
|
||||||
10.0.pow(
|
10.0.pow(
|
||||||
(it.tx.toDouble() - (it.rssi?.toDouble() ?: 0.0) - 74) / 20
|
(it.tx.toDouble() - (it.rssi?.toDouble() ?: 0.0) - 74) / 20
|
||||||
).toFloat()
|
).toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
BleListContract.State.Filter.Field.Dbm -> it.sortedBy { it.rssi ?: 0 }
|
BleFilter.Field.Dbm -> it.sortedBy { it.rssi ?: 0 }
|
||||||
BleListContract.State.Filter.Field.Battery -> it.sortedBy { it.batteryLevel }
|
BleFilter.Field.Battery -> it.sortedBy { it.batteryLevel }
|
||||||
}
|
}
|
||||||
}.let {
|
}.let {
|
||||||
|
|
||||||
when (state.filter.sortOrder) {
|
when (state.bleFilter.sortOrder) {
|
||||||
BleListContract.State.Filter.Order.Asc -> it
|
BleFilter.Order.Asc -> it
|
||||||
BleListContract.State.Filter.Order.Desc -> it.reversed()
|
BleFilter.Order.Desc -> it.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -317,7 +319,7 @@ fun BleItem(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ble.recordEnabled){
|
if(ble.tableStatus !== BleInfo.HistoryTableStatus.DISABLED){
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
|
|
@ -327,7 +329,11 @@ fun BleItem(
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
color = MaterialTheme.colorScheme.error,
|
color = when(ble.tableStatus){
|
||||||
|
BleInfo.HistoryTableStatus.EMPTY -> Color(0xff009116)
|
||||||
|
BleInfo.HistoryTableStatus.NOT_EMPTY -> MaterialTheme.colorScheme.error
|
||||||
|
else -> Color.Transparent
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(12.dp)
|
.size(12.dp)
|
||||||
.padding(2.dp)
|
.padding(2.dp)
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,16 @@ import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import llc.arma.ble.app.ui.common.BaseViewModel
|
import llc.arma.ble.app.ui.common.BaseViewModel
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
import llc.arma.ble.domain.usecase.GetBleAroundFlow
|
import llc.arma.ble.domain.usecase.GetBleAroundFlow
|
||||||
|
import llc.arma.ble.domain.usecase.filter.GetFilterFlow
|
||||||
|
import llc.arma.ble.domain.usecase.filter.SaveFilter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class BleListViewModel @Inject constructor(
|
class BleListViewModel @Inject constructor(
|
||||||
|
private val getFilterFlow: GetFilterFlow,
|
||||||
|
private val saveFilter: SaveFilter,
|
||||||
getBleAroundFlow: GetBleAroundFlow
|
getBleAroundFlow: GetBleAroundFlow
|
||||||
) : BaseViewModel<BleListContract.State, BleListContract.Event, BleListContract.Effect>() {
|
) : BaseViewModel<BleListContract.State, BleListContract.Event, BleListContract.Effect>() {
|
||||||
|
|
||||||
|
|
@ -37,6 +42,14 @@ class BleListViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
getFilterFlow.invoke().onEach {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
bleFilter = it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.launchIn(this)
|
||||||
|
|
||||||
/*while (true) {
|
/*while (true) {
|
||||||
|
|
||||||
job?.cancel()
|
job?.cancel()
|
||||||
|
|
@ -66,7 +79,7 @@ class BleListViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setInitialState(): BleListContract.State =
|
override fun setInitialState(): BleListContract.State =
|
||||||
BleListContract.State(emptyList(), emptyList(), BleListContract.State.Filter())
|
BleListContract.State(emptyList(), emptyList(), BleFilter())
|
||||||
|
|
||||||
override fun handleEvents(event: BleListContract.Event) {
|
override fun handleEvents(event: BleListContract.Event) {
|
||||||
when(event){
|
when(event){
|
||||||
|
|
@ -106,9 +119,9 @@ class BleListViewModel @Inject constructor(
|
||||||
state: BleListContract.State,
|
state: BleListContract.State,
|
||||||
event: BleListContract.Event.OnMacFilterChanged
|
event: BleListContract.Event.OnMacFilterChanged
|
||||||
) {
|
) {
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
saveFilter(
|
||||||
filter = this.filter.copy(mac = event.mac)
|
bleFilter = state.bleFilter.copy(mac = event.mac)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,9 +130,9 @@ class BleListViewModel @Inject constructor(
|
||||||
state: BleListContract.State,
|
state: BleListContract.State,
|
||||||
event: BleListContract.Event.OnSortOrderChanged
|
event: BleListContract.Event.OnSortOrderChanged
|
||||||
) {
|
) {
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
saveFilter(
|
||||||
filter = this.filter.copy(sortOrder = event.order)
|
bleFilter = state.bleFilter.copy(sortOrder = event.order)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -128,9 +141,9 @@ class BleListViewModel @Inject constructor(
|
||||||
state: BleListContract.State,
|
state: BleListContract.State,
|
||||||
event: BleListContract.Event.OnSortFieldChanged
|
event: BleListContract.Event.OnSortFieldChanged
|
||||||
) {
|
) {
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
saveFilter(
|
||||||
filter = this.filter.copy(sortField = event.field)
|
bleFilter = state.bleFilter.copy(sortField = event.field)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -139,9 +152,9 @@ class BleListViewModel @Inject constructor(
|
||||||
state: BleListContract.State,
|
state: BleListContract.State,
|
||||||
event: BleListContract.Event.OnNameFilterChanged
|
event: BleListContract.Event.OnNameFilterChanged
|
||||||
) {
|
) {
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
saveFilter(
|
||||||
filter = this.filter.copy(name = event.name)
|
bleFilter = state.bleFilter.copy(name = event.name)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -151,14 +164,14 @@ class BleListViewModel @Inject constructor(
|
||||||
event: BleListContract.Event.OnResetFilter
|
event: BleListContract.Event.OnResetFilter
|
||||||
) {
|
) {
|
||||||
|
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
|
||||||
filter = BleListContract.State.Filter()
|
saveFilter(BleFilter())
|
||||||
)
|
|
||||||
}
|
setEffect {
|
||||||
|
BleListContract.Effect.HideFilter
|
||||||
|
}
|
||||||
|
|
||||||
setEffect {
|
|
||||||
BleListContract.Effect.HideFilter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -167,9 +180,9 @@ class BleListViewModel @Inject constructor(
|
||||||
state: BleListContract.State,
|
state: BleListContract.State,
|
||||||
event: BleListContract.Event.OnRssiRangeChanged
|
event: BleListContract.Event.OnRssiRangeChanged
|
||||||
) {
|
) {
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
saveFilter(
|
||||||
filter = this.filter.copy(rssi = event.rssi)
|
bleFilter = state.bleFilter.copy(rssi = event.rssi)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,9 +191,9 @@ class BleListViewModel @Inject constructor(
|
||||||
state: BleListContract.State,
|
state: BleListContract.State,
|
||||||
event: BleListContract.Event.OnBatteryRangeChanged
|
event: BleListContract.Event.OnBatteryRangeChanged
|
||||||
) {
|
) {
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
saveFilter(
|
||||||
filter = this.filter.copy(battery = event.battery)
|
bleFilter = state.bleFilter.copy(battery = event.battery)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -189,9 +202,9 @@ class BleListViewModel @Inject constructor(
|
||||||
state: BleListContract.State,
|
state: BleListContract.State,
|
||||||
event: BleListContract.Event.OnTypeChanged
|
event: BleListContract.Event.OnTypeChanged
|
||||||
) {
|
) {
|
||||||
setState {
|
viewModelScope.launch {
|
||||||
copy(
|
saveFilter(
|
||||||
filter = this.filter.copy(bleType = event.type)
|
bleFilter = state.bleFilter.copy(bleType = event.type)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,24 +47,25 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
import llc.arma.ble.domain.model.BleInfo
|
import llc.arma.ble.domain.model.BleInfo
|
||||||
|
|
||||||
val BleListContract.State.Filter.Order.localized: String
|
val BleFilter.Order.localized: String
|
||||||
get() {
|
get() {
|
||||||
return when(this){
|
return when(this){
|
||||||
BleListContract.State.Filter.Order.Asc -> "Прямой ↓"
|
BleFilter.Order.Asc -> "Прямой ↓"
|
||||||
BleListContract.State.Filter.Order.Desc -> "Обратный ↑"
|
BleFilter.Order.Desc -> "Обратный ↑"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val BleListContract.State.Filter.Field.localized: String
|
val BleFilter.Field.localized: String
|
||||||
get() {
|
get() {
|
||||||
return when(this){
|
return when(this){
|
||||||
BleListContract.State.Filter.Field.Name -> "Имя"
|
BleFilter.Field.Name -> "Имя"
|
||||||
BleListContract.State.Filter.Field.Mac -> "MAC"
|
BleFilter.Field.Mac -> "MAC"
|
||||||
BleListContract.State.Filter.Field.Distance -> "Расстояние"
|
BleFilter.Field.Distance -> "Расстояние"
|
||||||
BleListContract.State.Filter.Field.Dbm -> "dBm"
|
BleFilter.Field.Dbm -> "dBm"
|
||||||
BleListContract.State.Filter.Field.Battery -> "Заряд"
|
BleFilter.Field.Battery -> "Заряд"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +94,7 @@ val BleInfo.Type?.icon: ImageVector
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Filter(
|
fun Filter(
|
||||||
filter: BleListContract.State.Filter,
|
filter: BleFilter,
|
||||||
onEvent: (BleListContract.Event) -> Unit
|
onEvent: (BleListContract.Event) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
@ -164,7 +165,7 @@ fun Filter(
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
BleListContract.State.Filter.Field.values().forEach { selectionOption ->
|
BleFilter.Field.entries.forEach { selectionOption ->
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
onClick = {
|
onClick = {
|
||||||
onEvent(
|
onEvent(
|
||||||
|
|
@ -233,7 +234,7 @@ fun Filter(
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
BleListContract.State.Filter.Order.values().forEach { selectionOption ->
|
BleFilter.Order.entries.forEach { selectionOption ->
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
onClick = {
|
onClick = {
|
||||||
onEvent(
|
onEvent(
|
||||||
|
|
@ -303,7 +304,7 @@ fun Filter(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
mutableListOf<BleInfo.Type?>(null).apply {
|
mutableListOf<BleInfo.Type?>(null).apply {
|
||||||
addAll(BleInfo.Type.values())
|
addAll(BleInfo.Type.entries.toTypedArray())
|
||||||
}.forEach { selectionOption ->
|
}.forEach { selectionOption ->
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.ContentAlpha
|
import androidx.compose.material.ContentAlpha
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
|
@ -48,17 +49,27 @@ import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.patrykandpatrick.vico.compose.axis.ChartShape
|
||||||
|
import com.patrykandpatrick.vico.compose.axis.axisGuidelineComponent
|
||||||
|
import com.patrykandpatrick.vico.compose.axis.axisLineComponent
|
||||||
import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis
|
import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis
|
||||||
|
import com.patrykandpatrick.vico.compose.axis.vertical.startAxis
|
||||||
import com.patrykandpatrick.vico.compose.chart.Chart
|
import com.patrykandpatrick.vico.compose.chart.Chart
|
||||||
import com.patrykandpatrick.vico.compose.chart.column.columnChart
|
import com.patrykandpatrick.vico.compose.chart.column.columnChart
|
||||||
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollSpec
|
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollSpec
|
||||||
|
import com.patrykandpatrick.vico.compose.component.lineComponent
|
||||||
|
import com.patrykandpatrick.vico.compose.component.shapeComponent
|
||||||
|
import com.patrykandpatrick.vico.compose.component.textComponent
|
||||||
import com.patrykandpatrick.vico.core.axis.AxisPosition
|
import com.patrykandpatrick.vico.core.axis.AxisPosition
|
||||||
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
|
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
|
||||||
import com.patrykandpatrick.vico.core.chart.scale.AutoScaleUp
|
import com.patrykandpatrick.vico.core.chart.scale.AutoScaleUp
|
||||||
|
import com.patrykandpatrick.vico.core.component.marker.MarkerComponent
|
||||||
import com.patrykandpatrick.vico.core.component.shape.LineComponent
|
import com.patrykandpatrick.vico.core.component.shape.LineComponent
|
||||||
import com.patrykandpatrick.vico.core.component.shape.Shapes.pillShape
|
import com.patrykandpatrick.vico.core.component.shape.Shapes.pillShape
|
||||||
|
import com.patrykandpatrick.vico.core.dimensions.MutableDimensions
|
||||||
import com.patrykandpatrick.vico.core.entry.ChartEntry
|
import com.patrykandpatrick.vico.core.entry.ChartEntry
|
||||||
import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer
|
import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer
|
||||||
import com.patrykandpatrick.vico.core.entry.composed.ComposedChartEntryModelProducer
|
import com.patrykandpatrick.vico.core.entry.composed.ComposedChartEntryModelProducer
|
||||||
|
|
@ -202,12 +213,17 @@ val dateFormatter = SimpleDateFormat("dd.MM", Locale.getDefault())
|
||||||
val timeFormatter = SimpleDateFormat("HH:mm", Locale.getDefault())
|
val timeFormatter = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||||
|
|
||||||
val colorsStack = listOf(
|
val colorsStack = listOf(
|
||||||
Color(0xffffd700), Color(0xff2f4f4f), Color(0xff7f0000), Color(0xFFFF0000),
|
Color(0xff2f4f4f), Color(0xff7f0000), Color(0xFFFF0000), Color(0xffffd700),
|
||||||
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
|
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
|
||||||
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
|
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
|
||||||
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee),
|
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val startAxisValueFormatter =
|
||||||
|
AxisValueFormatter<AxisPosition.Vertical.Start> { value, chartValues ->
|
||||||
|
" "
|
||||||
|
}
|
||||||
|
|
||||||
val axisValueFormatter =
|
val axisValueFormatter =
|
||||||
AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues ->
|
AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues ->
|
||||||
val first = (chartValues.chartEntryModel.entries.firstOrNull()?.firstOrNull() as? HostEntry)
|
val first = (chartValues.chartEntryModel.entries.firstOrNull()?.firstOrNull() as? HostEntry)
|
||||||
|
|
@ -279,7 +295,7 @@ fun Display(
|
||||||
if(historyPoint.value.contains(serial)) {
|
if(historyPoint.value.contains(serial)) {
|
||||||
HostEntry(historyPoint.date, index.toFloat(), 1f)
|
HostEntry(historyPoint.date, index.toFloat(), 1f)
|
||||||
} else {
|
} else {
|
||||||
HostEntry(historyPoint.date, index.toFloat(), 0f)
|
HostEntry(historyPoint.date, index.toFloat(), 0.0001f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -291,6 +307,31 @@ fun Display(
|
||||||
val producer = remember(entries) { ComposedChartEntryModelProducer(entries) }
|
val producer = remember(entries) { ComposedChartEntryModelProducer(entries) }
|
||||||
|
|
||||||
val chart = columnChart(
|
val chart = columnChart(
|
||||||
|
persistentMarkers = state.loadingHistoryState.data.mapIndexedNotNull { index, historyPoint ->
|
||||||
|
if(historyPoint.hit) {
|
||||||
|
Pair(
|
||||||
|
index.toFloat(),
|
||||||
|
MarkerComponent(
|
||||||
|
label = textComponent(
|
||||||
|
textSize = 0.sp,
|
||||||
|
padding = MutableDimensions(10f, 10f, 10f, 10f),
|
||||||
|
margins = MutableDimensions(10f, 10f, 10f, 10f),
|
||||||
|
color = Color.Red,
|
||||||
|
background = shapeComponent(
|
||||||
|
color = Color.Red,
|
||||||
|
shape = pillShape
|
||||||
|
)
|
||||||
|
),
|
||||||
|
indicator = null,
|
||||||
|
guideline = axisLineComponent(
|
||||||
|
thickness = 0.dp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}.toMap(),
|
||||||
innerSpacing = 2.dp,
|
innerSpacing = 2.dp,
|
||||||
columns = serials.map { LineComponent(color = colors[it]!!.toArgb(), thicknessDp = 7f, shape= pillShape) },
|
columns = serials.map { LineComponent(color = colors[it]!!.toArgb(), thicknessDp = 7f, shape= pillShape) },
|
||||||
spacing = 8.dp,
|
spacing = 8.dp,
|
||||||
|
|
@ -340,8 +381,6 @@ fun Display(
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Chart(
|
Chart(
|
||||||
chart = chart,
|
chart = chart,
|
||||||
chartModelProducer = producer,
|
chartModelProducer = producer,
|
||||||
|
|
@ -350,6 +389,9 @@ fun Display(
|
||||||
valueFormatter = axisValueFormatter,
|
valueFormatter = axisValueFormatter,
|
||||||
tickLength = 0.dp,
|
tickLength = 0.dp,
|
||||||
),
|
),
|
||||||
|
startAxis = startAxis(
|
||||||
|
valueFormatter = startAxisValueFormatter
|
||||||
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.weight(1f),
|
.weight(1f),
|
||||||
|
|
@ -400,6 +442,7 @@ fun Display(
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
|
|
||||||
Chart(
|
Chart(
|
||||||
|
|
||||||
chart = chart,
|
chart = chart,
|
||||||
chartModelProducer = producer,
|
chartModelProducer = producer,
|
||||||
bottomAxis = bottomAxis(
|
bottomAxis = bottomAxis(
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
|
|
||||||
val tState = readAccelState(
|
val tState = readAccelState(
|
||||||
result.serial,
|
result.serial,
|
||||||
result.recordEnabled
|
result.tableStatus
|
||||||
).fold(
|
).fold(
|
||||||
onFailure = {
|
onFailure = {
|
||||||
return Result.failure(it)
|
return Result.failure(it)
|
||||||
|
|
@ -227,7 +227,7 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
BleInfo.Type.THERMOMETER -> {
|
BleInfo.Type.THERMOMETER -> {
|
||||||
|
|
||||||
val tState = readThermometerState(result.serial, result.recordEnabled).fold(
|
val tState = readThermometerState(result.serial, result.tableStatus).fold(
|
||||||
onFailure = {
|
onFailure = {
|
||||||
return Result.failure(it)
|
return Result.failure(it)
|
||||||
},
|
},
|
||||||
|
|
@ -335,7 +335,7 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
private suspend fun readThermometerState(
|
private suspend fun readThermometerState(
|
||||||
address: String,
|
address: String,
|
||||||
timer: Boolean
|
timer: BleInfo.HistoryTableStatus
|
||||||
): Result<Ble.Thermometer.ThermometerState, BleException> {
|
): Result<Ble.Thermometer.ThermometerState, BleException> {
|
||||||
|
|
||||||
return if(app.checkPermission()) {
|
return if(app.checkPermission()) {
|
||||||
|
|
@ -373,7 +373,7 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
return Result.success(
|
return Result.success(
|
||||||
Ble.Thermometer.ThermometerState(
|
Ble.Thermometer.ThermometerState(
|
||||||
temperature = temperature,
|
temperature = temperature,
|
||||||
saveHistory = timer,
|
saveHistory = timer !== BleInfo.HistoryTableStatus.DISABLED,
|
||||||
historyInterval = interval
|
historyInterval = interval
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -410,9 +410,17 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
.findService(serviceUUID) ?: return Result.failure(BleException.UnexpectedResponse)
|
.findService(serviceUUID) ?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
val characteristic = service.findCharacteristic(intervalReadUUID)
|
val characteristic = service.findCharacteristic(intervalReadUUID)
|
||||||
?: return Result.failure(BleException.UnexpectedResponse)
|
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(3, 0, 0, 0, ))
|
if(characteristic == null){
|
||||||
|
service.characteristics.forEach {
|
||||||
|
Log.d("ble", "characteristic ${it.uuid} ")
|
||||||
|
}
|
||||||
|
Log.d("ble", "${intervalReadUUID} not found")
|
||||||
|
return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
characteristic.write(DataByteArray.from(3, 0, 0, 0))
|
||||||
|
|
||||||
val interval = characteristic.read().value.let {
|
val interval = characteristic.read().value.let {
|
||||||
if(it.size == 4){
|
if(it.size == 4){
|
||||||
|
|
@ -447,7 +455,7 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
|
|
||||||
private suspend fun readAccelState(
|
private suspend fun readAccelState(
|
||||||
address: String,
|
address: String,
|
||||||
timer: Boolean
|
timer: BleInfo.HistoryTableStatus
|
||||||
): Result<Ble.Accelerometer.AccelerometerState, BleException> {
|
): Result<Ble.Accelerometer.AccelerometerState, BleException> {
|
||||||
|
|
||||||
return if(app.checkPermission()) {
|
return if(app.checkPermission()) {
|
||||||
|
|
@ -474,7 +482,8 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
val historySettingsParams = when(timer){
|
val historySettingsParams = when(timer){
|
||||||
true -> {
|
BleInfo.HistoryTableStatus.EMPTY,
|
||||||
|
BleInfo.HistoryTableStatus.NOT_EMPTY -> {
|
||||||
|
|
||||||
characteristic = service.findCharacteristic(accelerometerReadUUID)
|
characteristic = service.findCharacteristic(accelerometerReadUUID)
|
||||||
?: return Result.failure(BleException.UnexpectedResponse)
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
@ -494,7 +503,7 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false -> Ble.Accelerometer.HistorySettings.Disabled
|
BleInfo.HistoryTableStatus.DISABLED -> Ble.Accelerometer.HistorySettings.Disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package llc.arma.ble.data.repository
|
package llc.arma.ble.data.repository
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.util.Log
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
@ -16,10 +18,12 @@ import llc.arma.ble.domain.model.Ble
|
||||||
import no.nordicsemi.android.common.core.DataByteArray
|
import no.nordicsemi.android.common.core.DataByteArray
|
||||||
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
||||||
import no.nordicsemi.android.kotlin.ble.client.main.service.ClientBleGattCharacteristic
|
import no.nordicsemi.android.kotlin.ble.client.main.service.ClientBleGattCharacteristic
|
||||||
|
import okio.ByteString.Companion.decodeHex
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.BitSet
|
import java.util.BitSet
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
suspend fun readTable(
|
suspend fun readTable(
|
||||||
characteristic: ClientBleGattCharacteristic,
|
characteristic: ClientBleGattCharacteristic,
|
||||||
startRequest: ByteArray,
|
startRequest: ByteArray,
|
||||||
|
|
@ -28,13 +32,11 @@ suspend fun readTable(
|
||||||
|
|
||||||
characteristic.write(DataByteArray(startRequest))
|
characteristic.write(DataByteArray(startRequest))
|
||||||
var value = characteristic.read().value
|
var value = characteristic.read().value
|
||||||
var nextPackageDataCount = value.get2byteUIntAt(2)
|
|
||||||
|
|
||||||
val tableResult = mutableListOf<Byte>()
|
val tableResult = mutableListOf<Byte>()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
nextPackageDataCount = value.get2byteUIntAt(2)
|
val nextPackageDataCount = value.get2byteUIntAt(2)
|
||||||
|
|
||||||
tableResult.addAll(value.asList().subList(4, value.size))
|
tableResult.addAll(value.asList().subList(4, value.size))
|
||||||
|
|
||||||
|
|
@ -85,17 +87,14 @@ fun readHostHistory(
|
||||||
firstTablePackage.addAll(
|
firstTablePackage.addAll(
|
||||||
readTable(
|
readTable(
|
||||||
characteristic,
|
characteristic,
|
||||||
mutableListOf(
|
//Чтение без удаления
|
||||||
1.toByte(),
|
byteArrayOf(1, 0, 0, -2, -1),
|
||||||
0.toByte(),
|
|
||||||
0.toByte()
|
|
||||||
).apply {
|
|
||||||
addAll(value.toList())
|
|
||||||
}.toByteArray(),
|
|
||||||
byteArrayOf(5)
|
byteArrayOf(5)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Log.d("table", firstTablePackage.joinToString { it.toString() })
|
||||||
|
|
||||||
val bleMeasureInterval = firstTablePackage.toByteArray().get4byteUIntAt(0).toLong()
|
val bleMeasureInterval = firstTablePackage.toByteArray().get4byteUIntAt(0).toLong()
|
||||||
val bleLastMeasureTime = firstTablePackage.toByteArray().get4byteUIntAt(4).toLong()
|
val bleLastMeasureTime = firstTablePackage.toByteArray().get4byteUIntAt(4).toLong()
|
||||||
val bleRealTime = firstTablePackage.toByteArray().get4byteUIntAt(8).toLong()
|
val bleRealTime = firstTablePackage.toByteArray().get4byteUIntAt(8).toLong()
|
||||||
|
|
@ -108,6 +107,7 @@ fun readHostHistory(
|
||||||
fun getBleIdIndex(bytes: ByteArray): UInt{
|
fun getBleIdIndex(bytes: ByteArray): UInt{
|
||||||
|
|
||||||
val bits = BitSet.valueOf(bytes)
|
val bits = BitSet.valueOf(bytes)
|
||||||
|
Log.d("bits", bits.toByteArray().joinToString())
|
||||||
bits.clear(12, 16)
|
bits.clear(12, 16)
|
||||||
|
|
||||||
val arr = bits.toByteArray()
|
val arr = bits.toByteArray()
|
||||||
|
|
@ -141,7 +141,7 @@ fun readHostHistory(
|
||||||
|
|
||||||
fun getDevType(byte: Byte): Int{
|
fun getDevType(byte: Byte): Int{
|
||||||
|
|
||||||
var bits = BitSet.valueOf(byteArrayOf(byte))
|
val bits = BitSet.valueOf(byteArrayOf(byte))
|
||||||
bits.clear(5, 9)
|
bits.clear(5, 9)
|
||||||
val arr = bits.toByteArray()
|
val arr = bits.toByteArray()
|
||||||
|
|
||||||
|
|
@ -169,26 +169,29 @@ fun readHostHistory(
|
||||||
}
|
}
|
||||||
|
|
||||||
var bleTableOffset = 12
|
var bleTableOffset = 12
|
||||||
var periods = mutableListOf<List<String>>()
|
var periods = mutableListOf<Pair<Boolean, List<String>>>()
|
||||||
var periodBle = mutableListOf<String>()
|
|
||||||
|
|
||||||
|
var periodBle = mutableListOf<String>()
|
||||||
|
var hasHit = false
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
val bleIdTableCell = firstTablePackage.drop(bleTableOffset).take(2).toByteArray()
|
val bleIdTableCell = firstTablePackage.drop(bleTableOffset).take(2).toByteArray()
|
||||||
|
|
||||||
|
println("cell ${bleIdTableCell.toHexString()} ${bleIdTableCell.joinToString()}")
|
||||||
|
|
||||||
if(bleIdTableCell.contentEquals(byteArrayOf(-1, 15)).not()) {
|
if(bleIdTableCell.contentEquals(byteArrayOf(-1, 15)).not()) {
|
||||||
|
|
||||||
println("offset $bleTableOffset/${firstTablePackage.size}")
|
if(bleIdTableCell.contentEquals(byteArrayOf(-2, 15))){
|
||||||
|
bleTableOffset += 2
|
||||||
|
hasHit = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
val innerIndex = getInnerIndex(bleIdTableCell[1])
|
val innerIndex = getInnerIndex(bleIdTableCell[1])
|
||||||
|
|
||||||
println("inner index $innerIndex")
|
|
||||||
|
|
||||||
val bleTableIndex = getBleIdIndex(bleIdTableCell) * 8u
|
val bleTableIndex = getBleIdIndex(bleIdTableCell) * 8u
|
||||||
|
|
||||||
println("table index $bleTableIndex")
|
|
||||||
|
|
||||||
val serial =
|
val serial =
|
||||||
secondTablePackage.drop(bleTableIndex.toInt()).take(6).reversed()
|
secondTablePackage.drop(bleTableIndex.toInt()).take(6).reversed()
|
||||||
.joinToString(
|
.joinToString(
|
||||||
|
|
@ -197,13 +200,8 @@ fun readHostHistory(
|
||||||
.uppercase(Locale.getDefault())
|
.uppercase(Locale.getDefault())
|
||||||
val devTypeByte = secondTablePackage.drop(bleTableIndex.toInt() + 6)[0]
|
val devTypeByte = secondTablePackage.drop(bleTableIndex.toInt() + 6)[0]
|
||||||
|
|
||||||
println("table serial $serial")
|
|
||||||
|
|
||||||
val devType = getDevType(devTypeByte)
|
val devType = getDevType(devTypeByte)
|
||||||
println("devType $devType")
|
|
||||||
val devDataSize = getDevDataSize(devTypeByte)
|
val devDataSize = getDevDataSize(devTypeByte)
|
||||||
|
|
||||||
println("payload $devDataSize")
|
|
||||||
bleTableOffset += 2
|
bleTableOffset += 2
|
||||||
|
|
||||||
if (devDataSize != 0) {
|
if (devDataSize != 0) {
|
||||||
|
|
@ -222,8 +220,6 @@ fun readHostHistory(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var nextIndex = 0
|
var nextIndex = 0
|
||||||
|
|
||||||
if(bleTableOffset <= firstTablePackage.size - 2){
|
if(bleTableOffset <= firstTablePackage.size - 2){
|
||||||
|
|
@ -231,22 +227,21 @@ fun readHostHistory(
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nextIndex == 0){
|
if(nextIndex == 0){
|
||||||
println("________________")
|
periods.add(Pair(hasHit, periodBle))
|
||||||
periods.add(periodBle)
|
|
||||||
periodBle = mutableListOf()
|
periodBle = mutableListOf()
|
||||||
|
hasHit = false
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (bleTableOffset < firstTablePackage.size)
|
} while (bleTableOffset < firstTablePackage.size)
|
||||||
|
|
||||||
//periods.add(periodBle)
|
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
Result.success(
|
Result.success(
|
||||||
ProgressState.Finished(
|
ProgressState.Finished(
|
||||||
periods.withIndex().map {
|
periods.withIndex().map {
|
||||||
Ble.Host.HistoryPoint(
|
Ble.Host.HistoryPoint(
|
||||||
date = lastMeasureSystemTime - (((periods.size - 1) - it.index) * bleMeasureInterval),
|
date = lastMeasureSystemTime - (((periods.size - 1) - it.index) * bleMeasureInterval),
|
||||||
value = it.value
|
hit = it.value.first,
|
||||||
|
value = it.value.second
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package llc.arma.ble.data.repository
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
|
import llc.arma.ble.domain.repository.SettingsRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class SettingsRepositoryImpl @Inject constructor(
|
||||||
|
private val app: Application
|
||||||
|
) : SettingsRepository {
|
||||||
|
|
||||||
|
val FILTER = stringPreferencesKey("ble_filter")
|
||||||
|
|
||||||
|
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||||
|
|
||||||
|
override suspend fun saveFilter(
|
||||||
|
bleFilter: BleFilter
|
||||||
|
) {
|
||||||
|
app.dataStore.edit { settings ->
|
||||||
|
|
||||||
|
settings[FILTER] = Json.encodeToString(bleFilter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFilterFlow(): Flow<BleFilter?> {
|
||||||
|
return app.dataStore.data.map { settings ->
|
||||||
|
try {
|
||||||
|
|
||||||
|
Json.decodeFromString<BleFilter>(settings[FILTER] ?: "")
|
||||||
|
} catch (e: Throwable){
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,9 +3,13 @@ package llc.arma.ble.data.repository.extensions
|
||||||
import llc.arma.ble.domain.model.BleInfo
|
import llc.arma.ble.domain.model.BleInfo
|
||||||
import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanResult
|
import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanResult
|
||||||
|
|
||||||
val BleScanResult.timerEnabled: Boolean
|
val BleScanResult.timerEnabled: BleInfo.HistoryTableStatus
|
||||||
get() {
|
get() {
|
||||||
return data?.scanRecord?.manufacturerSpecificData?.get(89)?.getByte(2) == 1.toByte()
|
return when(data?.scanRecord?.manufacturerSpecificData?.get(89)?.getByte(2)){
|
||||||
|
1.toByte() -> BleInfo.HistoryTableStatus.NOT_EMPTY
|
||||||
|
2.toByte() -> BleInfo.HistoryTableStatus.EMPTY
|
||||||
|
else -> BleInfo.HistoryTableStatus.DISABLED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val BleScanResult.info: BleInfo
|
val BleScanResult.info: BleInfo
|
||||||
|
|
@ -19,7 +23,7 @@ val BleScanResult.info: BleInfo
|
||||||
type = type,
|
type = type,
|
||||||
scanTime = (data?.timestampNanos ?: 0) / 1_000_000,
|
scanTime = (data?.timestampNanos ?: 0) / 1_000_000,
|
||||||
tx = data?.scanRecord?.txPowerLevel ?: 0,
|
tx = data?.scanRecord?.txPowerLevel ?: 0,
|
||||||
recordEnabled = timerEnabled
|
tableStatus = timerEnabled
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ sealed class Ble(
|
||||||
|
|
||||||
class HistoryPoint(
|
class HistoryPoint(
|
||||||
val date: Long,
|
val date: Long,
|
||||||
|
val hit: Boolean,
|
||||||
val value: List<String>
|
val value: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package llc.arma.ble.domain.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.SerializationException
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.element
|
||||||
|
import kotlinx.serialization.encoding.CompositeDecoder
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.encoding.decodeStructure
|
||||||
|
import kotlinx.serialization.encoding.encodeStructure
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BleFilter(
|
||||||
|
val sortField: Field = Field.Name,
|
||||||
|
val sortOrder: Order = Order.Asc,
|
||||||
|
val name: String = "",
|
||||||
|
val mac: String = "",
|
||||||
|
@Serializable(with = CFPRSerializer::class) val battery: ClosedFloatingPointRange<Float> = (0f)..(100f),
|
||||||
|
@Serializable(with = CFPRSerializer::class) val rssi: ClosedFloatingPointRange<Float> = (-100f)..(-10f),
|
||||||
|
val bleType: BleInfo.Type? = null
|
||||||
|
){
|
||||||
|
|
||||||
|
enum class Field {
|
||||||
|
Name, Mac, Distance, Dbm, Battery
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Order {
|
||||||
|
Asc, Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object CFPRSerializer : KSerializer<ClosedFloatingPointRange<Float>> {
|
||||||
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("kotlin.ranges.DoubleClosedFloatingPointRange") {
|
||||||
|
element<Float>("start")
|
||||||
|
element<Float>("endInclusive")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: ClosedFloatingPointRange<Float>) {
|
||||||
|
encoder.encodeStructure(descriptor) {
|
||||||
|
encodeFloatElement(descriptor, 0, value.start)
|
||||||
|
encodeFloatElement(descriptor, 1, value.endInclusive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): ClosedFloatingPointRange<Float> {
|
||||||
|
return decoder.decodeStructure(descriptor) {
|
||||||
|
var start: Float? = null
|
||||||
|
var end: Float? = null
|
||||||
|
while (true) {
|
||||||
|
val index = decodeElementIndex(descriptor)
|
||||||
|
if (index == CompositeDecoder.DECODE_DONE) break
|
||||||
|
if (index == 0) start = decodeFloatElement(descriptor, index)
|
||||||
|
else end = decodeFloatElement(descriptor, index)
|
||||||
|
}
|
||||||
|
if (start == null || end == null) throw SerializationException("...")
|
||||||
|
start..end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,9 +12,13 @@ data class BleInfo(
|
||||||
val type: Type,
|
val type: Type,
|
||||||
val scanTime: Long,
|
val scanTime: Long,
|
||||||
val tx: Int,
|
val tx: Int,
|
||||||
val recordEnabled: Boolean
|
val tableStatus: HistoryTableStatus
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
|
enum class HistoryTableStatus {
|
||||||
|
DISABLED, EMPTY, NOT_EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
HOST, BEACON, THERMOMETER, ACCELEROMETER
|
HOST, BEACON, THERMOMETER, ACCELEROMETER
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package llc.arma.ble.domain.repository
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
|
|
||||||
|
interface SettingsRepository {
|
||||||
|
|
||||||
|
suspend fun saveFilter(bleFilter: BleFilter)
|
||||||
|
|
||||||
|
fun getFilterFlow(): Flow<BleFilter?>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package llc.arma.ble.domain.usecase.filter
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
|
import llc.arma.ble.domain.repository.SettingsRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GetFilterFlow @Inject constructor(
|
||||||
|
private val settingsRepository: SettingsRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
operator fun invoke(): Flow<BleFilter> {
|
||||||
|
return settingsRepository.getFilterFlow().map {
|
||||||
|
it ?: BleFilter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package llc.arma.ble.domain.usecase.filter
|
||||||
|
|
||||||
|
import llc.arma.ble.domain.model.BleFilter
|
||||||
|
import llc.arma.ble.domain.repository.SettingsRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SaveFilter @Inject constructor(
|
||||||
|
private val settingsRepository: SettingsRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(bleFilter: BleFilter){
|
||||||
|
|
||||||
|
settingsRepository.saveFilter(bleFilter)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -17,5 +17,6 @@ plugins {
|
||||||
id 'com.android.application' version '8.1.1' apply false
|
id 'com.android.application' version '8.1.1' apply false
|
||||||
id 'com.android.library' version '8.1.1' apply false
|
id 'com.android.library' version '8.1.1' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.9.22' apply false
|
id 'org.jetbrains.kotlin.android' version '1.9.22' apply false
|
||||||
|
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.22'
|
||||||
id("androidx.room") version "2.6.1" apply false
|
id("androidx.room") version "2.6.1" apply false
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue