Browse Source

initial commit

Dola TENG 3 years ago
commit
205906c532
100 changed files with 6989 additions and 0 deletions
  1. 14 0
      .gitignore
  2. 3 0
      .idea/.gitignore
  3. 1 0
      .idea/.name
  4. 122 0
      .idea/codeStyles/Project.xml
  5. 5 0
      .idea/codeStyles/codeStyleConfig.xml
  6. 6 0
      .idea/compiler.xml
  7. 21 0
      .idea/gradle.xml
  8. 35 0
      .idea/jarRepositories.xml
  9. 24 0
      .idea/misc.xml
  10. 6 0
      .idea/vcs.xml
  11. 1 0
      app/.gitignore
  12. 167 0
      app/build.gradle
  13. BIN
      app/dev/release/Khmer9_Lotto_devRelease_1.0-newicon-dev.apk
  14. BIN
      app/dev/release/Khmer9_Lotto_devRelease_1.4-dev.apk
  15. 18 0
      app/dev/release/output-metadata.json
  16. 39 0
      app/google-services.json
  17. 18 0
      app/prod/debug/output-metadata.json
  18. BIN
      app/prod/release/Khmer9_Lotto_prodRelease_1.9.apk
  19. 18 0
      app/prod/release/output-metadata.json
  20. 116 0
      app/proguard-rules.pro
  21. 24 0
      app/src/androidTest/java/com/khmer9/lotto/ExampleInstrumentedTest.kt
  22. 8 0
      app/src/dev/java/com/khmer9/lotto/config/Config.kt
  23. 50 0
      app/src/main/AndroidManifest.xml
  24. BIN
      app/src/main/ic_launcher-playstore.png
  25. 47 0
      app/src/main/java/com/khmer9/lotto/adapter/AbstractAdapter.kt
  26. 23 0
      app/src/main/java/com/khmer9/lotto/adapter/AbstractViewHolder.kt
  27. 31 0
      app/src/main/java/com/khmer9/lotto/adapter/BaseListAdapter.kt
  28. 21 0
      app/src/main/java/com/khmer9/lotto/adapter/BaseListItem.kt
  29. 58 0
      app/src/main/java/com/khmer9/lotto/adapter/BaseListViewHolder.kt
  30. 144 0
      app/src/main/java/com/khmer9/lotto/app/App.kt
  31. 41 0
      app/src/main/java/com/khmer9/lotto/app/ErrorInterceptor.kt
  32. 14 0
      app/src/main/java/com/khmer9/lotto/app/ExceptionExtension.kt
  33. 33 0
      app/src/main/java/com/khmer9/lotto/app/ServiceInterceptor.kt
  34. 157 0
      app/src/main/java/com/khmer9/lotto/app/ShareActivity.kt
  35. 380 0
      app/src/main/java/com/khmer9/lotto/app/ShareViewModel.kt
  36. 21 0
      app/src/main/java/com/khmer9/lotto/app/ShareViewState.kt
  37. 41 0
      app/src/main/java/com/khmer9/lotto/base/BaseActivity.kt
  38. 171 0
      app/src/main/java/com/khmer9/lotto/base/BaseFragment.kt
  39. 16 0
      app/src/main/java/com/khmer9/lotto/base/BaseViewModel.kt
  40. 209 0
      app/src/main/java/com/khmer9/lotto/extension/ViewExtensions.kt
  41. 95 0
      app/src/main/java/com/khmer9/lotto/remote/LoginDataModel.kt
  42. 119 0
      app/src/main/java/com/khmer9/lotto/remote/MainDataModel.kt
  43. 93 0
      app/src/main/java/com/khmer9/lotto/remote/PlayDataModel.kt
  44. 153 0
      app/src/main/java/com/khmer9/lotto/remote/ReportDataModel.kt
  45. 57 0
      app/src/main/java/com/khmer9/lotto/remote/ResultDataModel.kt
  46. 18 0
      app/src/main/java/com/khmer9/lotto/remote/SocketMessageDataModel.kt
  47. 30 0
      app/src/main/java/com/khmer9/lotto/remote/UpdatePwdDataModel.kt
  48. 30 0
      app/src/main/java/com/khmer9/lotto/remote/service/ApiService.kt
  49. 19 0
      app/src/main/java/com/khmer9/lotto/remote/service/ConnectivityStates.java
  50. 23 0
      app/src/main/java/com/khmer9/lotto/remote/service/EventListener.java
  51. 155 0
      app/src/main/java/com/khmer9/lotto/remote/service/SocketService.java
  52. 86 0
      app/src/main/java/com/khmer9/lotto/screen/login/LoginActivity.kt
  53. 75 0
      app/src/main/java/com/khmer9/lotto/screen/login/LoginViewModel.kt
  54. 9 0
      app/src/main/java/com/khmer9/lotto/screen/login/LoginViewState.kt
  55. 21 0
      app/src/main/java/com/khmer9/lotto/screen/main/MainAdapter.kt
  56. 936 0
      app/src/main/java/com/khmer9/lotto/screen/main/MainFragment.kt
  57. 10 0
      app/src/main/java/com/khmer9/lotto/screen/main/MainListItem.kt
  58. 75 0
      app/src/main/java/com/khmer9/lotto/screen/main/MainListViewHolder.kt
  59. 385 0
      app/src/main/java/com/khmer9/lotto/screen/play/PlayFragment.kt
  60. 48 0
      app/src/main/java/com/khmer9/lotto/screen/report/ReportAdapter.kt
  61. 159 0
      app/src/main/java/com/khmer9/lotto/screen/report/ReportListViewHolder.kt
  62. 16 0
      app/src/main/java/com/khmer9/lotto/screen/report/ReportViewState.kt
  63. 174 0
      app/src/main/java/com/khmer9/lotto/screen/report/StatementFragment.kt
  64. 280 0
      app/src/main/java/com/khmer9/lotto/screen/result/ResultFragment.kt
  65. 11 0
      app/src/main/java/com/khmer9/lotto/screen/result/ResultViewState.kt
  66. 20 0
      app/src/main/java/com/khmer9/lotto/screen/result/Table1Adapter.kt
  67. 11 0
      app/src/main/java/com/khmer9/lotto/screen/result/Table1ListItem.kt
  68. 34 0
      app/src/main/java/com/khmer9/lotto/screen/result/Table1ListViewHolder.kt
  69. 20 0
      app/src/main/java/com/khmer9/lotto/screen/result/Table2Adapter.kt
  70. 11 0
      app/src/main/java/com/khmer9/lotto/screen/result/Table2ListItem.kt
  71. 47 0
      app/src/main/java/com/khmer9/lotto/screen/result/Table2ListViewHolder.kt
  72. 184 0
      app/src/main/java/com/khmer9/lotto/screen/setting/SettingFragment.kt
  73. 49 0
      app/src/main/java/com/khmer9/lotto/screen/setting/SettingViewModel.kt
  74. 10 0
      app/src/main/java/com/khmer9/lotto/screen/setting/UpdatePwdViewState.kt
  75. 102 0
      app/src/main/java/com/khmer9/lotto/screen/splash/SplashScreenActivity.kt
  76. 36 0
      app/src/main/java/com/khmer9/lotto/util/AnimationDrawableWithCallback.java
  77. 25 0
      app/src/main/java/com/khmer9/lotto/util/BaseObservable.java
  78. 52 0
      app/src/main/java/com/khmer9/lotto/util/ConfirmDialog.kt
  79. 16 0
      app/src/main/java/com/khmer9/lotto/util/Const.kt
  80. 66 0
      app/src/main/java/com/khmer9/lotto/util/CustomAnimationDrawable.java
  81. 25 0
      app/src/main/java/com/khmer9/lotto/util/DimensionUtil.kt
  82. 23 0
      app/src/main/java/com/khmer9/lotto/util/DimensionUtils.kt
  83. 27 0
      app/src/main/java/com/khmer9/lotto/util/Event.kt
  84. 135 0
      app/src/main/java/com/khmer9/lotto/util/GridDividerItemDecoration.java
  85. 205 0
      app/src/main/java/com/khmer9/lotto/util/MiddleDividerItemDecoration.kt
  86. 81 0
      app/src/main/java/com/khmer9/lotto/util/ModelPreferencesManager.kt
  87. 42 0
      app/src/main/java/com/khmer9/lotto/util/PrefHelper.kt
  88. 18 0
      app/src/main/java/com/khmer9/lotto/util/SafeClickListener.kt
  89. 63 0
      app/src/main/java/com/khmer9/lotto/util/UnsafeOkHttpClient.java
  90. 81 0
      app/src/main/java/com/khmer9/lotto/view/CircleView.java
  91. 40 0
      app/src/main/java/com/khmer9/lotto/view/LottoView.java
  92. 21 0
      app/src/main/java/com/khmer9/lotto/view/MaterialTextBTB.kt
  93. 75 0
      app/src/main/java/com/khmer9/lotto/view/NoPaddingTextView.java
  94. 76 0
      app/src/main/java/com/khmer9/lotto/view/RectangleView.java
  95. 44 0
      app/src/main/java/com/khmer9/lotto/view/ResultView.java
  96. 77 0
      app/src/main/java/com/khmer9/lotto/view/SettingButtonView.java
  97. 64 0
      app/src/main/java/com/khmer9/lotto/view/SquareView.java
  98. 8 0
      app/src/main/res/anim/blink.xml
  99. 10 0
      app/src/main/res/anim/fade_in.xml
  100. 11 0
      app/src/main/res/anim/rotation.xml

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx

+ 3 - 0
.idea/.gitignore

@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml

+ 1 - 0
.idea/.name

@@ -0,0 +1 @@
+SampleApp

+ 122 - 0
.idea/codeStyles/Project.xml

@@ -0,0 +1,122 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <JetCodeStyleSettings>
+      <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
+    </JetCodeStyleSettings>
+    <codeStyleSettings language="XML">
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+      <arrangement>
+        <rules>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:android</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:id</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>style</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+        </rules>
+      </arrangement>
+    </codeStyleSettings>
+    <codeStyleSettings language="kotlin">
+      <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
+    </codeStyleSettings>
+  </code_scheme>
+</component>

+ 5 - 0
.idea/codeStyles/codeStyleConfig.xml

@@ -0,0 +1,5 @@
+<component name="ProjectCodeStyleConfiguration">
+  <state>
+    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
+  </state>
+</component>

+ 6 - 0
.idea/compiler.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <bytecodeTargetLevel target="11" />
+  </component>
+</project>

+ 21 - 0
.idea/gradle.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleMigrationSettings" migrationVersion="1" />
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="testRunner" value="GRADLE" />
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+            <option value="$PROJECT_DIR$/printooth" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 35 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="BintrayJCenter" />
+      <option name="name" value="BintrayJCenter" />
+      <option name="url" value="https://jcenter.bintray.com/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="Google" />
+      <option name="name" value="Google" />
+      <option name="url" value="https://dl.google.com/dl/android/maven2/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="maven" />
+      <option name="name" value="maven" />
+      <option name="url" value="https://jitpack.io" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="MavenRepo" />
+      <option name="name" value="MavenRepo" />
+      <option name="url" value="https://repo.maven.apache.org/maven2/" />
+    </remote-repository>
+  </component>
+</project>

+ 24 - 0
.idea/misc.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+  <component name="masterDetails">
+    <states>
+      <state key="ScopeChooserConfigurable.UI">
+        <settings>
+          <splitter-proportions>
+            <option name="proportions">
+              <list>
+                <option value="0.2" />
+              </list>
+            </option>
+          </splitter-proportions>
+        </settings>
+      </state>
+    </states>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
+/build

+ 167 - 0
app/build.gradle

@@ -0,0 +1,167 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
+// Apply the Crashlytics Gradle plugin
+apply plugin: 'com.google.gms.google-services'
+apply plugin: 'com.google.firebase.crashlytics'
+android {
+
+    compileSdkVersion 29
+    buildToolsVersion "29.0.3"
+    signingConfigs {
+        release {
+             storeFile rootProject.file("evaluation-testing.jks")
+            //storeFile file('D:\\Desktop\\evaluation-testing.jks')
+            storePassword "123456"
+            keyAlias = "gdt"
+            keyPassword "123456"
+        }
+    }
+    defaultConfig {
+        applicationId "com.khmer9.lotto"
+        minSdkVersion 21
+        targetSdkVersion 29
+        versionCode 10
+        versionName "1.9"
+        signingConfig signingConfigs.release
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        debug {
+            manifestPlaceholders = [enableCrashlytic:false]
+            firebaseCrashlytics.mappingFileUploadEnabled false
+            minifyEnabled false
+            debuggable true
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+        release {
+            manifestPlaceholders = [enableCrashlytic:true]
+            firebaseCrashlytics.mappingFileUploadEnabled true
+            shrinkResources true
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+
+// To inline the bytecode built with JVM target 1.8 into
+// bytecode that is being built with JVM target 1.6. (e.g. navArgs)
+
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    kotlinOptions {
+        jvmTarget = "1.8"
+    }
+    androidExtensions {
+        experimental = true
+    }
+    packagingOptions {
+        exclude 'META-INF/DEPENDENCIES'
+        exclude 'META-INF/LICENSE'
+        exclude 'META-INF/LICENSE.txt'
+        exclude 'META-INF/license.txt'
+        exclude 'META-INF/NOTICE'
+        exclude 'META-INF/NOTICE.txt'
+        exclude 'META-INF/notice.txt'
+        exclude 'META-INF/ASL2.0'
+    }
+    lintOptions {
+        checkReleaseBuilds false
+        abortOnError false
+    }
+    flavorDimensions 'env'
+    productFlavors {
+        dev {
+            dimension 'env'
+            //applicationIdSuffix = ".dev"
+            versionNameSuffix "-dev"
+        }
+        prod {
+            dimension 'env'
+        }
+    }
+    applicationVariants.all { variant ->
+        variant.outputs.all {
+            //def formattedDate = new Date().format('yyyy-MM-dd HH-mm')
+
+            def appName = "Khmer9_Lotto"
+            def appId = variant.applicationId
+            def versionName = variant.versionName
+            def versionCode = variant.versionCode
+            def flavorName = variant.flavorName // e. g. free
+            def buildType = variant.buildType // e. g. debug
+            def variantName = variant.name // e. g. freeDebug
+
+            def apkName = appName + '_' + variantName + '_' + versionName + '.apk'
+            outputFileName = apkName
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+    implementation 'androidx.appcompat:appcompat:1.2.0'
+    implementation 'androidx.core:core-ktx:1.3.2'
+    implementation 'com.google.android.material:material:1.2.1'
+    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.3'
+    implementation 'androidx.navigation:navigation-ui-ktx:2.3.3'
+
+
+
+    //Architecture components
+    def lifecycle_version = "2.2.0"
+    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
+    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
+
+    //RxJava & RxAndroid
+    implementation "io.reactivex.rxjava2:rxjava:2.2.18"
+    implementation "io.reactivex.rxjava2:rxkotlin:2.4.0"
+    implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
+
+    //Retrofit
+    def retrofit_version = "2.9.0"
+    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
+    implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version"
+    implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"
+    implementation 'com.squareup.okhttp3:logging-interceptor:4.7.2'
+    implementation 'com.itkacher.okhttpprofiler:okhttpprofiler:1.0.7'
+
+//
+//    /*Json Serialize & Deserialize Library*/
+    implementation("com.squareup.moshi:moshi-kotlin:1.9.2")
+    kapt("com.squareup.moshi:moshi-kotlin-codegen:1.9.2")
+//Socket io client
+    implementation 'com.github.nkzawa:socket.io-client:0.6.0'
+
+//
+//    //Logging helper
+    implementation 'com.jakewharton.timber:timber:4.7.1'
+    implementation 'com.google.code.gson:gson:2.8.6'
+
+    //implementation 'com.github.mazenrashed:Printooth:1.2.2'
+    //Lib
+    implementation project(path: ':printooth')
+    implementation 'com.squareup.picasso:picasso:2.71828'
+
+//Firebase
+// Import the BoM for the Firebase platform
+    implementation platform('com.google.firebase:firebase-bom:26.4.0')
+    implementation 'com.google.firebase:firebase-crashlytics-ktx'
+    implementation 'com.google.firebase:firebase-analytics-ktx'
+    implementation 'com.google.firebase:firebase-config-ktx'
+
+    implementation 'nl.dionsegijn:konfetti:1.3.2'
+
+
+    testImplementation 'junit:junit:4.13.1'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}

BIN
app/dev/release/Khmer9_Lotto_devRelease_1.0-newicon-dev.apk


BIN
app/dev/release/Khmer9_Lotto_devRelease_1.4-dev.apk


+ 18 - 0
app/dev/release/output-metadata.json

@@ -0,0 +1,18 @@
+{
+  "version": 2,
+  "artifactType": {
+    "type": "APK",
+    "kind": "Directory"
+  },
+  "applicationId": "com.khmer9.lotto",
+  "variantName": "processDevReleaseResources",
+  "elements": [
+    {
+      "type": "SINGLE",
+      "filters": [],
+      "versionCode": 5,
+      "versionName": "1.4-dev",
+      "outputFile": "Khmer9_Lotto_devRelease_1.4-dev.apk"
+    }
+  ]
+}

+ 39 - 0
app/google-services.json

@@ -0,0 +1,39 @@
+{
+  "project_info": {
+    "project_number": "1051787698407",
+    "project_id": "khmer9lotto",
+    "storage_bucket": "khmer9lotto.appspot.com"
+  },
+  "client": [
+    {
+      "client_info": {
+        "mobilesdk_app_id": "1:1051787698407:android:e305f17484f532b9490242",
+        "android_client_info": {
+          "package_name": "com.khmer9.lotto"
+        }
+      },
+      "oauth_client": [
+        {
+          "client_id": "1051787698407-ki8dmfdjpfdq84r9mi3h9l44h62uod3p.apps.googleusercontent.com",
+          "client_type": 3
+        }
+      ],
+      "api_key": [
+        {
+          "current_key": "AIzaSyDFmRHJwml_ByjIL1sVBW4oDSDI4cFCEDA"
+        }
+      ],
+      "services": {
+        "appinvite_service": {
+          "other_platform_oauth_client": [
+            {
+              "client_id": "1051787698407-ki8dmfdjpfdq84r9mi3h9l44h62uod3p.apps.googleusercontent.com",
+              "client_type": 3
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "configuration_version": "1"
+}

+ 18 - 0
app/prod/debug/output-metadata.json

@@ -0,0 +1,18 @@
+{
+  "version": 2,
+  "artifactType": {
+    "type": "APK",
+    "kind": "Directory"
+  },
+  "applicationId": "com.sambath.loto",
+  "variantName": "processProdDebugResources",
+  "elements": [
+    {
+      "type": "SINGLE",
+      "filters": [],
+      "versionCode": 1,
+      "versionName": "1.0",
+      "outputFile": "App_prodDebug_1.0_1.apk"
+    }
+  ]
+}

BIN
app/prod/release/Khmer9_Lotto_prodRelease_1.9.apk


+ 18 - 0
app/prod/release/output-metadata.json

@@ -0,0 +1,18 @@
+{
+  "version": 2,
+  "artifactType": {
+    "type": "APK",
+    "kind": "Directory"
+  },
+  "applicationId": "com.khmer9.lotto",
+  "variantName": "processProdReleaseResources",
+  "elements": [
+    {
+      "type": "SINGLE",
+      "filters": [],
+      "versionCode": 10,
+      "versionName": "1.9",
+      "outputFile": "Khmer9_Lotto_prodRelease_1.9.apk"
+    }
+  ]
+}

+ 116 - 0
app/proguard-rules.pro

@@ -0,0 +1,116 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+-keep class * implements java.io.Serializable { *; }
+
+-keepattributes *Annotation*
+
+#### OkHttp, Retrofit and Moshi
+-dontwarn okhttp3.**
+-dontwarn retrofit2.Platform$Java8
+-dontwarn okio.**
+-dontwarn javax.annotation.**
+-dontwarn org.jetbrains.annotations.**
+
+#-keep class kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoaderImpl
+-keep class kotlin.Metadata { *; }
+-keepclassmembers class kotlin.Metadata {
+    public <methods>;
+}
+
+#-keepnames @kotlin.Metadata class gdt.com.e_payments.data.model.**
+#-keep class gdt.com.e_payments.data.model.** { *; }
+#-keepclassmembers class gdt.com.e_payments.data.model.** { *; }
+
+-keepclasseswithmembers class * {
+    @retrofit2.http.* <methods>;
+}
+
+-keepclasseswithmembers class * {
+    @com.squareup.moshi.* <methods>;
+}
+-keepclassmembers class * {
+    @com.squareup.moshi.FromJson <methods>;
+    @com.squareup.moshi.ToJson <methods>;
+}
+-keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
+    <fields>;
+    **[] values();
+}
+
+-keep @com.squareup.moshi.JsonQualifier interface *
+-keepnames @com.squareup.moshi.JsonClass class *
+
+# Retain generated target class's synthetic defaults constructor and keep DefaultConstructorMarker's
+# name. We will look this up reflectively to invoke the type's constructor.
+#
+# We can't _just_ keep the defaults constructor because Proguard/R8's spec doesn't allow wildcard
+# matching preceding parameters.
+-keepnames class kotlin.jvm.internal.DefaultConstructorMarker
+-keepclassmembers @com.squareup.moshi.JsonClass @kotlin.Metadata class * {
+    synthetic <init>(...);
+}
+
+# Retain generated JsonAdapters if annotated type is retained.
+-if @com.squareup.moshi.JsonClass class *
+-keep class <1>JsonAdapter {
+    <init>(...);
+    <fields>;
+}
+-if @com.squareup.moshi.JsonClass class **$*
+-keep class <1>_<2>JsonAdapter {
+    <init>(...);
+    <fields>;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*
+-keep class <1>_<2>_<3>JsonAdapter {
+    <init>(...);
+    <fields>;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*$*
+-keep class <1>_<2>_<3>_<4>JsonAdapter {
+    <init>(...);
+    <fields>;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*$*$*
+-keep class <1>_<2>_<3>_<4>_<5>JsonAdapter {
+    <init>(...);
+    <fields>;
+}
+-if @com.squareup.moshi.JsonClass class **$*$*$*$*$*
+-keep class <1>_<2>_<3>_<4>_<5>_<6>JsonAdapter {
+    <init>(...);
+    <fields>;
+}
+
+# RxJava
+-dontwarn org.reactivestreams.FlowAdapters
+-dontwarn org.reactivestreams.**
+-dontwarn java.util.concurrent.Flow.**
+-dontwarn java.util.concurrent.**
+# Firebase Crashlytics
+-keepattributes SourceFile,LineNumberTable        # Keep file names and line numbers.
+-keep public class * extends java.lang.Exception  # Optional: Keep custom exceptions.
+-keep class com.google.firebase.crashlytics. { *; }
+-dontwarn com.google.firebase.crashlytics.
+#-keepnames @kotlin.Metadata class com.gdt.dev.gdtevaluationAdmin.data.remote.model.**
+#-keep class com.gdt.dev.gdtevaluationAdmin.data.remote.model.** { *; }
+#-keepclassmembers class com.gdt.dev.gdtevaluationAdmin.data.remote.model.** { *; }

+ 24 - 0
app/src/androidTest/java/com/khmer9/lotto/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.khmer9.lotto
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.sambath.loto", appContext.packageName)
+    }
+}

+ 8 - 0
app/src/dev/java/com/khmer9/lotto/config/Config.kt

@@ -0,0 +1,8 @@
+package com.khmer9.lotto.config
+
+object Config {
+
+    const val BASE_URL = "http://159.203.19.62:3010"
+    const val SOCKET_URL = "http://159.203.19.62:4010/loto-betting"
+
+}

+ 50 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.khmer9.lotto">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <meta-data
+        android:name="firebase_crashlytics_collection_enabled"
+        android:value="${enableCrashlytic}" />
+
+    <application
+        android:name="com.khmer9.lotto.app.App"
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:hardwareAccelerated="true"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme"
+        android:usesCleartextTraffic="true"
+        tools:targetApi="m">
+        <activity
+            android:name="com.khmer9.lotto.app.ShareActivity"
+            android:label="@string/app_name"
+            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
+            android:screenOrientation="sensorPortrait"
+            android:windowSoftInputMode="adjustResize" />
+        <activity
+            android:name="com.khmer9.lotto.screen.login.LoginActivity"
+            android:label="@string/app_name"
+            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
+            android:screenOrientation="sensorPortrait"
+            android:windowSoftInputMode="adjustResize"/>
+
+        <activity android:name="com.khmer9.lotto.screen.splash.SplashScreenActivity"
+            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
+            android:screenOrientation="sensorPortrait"
+            android:windowSoftInputMode="adjustResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+
+        </activity>
+    </application>
+
+</manifest>

BIN
app/src/main/ic_launcher-playstore.png


+ 47 - 0
app/src/main/java/com/khmer9/lotto/adapter/AbstractAdapter.kt

@@ -0,0 +1,47 @@
+package com.gdtlib.lib.adapter
+
+import android.view.LayoutInflater
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.viewholder.AbstractViewHolder
+
+/**
+ * An abstract class of [RecyclerView.Adapter] to display a list of [T]
+ */
+abstract class AbstractAdapter<T : Any>(
+    protected val inflater: LayoutInflater
+) : RecyclerView.Adapter<AbstractViewHolder<T>>(),
+    AbstractViewHolder.OnClickListener {
+
+    interface OnItemClickListener<T : Any> {
+        fun onItemClick(item: T)
+
+    }
+
+    var listener: OnItemClickListener<T>? = null
+
+    var list: List<T> = ArrayList()
+        set(value) {
+            if (field.isNotEmpty()) (field as ArrayList).clear()
+            (field as ArrayList).addAll(value)
+            notifyDataSetChanged()
+        }
+
+    fun addList(list: List<T>) {
+        if (list.isEmpty()) return
+        (this.list as ArrayList).addAll(list)
+        notifyDataSetChanged()
+    }
+
+    override fun getItemCount(): Int {
+        return list.size
+    }
+
+    override fun onBindViewHolder(holder: AbstractViewHolder<T>, position: Int) {
+        val user = list[position]
+        holder.bindView(user)
+    }
+
+    override fun onClick(position: Int) {
+        listener?.onItemClick(list[position])
+    }
+}

+ 23 - 0
app/src/main/java/com/khmer9/lotto/adapter/AbstractViewHolder.kt

@@ -0,0 +1,23 @@
+package com.gdtlib.lib.viewholder
+
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+
+abstract class AbstractViewHolder<T : Any>(
+    view: View,
+    private val listener: OnClickListener?
+) : RecyclerView.ViewHolder(view){
+
+    init {
+        itemView.setOnClickListener {
+            listener?.onClick(adapterPosition)
+        }
+    }
+
+    interface OnClickListener {
+        fun onClick(position: Int)
+    }
+
+    abstract fun bindView(item: T)
+
+}

+ 31 - 0
app/src/main/java/com/khmer9/lotto/adapter/BaseListAdapter.kt

@@ -0,0 +1,31 @@
+package com.gdtlib.lib.adapter
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+
+abstract class BaseListAdapter :
+  ListAdapter<BaseListItem, RecyclerView.ViewHolder>(
+    BaseListItem.ITEM_CALLBACK
+  ) {
+
+  private var itemClickListener: ((Int) -> Unit)? = null
+  private var loadMoreListener: (() -> Unit)? = null
+
+  fun setItemClickListener(itemClickListener: ((Int) -> Unit)?) {
+    this.itemClickListener = itemClickListener
+  }
+
+  fun setLoadMoreListener(loadMoreListener: (() -> Unit)?) {
+    this.loadMoreListener = loadMoreListener
+  }
+
+  override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+    if (holder is BaseListViewHolder) {
+      holder.bindView(getItem(position))
+      holder.setClickListener(itemClickListener)
+      if (position >= itemCount - 1 - 2) {
+        loadMoreListener?.invoke()
+      }
+    }
+  }
+}

+ 21 - 0
app/src/main/java/com/khmer9/lotto/adapter/BaseListItem.kt

@@ -0,0 +1,21 @@
+package com.gdtlib.lib.adapter
+
+import android.annotation.SuppressLint
+import androidx.recyclerview.widget.DiffUtil
+
+abstract class BaseListItem {
+
+    companion object {
+
+        val ITEM_CALLBACK = object : DiffUtil.ItemCallback<BaseListItem>() {
+            override fun areItemsTheSame(oldItem: BaseListItem, newItem: BaseListItem) =
+                oldItem.getUnique() == newItem.getUnique()
+
+            @SuppressLint("DiffUtilEquals")
+            override fun areContentsTheSame(oldItem: BaseListItem, newItem: BaseListItem) =
+                oldItem == newItem
+        }
+    }
+
+    abstract fun getUnique(): String
+}

+ 58 - 0
app/src/main/java/com/khmer9/lotto/adapter/BaseListViewHolder.kt

@@ -0,0 +1,58 @@
+package com.gdtlib.lib.viewholder
+
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListItem
+
+abstract class BaseListViewHolder(
+    itemView: View
+) : RecyclerView.ViewHolder(itemView) {
+
+    abstract fun bindView(item: BaseListItem)
+
+    fun setClickListener(clickListener: ((Int) -> Unit)?) {
+        if (clickListener != null) {
+            itemView.setOnClickListener {
+                clickListener(adapterPosition)
+            }
+        } else {
+            itemView.setOnClickListener(null)
+        }
+    }
+    companion object{
+        fun  getCurrency(currency: Int): String{
+            val short = currency/1000
+
+            return "${short}K"
+
+
+
+        }
+        fun getBettingId(playNo:String, playDate: String) : String {
+
+            val playID = playNo.subSequence(0,playNo.length-5)
+            val playTime = playDate.subSequence(playDate.length -8, playDate.length-3)
+            return "$playID $playTime"
+
+        }
+
+        fun getTypeOfBetting(type: String): String{
+            return when(type){
+                "Small" -> "U"
+                "Large" -> "O"
+                else -> type
+            }
+        }
+
+        fun convertToTypeOfBetting(type: String): String{
+            return when(type){
+                "U" -> "Small"
+                "O" -> "Large"
+                else -> type
+            }
+        }
+
+
+    }
+
+}

+ 144 - 0
app/src/main/java/com/khmer9/lotto/app/App.kt

@@ -0,0 +1,144 @@
+package com.khmer9.lotto.app
+
+import android.app.Application
+import android.content.Context
+import com.itkacher.okhttpprofiler.OkHttpProfilerInterceptor
+import com.mazenrashed.printooth.Printooth
+import com.khmer9.lotto.BuildConfig
+import com.khmer9.lotto.remote.service.ApiService
+import com.khmer9.lotto.remote.service.SocketService
+import com.khmer9.lotto.util.*
+import com.squareup.moshi.Moshi
+import com.khmer9.lotto.config.Config
+import com.squareup.picasso.Picasso
+import okhttp3.OkHttpClient
+import retrofit2.CallAdapter
+import retrofit2.Converter
+import retrofit2.Retrofit
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
+import retrofit2.converter.moshi.MoshiConverterFactory
+import timber.log.Timber
+
+
+class App : Application() {
+
+    companion object {
+        private lateinit var retrofit: Retrofit
+        private lateinit var apiService: ApiService
+        private lateinit var socketService: SocketService
+        private lateinit var picasso: Picasso
+
+        //private lateinit var loginViewModel: LoginViewModel
+        //private lateinit var settingViewModel: SettingViewModel
+        private lateinit var shareViewModel: ShareViewModel
+        private lateinit var prefHelper: PrefHelper
+        var guidelineLeft: Float = 0f
+        var guidelineRight: Float = 100f
+
+        fun injectApiService() = apiService
+        //fun injectLoginViewModel() = loginViewModel
+        fun injectShareViewModel() = shareViewModel
+        //fun injectSettingViewModel() = settingViewModel
+        fun injectPrefHelper() = prefHelper
+        // Called on main activity create
+        fun onAppStart(userID: String) {
+           // Log.d("Socket", "onAppStart")
+            shareViewModel.startListeningToSocketServer(userID)
+        }
+
+        // Called on main activity destroy
+        fun onAppStop() {
+            //Log.d("Socket", "onAppStop")
+            shareViewModel.stopListeningToSocketServer()
+        }
+
+    }
+
+    override fun onCreate() {
+        super.onCreate()
+        ModelPreferencesManager.with(this)
+        Printooth.init(this)
+        picasso = Picasso.Builder(this).loggingEnabled(true).build()
+       // FirebaseApp.initializeApp(this)
+        Picasso.setSingletonInstance(picasso)
+
+        if (BuildConfig.DEBUG){
+            Timber.uprootAll()
+            Timber.plant(Timber.DebugTree())
+
+        }
+        val widthPx = screenRectPx.width()
+        val heightPx = screenRectPx.height()
+        val percentage =widthPx*100/heightPx
+       // Log.d("DATA", ""+widthPx)
+       // Log.d("DATA", ""+heightPx)
+      //  Log.d("DATA", ""+percentage)
+
+        when(percentage){
+            in 30..54->{
+                guidelineLeft = 0f
+                guidelineRight = 1f
+
+            }
+            else -> {
+                guidelineLeft = 0.05f
+                guidelineRight = 0.95f
+            }
+
+
+        }
+
+        prefHelper = PrefHelper(context =appContext(this))
+        val builder = OkHttpClient.Builder()
+
+        if(BuildConfig.DEBUG){
+            builder
+                .addInterceptor(ServiceInterceptor(prefHelper))
+                .addInterceptor(OkHttpProfilerInterceptor())
+                .addInterceptor(ErrorInterceptor(appContext(this), prefHelper))
+               // .readTimeout(5, TimeUnit.MINUTES)
+               // .writeTimeout(60,TimeUnit.SECONDS)
+
+        }else{
+
+            builder
+                .addInterceptor(ServiceInterceptor(prefHelper))
+                .addInterceptor(ErrorInterceptor(appContext(this), prefHelper))
+               // .readTimeout(5, TimeUnit.MINUTES)
+               // .writeTimeout(60,TimeUnit.SECONDS)
+
+        }
+
+        val client = builder.build()
+        retrofit = Retrofit.Builder()
+            .baseUrl(Config.BASE_URL)
+            .client(client)
+            .addCallAdapterFactory(callFactory())
+            .addConverterFactory(converterFactory(moshi()))
+            .build()
+
+        apiService = retrofit.create(ApiService::class.java)
+        socketService = SocketService()
+        //loginViewModel = LoginViewModel(apiService, prefHelper)
+        //settingViewModel = SettingViewModel(apiService, prefHelper)
+        shareViewModel = ShareViewModel(apiService, prefHelper, socketService)
+
+
+
+    }
+
+
+    private fun callFactory(): CallAdapter.Factory = RxJava2CallAdapterFactory.create()
+
+
+
+    private fun converterFactory(moshi: Moshi): Converter.Factory =
+        MoshiConverterFactory.create(moshi).withNullSerialization()
+
+    private fun moshi(): Moshi = Moshi.Builder().build()
+    //fun unSafeOkHttpClient(): OkHttpClient = UnsafeOkHttpClient.getClient()
+    private fun appContext(app: App): Context = app
+
+    fun unSafeOkHttpClient(): OkHttpClient = UnsafeOkHttpClient.getClient()
+
+}

+ 41 - 0
app/src/main/java/com/khmer9/lotto/app/ErrorInterceptor.kt

@@ -0,0 +1,41 @@
+package com.khmer9.lotto.app
+
+import android.content.Context
+import android.content.Intent
+import com.khmer9.lotto.screen.login.LoginActivity
+import com.khmer9.lotto.util.PrefHelper
+import okhttp3.Interceptor
+import okhttp3.Request
+import okhttp3.Response
+
+class ErrorInterceptor(private val context: Context, private val prefHelper: PrefHelper) : Interceptor {
+    override fun intercept(chain: Interceptor.Chain): Response {
+
+        val request: Request = chain.request()
+        val response = chain.proceed(request)
+        when (response.code) {
+//            400 -> {
+//                //Show Bad Request Error Message
+//            }
+            401 -> {
+                //Show UnauthorizedError Message
+                    prefHelper.logout()
+                    val i =  Intent(context, LoginActivity::class.java)
+                    i.flags=Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
+                    context.startActivity(i)
+            }
+
+//            403 -> {
+//                //Show Forbidden Message
+//            }
+//
+//            404 -> {
+//                //Show NotFound Message
+//            }
+
+            // ... and so on
+
+        }
+        return response
+    }
+}

+ 14 - 0
app/src/main/java/com/khmer9/lotto/app/ExceptionExtension.kt

@@ -0,0 +1,14 @@
+package com.khmer9.lotto.app
+
+import java.net.ConnectException
+import java.net.SocketTimeoutException
+import java.util.concurrent.TimeoutException
+
+fun Throwable.getErrorCode(): String {
+    return when (this) {
+        is SocketTimeoutException -> "[120]"
+        is ConnectException -> "[120]"
+        is TimeoutException -> "[121]"
+        else -> "[122]"
+    }
+}

+ 33 - 0
app/src/main/java/com/khmer9/lotto/app/ServiceInterceptor.kt

@@ -0,0 +1,33 @@
+package com.khmer9.lotto.app
+
+import com.khmer9.lotto.util.PrefHelper
+import okhttp3.Interceptor
+import okhttp3.Response
+
+class ServiceInterceptor(private val prefHelper: PrefHelper) : Interceptor {
+
+//    var token : String = "";
+//
+//    fun Token(token: String ) {
+//        this.token = token;
+//    }
+
+    override fun intercept(chain: Interceptor.Chain): Response {
+        var request = chain.request()
+
+        if(request.header("No-Authentication")==null){
+            //or use Token Function
+            if(prefHelper.getToken().isNotEmpty())
+            {
+                val finalToken = "${prefHelper.getToken()}"
+                request = request.newBuilder()
+                    .addHeader("Authorization",finalToken)
+                    .build()
+            }
+
+        }
+
+        return chain.proceed(request)
+    }
+
+}

+ 157 - 0
app/src/main/java/com/khmer9/lotto/app/ShareActivity.kt

@@ -0,0 +1,157 @@
+package com.khmer9.lotto.app
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
+import androidx.constraintlayout.widget.Group
+import androidx.core.view.isVisible
+import com.google.firebase.ktx.Firebase
+import com.google.firebase.remoteconfig.FirebaseRemoteConfig
+import com.google.firebase.remoteconfig.ktx.remoteConfig
+import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
+import com.khmer9.lotto.R
+import com.khmer9.lotto.base.BaseActivity
+import com.khmer9.lotto.remote.User
+import com.khmer9.lotto.screen.main.MainFragment
+import com.khmer9.lotto.util.Const
+import com.khmer9.lotto.util.ModelPreferencesManager
+import com.khmer9.lotto.util.PrefHelper
+
+class ShareActivity : BaseActivity() {
+
+    lateinit var settingImageView: ImageView
+    lateinit var reportImageView: ImageView
+    lateinit var soundImageView: ImageView
+    lateinit var userNameTextView : TextView
+    lateinit var balanceTextView: TextView
+    lateinit var refreshImageView: ImageView
+    private lateinit var remoteConfig: FirebaseRemoteConfig
+    lateinit var userShare: User
+
+    lateinit var groupToolbarIcons : Group
+    lateinit var sharePref: PrefHelper
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        //Log.d("Oncreate", "before")
+        ModelPreferencesManager.get<User>(Const.USER_KEY)?.let {
+            userShare = it
+        }
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        sharePref= App.injectPrefHelper()
+
+
+        remoteConfig = Firebase.remoteConfig
+        val configSettings = remoteConfigSettings {
+            minimumFetchIntervalInSeconds = 3600
+        }
+        remoteConfig.setConfigSettingsAsync(configSettings)
+        //Log.d("Oncreate", "after")
+        if (savedInstanceState == null) {
+            supportFragmentManager.beginTransaction()
+                .add(
+                    R.id.container,
+                    MainFragment().apply {
+                        arguments =
+                            Bundle().apply {
+                                //putInt(InventoryFragment.COM_INTO_ID_KEY,10)
+                            }
+
+                    })
+                .addToBackStack(null)
+                .commit()
+        }
+
+        remoteConfig.fetchAndActivate()
+        val isActivated: String = remoteConfig.getString("is_activated")
+        if (isActivated == "0") finishAffinity()
+
+        reportImageView=findViewById<ImageView>(R.id.iv_report)
+        settingImageView=findViewById<ImageView>(R.id.iv_setting)
+        soundImageView=findViewById<ImageView>(R.id.iv_sound)
+        refreshImageView = findViewById<ImageView>(R.id.iv_auto_new)
+        groupToolbarIcons=findViewById<Group>(R.id.group_toolbar_icons)
+        userNameTextView = findViewById<TextView>(R.id.tv_user_id)
+        balanceTextView = findViewById<TextView>(R.id.tv_amount)
+
+        soundImageView.setOnClickListener {
+            if (sharePref.getIsMute()){
+                sharePref.setIsMute(false)
+                soundImageView.setImageResource(R.drawable.ic_unmute)
+            }else{
+                sharePref.setIsMute(true)
+                soundImageView.setImageResource(R.drawable.ic_mute)
+
+            }
+        }
+
+        if (sharePref.getIsMute()){
+            soundImageView.setImageResource(R.drawable.ic_mute)
+        }else{
+            soundImageView.setImageResource(R.drawable.ic_unmute)
+
+        }
+
+    }
+    override fun onWindowFocusChanged(hasFocus: Boolean) {
+        super.onWindowFocusChanged(hasFocus)
+        //Log.d("Window", "hase focus")
+
+        if (hasFocus) hideSystemUI()
+    }
+
+    private fun hideSystemUI() {
+
+        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                // Set the content to appear under the system bars so that the
+                // content doesn't resize when the system bars hide and show.
+                or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                // Hide the nav bar and status bar
+                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                or View.SYSTEM_UI_FLAG_FULLSCREEN)
+
+    }
+    override fun onBackPressed() {
+        val count = supportFragmentManager.backStackEntryCount
+        when {
+            count == 1 ->  {
+
+                finish()
+            }
+
+            else -> {
+                groupToolbarIcons.isVisible=true
+
+                super.onBackPressed()
+            }
+        }
+    }
+    override fun onDestroy() {
+        super.onDestroy()
+    }
+
+    private var confirmDialog: AlertDialog? = null
+
+
+    override fun onPause() {
+        super.onPause()
+        App.onAppStop()
+
+        //Log.d("Lifecycle","onPause")
+
+    }
+    override fun onResume() {
+        super.onResume()
+        App.onAppStart(userID = userShare.id)
+
+        //Log.d("Lifecycle","onResume")
+    }
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+    }
+}

+ 380 - 0
app/src/main/java/com/khmer9/lotto/app/ShareViewModel.kt

@@ -0,0 +1,380 @@
+package com.khmer9.lotto.app
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.khmer9.lotto.base.BaseViewModel
+import com.khmer9.lotto.extension.prepend
+import com.khmer9.lotto.remote.*
+import com.khmer9.lotto.remote.service.EventListener
+import com.khmer9.lotto.remote.service.ApiService
+import com.khmer9.lotto.remote.service.ConnectivityStates
+import com.khmer9.lotto.remote.service.SocketService
+import com.khmer9.lotto.screen.report.ReportViewState
+import com.khmer9.lotto.screen.result.ResultViewState
+import com.khmer9.lotto.util.Event
+import com.khmer9.lotto.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import org.json.JSONObject
+import java.net.URISyntaxException
+import java.util.concurrent.TimeUnit
+
+class ShareViewModel(
+    private val apiService: ApiService,
+    private val prefHelper: PrefHelper,
+    private val socketService: SocketService
+) : BaseViewModel(), EventListener {
+    //Socket Data LiveData
+    private val newMessagesLotto = MutableLiveData<SocketMessageDataModel>()
+    val getLottoMessage: LiveData<SocketMessageDataModel> get() = newMessagesLotto
+
+    //Socket Data LiveData
+    private val newCreatedBetting = MutableLiveData<JSONObject>()
+    val getBettingCreated: LiveData<JSONObject> get() = newCreatedBetting
+
+    //Socket Connection Live Data
+    private val connectivityStateLD = MutableLiveData<Int>()
+    val getConnectivityStates: LiveData<Int> get() = connectivityStateLD
+    //MainScreen and Create Betting Screen
+    private val shareState = MutableLiveData<ShareViewState>(ShareViewState())
+    val getShareState: LiveData<ShareViewState> = shareState
+
+    //Result Screen Live Data
+    private val resultState = MutableLiveData<ResultViewState>(ResultViewState())
+    val getResultState: LiveData<ResultViewState> = resultState
+
+    //Report Screen Live Data
+    private val reportState = MutableLiveData<ReportViewState>(ReportViewState())
+    val getReportState: LiveData<ReportViewState> = reportState
+
+//    val isCallAPI = MutableLiveData<Boolean>()
+//    fun setIsCall(isCall: Boolean) {
+//        isCallAPI.postValue(isCall)
+//    }
+
+    fun remoteReport(userId: String){
+        if (reportState.value!!.isProgress) return
+        reportState.value = prevReport().copy(isProgress = true)
+        //val user = ModelPreferencesManager.get<User>("USER")
+
+        disposables.add(
+            apiService.remoteReportScreen(userId = userId)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({response->
+                    if (response.resultCode == "1") {
+                        response.data?.let {
+
+                            reportState.value = prevReport().copy(
+                                isProgress = false,
+                                winList = it.winList,
+                                winLostList = it.winLostLst,
+                                statementList = it.statementList,
+                                error = null
+
+                            )
+
+                        }
+
+                    } else {
+                        reportState.value = prevReport().copy(isProgress = false, error = "[${response.message.description}]")
+                    }
+
+                },{
+                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
+                    reportState.value = prevReport().copy(isProgress = false, error = message)
+
+                })
+        )
+
+
+
+    }
+    fun remoteResult(){
+
+        if (resultState.value!!.isProgress) return
+        resultState.value = prevResult().copy(isProgress = true)
+        disposables.add(
+            apiService.remoteResultScreen()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({response->
+                    if (response.resultCode == "1") {
+                        response.data?.let {
+
+
+//                           val sortedList : MutableList<com.sambath.lotto.remote.Result> = mutableListOf(
+//                               Result("1","","","","","","Large","","","","1",""),
+//                               Result("2","","","","","","Large","","","","1","") ,
+//                               Result("3","","","","","","Small","","","","1",""),
+//                               Result("4","","","","","","Small","","","","5","") ,
+//                               Result("5","","","","","","Small","","","","1","") ,
+//                               Result("6","","","","","","Small","","","","1","") ,
+//                               Result("7","","","","","","Small","","","","1","") ,
+//                               Result("8","","","","","","Small","","","","1","") ,
+//                               Result("9","","","","","","Small","","","","2","") ,
+//                               Result("10","","","","","","Large","","","","2","") ,
+//                               Result("11","","","","","","Small","","","","2","") ,
+//                               Result("12","","","","","","Small","","","","2","") ,
+//                               Result("13","","","","","","Large","","","","2","") ,
+//
+//
+//                               )
+
+
+                            val sortedList = it.resultList?.sortedWith(compareBy { it.no})
+                            resultState.value = prevResult().copy(
+                                isProgress = false,
+                                resultList = sortedList,
+                                error = null
+
+
+                            )
+
+
+                        }
+
+                    } else {
+                        resultState.value = prevResult().copy(isProgress = false, error = "[${response.message.description}]")
+                    }
+
+                },{
+                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
+                    resultState.value = prevResult().copy(isProgress = false, error = message)
+
+                })
+        )
+
+
+
+    }
+
+    fun addOtherCreatedBetting(accountBalance: String, currentBetting: CurrentBetting?){
+        currentBetting?.let {
+            var newList = shareState.value?.myBettingList
+
+            if (newList.isNullOrEmpty()){
+                newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = null, amount_win = "0"))
+
+            }else {
+                if (shareState.value!!.myBettingId == it.no){
+                    newList.prepend(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = null, amount_win = "0"))
+                }else newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = null, amount_win = "0"))
+
+
+            }
+            shareState.value = prevShare().copy(
+                myBettingId = it.no,
+                myBettingList = newList,
+                accountBalance = accountBalance,
+                isAutoPrint= null,
+
+                )
+        }
+
+    }
+
+
+    fun remoteCreateBettingAPI(lottoSet: LottoSet, amount: Int, userId: String){
+
+        if (shareState.value!!.isProgress) return
+
+        val request = PlayRequest(setID = lottoSet.id,userId =userId, no = shareState.value!!.nextNo!!,cast = lottoSet.payment,amount = amount )
+
+        shareState.value = prevShare().copy(
+            initial = false,
+            isProgress = true,
+            error = null,
+            isAutoPrint = null
+        )
+
+        disposables.add(
+            apiService.createBetting(request)
+                .timeout(20, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({response->
+                    if (response.resultCode == "1") {
+                        response.data?.let {playData->
+
+                            playData.myBetting?.let {
+                                var newList = shareState.value?.myBettingList
+
+                                if (newList.isNullOrEmpty()){
+                                    newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = it.win_lose, amount_win = "0"))
+
+                                }else {
+                                    if (shareState.value!!.myBettingId == it.no){
+                                        newList.prepend(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = it.win_lose, amount_win = "0"))
+                                    }else newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = it.win_lose, amount_win = "0"))
+
+
+                                }
+
+                                shareState.value = prevShare().copy(
+                                    isProgress = false,
+                                    myBettingId = it.no,
+                                    myBettingList = newList,
+                                    currentBetting = it,
+                                    accountBalance = playData.accountBalance,
+                                    error = null,
+                                    isAutoPrint = Event(prefHelper.getIsAutoPrint())
+
+                                )
+
+                            }
+
+                        }
+
+                    } else {
+                        shareState.value = prevShare().copy(isProgress = false, error = "[${response.message.description}]")
+                    }
+
+                },{
+                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
+                    shareState.value = prevShare().copy(isProgress = false, error = message)
+
+                })
+        )
+
+    }
+
+    fun remoteMainScreenAPI(userId: String){
+
+        if (shareState.value!!.isProgress) return
+        shareState.value = prevShare().copy(
+            initial = false,
+            isProgress = true,
+            error = null,
+            myBettingId = null,
+            myBettingList = null,
+            result = null,
+            accountBalance = null,
+            nextNo = null,
+        )
+
+        disposables.add(
+            apiService.remoteMainScreen(userId)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({response->
+                    if (response.resultCode == "1") {
+                        response.data?.let {
+                            shareState.value = prevShare().copy(
+                                isProgress = false,
+                                myBettingId = it.myBetting?.id,
+                                myBettingList = it.myBetting?.data as MutableList<ListItem>?,
+                                accountBalance = it.accountBalance,
+                                nextNo = it.nextNo,
+                                result = it.result,
+                                error = null
+                            )
+                        }
+
+                    } else {
+                        shareState.value = prevShare().copy(isProgress = false, error = "[${response.message.description}]")
+                    }
+
+                },{
+                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
+                    shareState.value = prevShare().copy(isProgress = false, error = message)
+
+                })
+        )
+
+    }
+
+    // Remote
+    fun startListeningToSocketServer(userId: String) {
+        //if(prefHelper.getToken().isEmpty()) return
+        try {
+            //val jsonObjectLottoRoom = JSONObject()
+           // jsonObjectLottoRoom.put("_id", "group-loto-betting")
+
+            val jsonObjectBettingRoom = JSONObject()
+            jsonObjectBettingRoom.put("_id", "group-loto-betting")
+            jsonObjectBettingRoom.put("user_id",userId)
+            socketService.registerListener(this)
+            socketService.startListening(jsonObjectBettingRoom)
+        } catch (e: URISyntaxException) {
+            e.printStackTrace()
+        }
+    }
+
+    fun emitCreateBetting(userId : String, accountBalances: String, objCurrentBetting: CurrentBetting){
+        try {
+            val jsonObject = JSONObject()
+            val jsonCurrentBetting = JSONObject()
+            jsonCurrentBetting.put("_id",objCurrentBetting.id)
+            jsonCurrentBetting.put("no",objCurrentBetting.no)
+            jsonCurrentBetting.put("set_result_id",objCurrentBetting.setId)
+            jsonCurrentBetting.put("type_of_betting",objCurrentBetting.typeOfBetting)
+            jsonCurrentBetting.put("category",objCurrentBetting.category)
+            jsonCurrentBetting.put("user_id",objCurrentBetting.userId)
+            jsonCurrentBetting.put("date",objCurrentBetting.date)
+            jsonCurrentBetting.put("amount",objCurrentBetting.amount)
+            jsonCurrentBetting.put("cast",objCurrentBetting.cast)
+            jsonCurrentBetting.put("win_lose",objCurrentBetting.win_lose)
+            jsonCurrentBetting.put("amount_win",objCurrentBetting.amount_win)
+            jsonObject.put("_id", "group-loto-betting")
+            jsonObject.put("user_id", userId)
+            jsonObject.put("accountBalances", accountBalances)
+            jsonObject.put("objCurrentBetting", jsonCurrentBetting)
+           // Log.d("JSON", jsonObject.toString())
+
+            socketService.startEmitCreateBetting(jsonObject)
+        } catch (e: URISyntaxException) {
+            e.printStackTrace()
+        }
+    }
+
+    fun stopListeningToSocketServer() {
+        //if(prefHelper.getToken().isEmpty()) return
+        socketService.unregisterListener(this)
+        socketService.stopListening()
+    }
+
+    // Server callbacks
+
+    // Server callbacks
+    override fun onConnect() {
+        connectivityStateLD.postValue(ConnectivityStates.STATE_CONNECTED)
+    }
+
+    override fun onReconnectionTimeout() {
+        connectivityStateLD.postValue(ConnectivityStates.STATE_TIMEOUT)
+    }
+    override fun onConnectionError() {
+        connectivityStateLD.postValue(ConnectivityStates.STATE_NOT_CONNECTED)
+    }
+
+    override fun onReconnect() {
+        connectivityStateLD.postValue(ConnectivityStates.STATE_RECONNECTING)
+    }
+
+    override fun onDisconnect() {
+        connectivityStateLD.postValue(ConnectivityStates.STATE_DISCONNECTED)
+    }
+
+    override fun onNewCreatedBettingMessage(createdBettingJsonObject: JSONObject) {
+        newCreatedBetting.postValue(createdBettingJsonObject)
+    }
+
+    override fun onNewLottoMessage(chatMessage: SocketMessageDataModel) {
+
+        newMessagesLotto.postValue(chatMessage)
+
+    }
+
+    private fun prevShare() = shareState.value!!
+
+    private fun prevResult() = resultState.value!!
+
+    private fun prevReport() = reportState.value!!
+
+
+
+
+}

+ 21 - 0
app/src/main/java/com/khmer9/lotto/app/ShareViewState.kt

@@ -0,0 +1,21 @@
+package com.khmer9.lotto.app
+
+import com.khmer9.lotto.remote.CurrentBetting
+import com.khmer9.lotto.remote.ListItem
+import com.khmer9.lotto.remote.Result
+import com.khmer9.lotto.util.Event
+
+
+data class ShareViewState(
+
+    val initial: Boolean = true,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    val myBettingId: String?=null,
+    val myBettingList: MutableList<ListItem> ?= null,
+    val result: Result?= null,
+    val nextNo: String ?= null,
+    val accountBalance: String ?= null,
+    var currentBetting: CurrentBetting?= null,
+    val isAutoPrint: Event<Boolean>? = null
+)

+ 41 - 0
app/src/main/java/com/khmer9/lotto/base/BaseActivity.kt

@@ -0,0 +1,41 @@
+package com.khmer9.lotto.base
+
+import android.os.Bundle
+import android.view.MenuItem
+import androidx.appcompat.app.AppCompatActivity
+import com.khmer9.lotto.R
+
+abstract class BaseActivity : AppCompatActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        if (savedInstanceState == null) overridePendingTransition(
+            R.anim.slide_in,
+            R.anim.slide_out
+        )
+    }
+
+    override fun finish() {
+        super.finish()
+        overridePendingTransition(
+            R.anim.slide_in_exit,
+            R.anim.slide_out_exit
+        )
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        if (item.itemId == android.R.id.home) {
+            onBackPressed()
+            return true
+        }
+        return super.onOptionsItemSelected(item)
+    }
+
+    override fun onBackPressed() {
+        super.onBackPressed()
+        overridePendingTransition(
+            R.anim.slide_in_exit,
+            R.anim.slide_out_exit
+        )
+    }
+}

+ 171 - 0
app/src/main/java/com/khmer9/lotto/base/BaseFragment.kt

@@ -0,0 +1,171 @@
+package com.khmer9.lotto.base
+
+import android.animation.ValueAnimator
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import android.widget.Toast
+import androidx.annotation.LayoutRes
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.Guideline
+import androidx.fragment.app.Fragment
+import com.mazenrashed.printooth.Printooth
+import com.mazenrashed.printooth.data.printable.Printable
+import com.mazenrashed.printooth.data.printable.TextPrintable
+import com.mazenrashed.printooth.data.printer.DefaultPrinter
+import com.mazenrashed.printooth.utilities.Printing
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.remote.LottoSet
+import java.text.DecimalFormat
+import java.text.SimpleDateFormat
+import java.util.*
+
+abstract class BaseFragment(
+    @LayoutRes private val layoutRes: Int
+) : Fragment() {
+    private var printing : Printing? = null
+
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        if (Printooth.hasPairedPrinter()) printing = Printooth.printer()
+    }
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(layoutRes, container, false)
+    }
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        val guideLeft = view.findViewById<Guideline>(R.id.left_guideline)
+        val guideRight = view.findViewById<Guideline>(R.id.right_guideline)
+        val leftParams = guideLeft.layoutParams as ConstraintLayout.LayoutParams
+        leftParams.guidePercent = App.guidelineLeft
+        val rightParams = guideRight.layoutParams as ConstraintLayout.LayoutParams
+        rightParams.guidePercent = App.guidelineRight
+        guideRight.layoutParams = rightParams
+    }
+    fun currencyFormat(amount: Int): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+    @SuppressLint("SimpleDateFormat")
+    open fun formatShowDate(showDate: Date): String {
+        val formatter = SimpleDateFormat(("dd/MM/yyyy HH:mm:ss"))
+        return formatter.format(showDate)
+    }
+
+    fun findLottoSet(lottoSet: List<LottoSet>, type_of_betting: String): LottoSet {
+
+        return lottoSet.find { type_of_betting == it.typeOfBetting }!!
+    }
+    fun animateTextView(initialValue: Int, finalValue: Int, textview: TextView) : ValueAnimator {
+        val valueAnimator = ValueAnimator.ofInt(initialValue, finalValue)
+        valueAnimator.duration = 50
+        valueAnimator.addUpdateListener { animator ->
+            textview.text = animator.animatedValue.toString()
+        }
+        valueAnimator.start()
+
+        return valueAnimator
+
+
+    }
+    fun printSomePrintable(userName: String, ticketID: String, gameID: String, betDate: String, betType: String, betCast: String, winLose: String)  {
+        if (Printooth.hasPairedPrinter() && printing == null)printing = Printooth.printer()
+        if (printing == null) {
+            Toast.makeText(requireContext(),"No printing paired", Toast.LENGTH_SHORT).show()
+        } else{
+            val printables = getSomePrintables(userName, ticketID, gameID, betDate, betType, betCast, winLose)
+            printing?.print(printables)
+        }
+    }
+
+
+    private fun getSomePrintables(userName: String, ticketID: String, gameID: String, betDate: String, betType: String, betCast: String, winLose: String) = ArrayList<Printable>().apply {
+
+        add(
+            TextPrintable.Builder()
+                .setText(userName)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build())
+
+        add(
+            TextPrintable.Builder()
+                .setText("----------------")
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC1252)
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("Ticket ID:   $ticketID")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("Game ID  :   $gameID")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("Date     :   $betDate")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("Bet Type :   $betType")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("Bet Point:   $betCast")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("Win/Lose :   $winLose")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("----------------")
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
+                .build())
+        add(
+            TextPrintable.Builder()
+                .setText("www.mohasombath.com")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC437)
+                .setNewLinesAfter(1)
+                .build())
+
+    }
+}

+ 16 - 0
app/src/main/java/com/khmer9/lotto/base/BaseViewModel.kt

@@ -0,0 +1,16 @@
+package com.khmer9.lotto.base
+
+import androidx.lifecycle.ViewModel
+import io.reactivex.disposables.CompositeDisposable
+
+
+abstract class BaseViewModel : ViewModel() {
+
+    protected val disposables = CompositeDisposable()
+
+    override fun onCleared() {
+        disposables.clear()
+        super.onCleared()
+    }
+
+}

+ 209 - 0
app/src/main/java/com/khmer9/lotto/extension/ViewExtensions.kt

@@ -0,0 +1,209 @@
+package com.khmer9.lotto.extension
+
+import android.graphics.drawable.AnimationDrawable
+import android.os.Handler
+import android.view.View
+import android.view.animation.AlphaAnimation
+import android.view.animation.Animation
+import android.view.animation.LinearInterpolator
+import android.view.animation.OvershootInterpolator
+import com.khmer9.lotto.util.SafeClickListener
+import io.reactivex.Completable
+import java.util.*
+
+fun View.showIf(show: Boolean) {
+    if (show) {
+        show()
+    } else {
+        hide()
+    }
+}
+
+fun View.show() {
+    this.visibility = View.VISIBLE
+}
+
+fun View.hide() {
+    this.visibility = View.INVISIBLE
+}
+
+fun View.slideIn(offset: Float): Completable {
+    return Completable.create {
+        visibility = View.VISIBLE
+        alpha = 0f
+        scaleX = 0f
+        scaleY = 0f
+        translationY = offset
+        animate().alpha(1f)
+            .translationY(0f)
+            .scaleX(1f)
+            .scaleY(1f)
+            .setDuration(200)
+            .setInterpolator(OvershootInterpolator())
+            .withEndAction(it::onComplete)
+    }
+}
+
+fun View.slideOut(offset: Float): Completable {
+    return Completable.create {
+        animate().alpha(0f)
+            .scaleX(0f)
+            .scaleY(0f)
+            .translationY(offset)
+            .setDuration(200)
+            .withEndAction {
+                visibility = View.INVISIBLE
+                it.onComplete()
+            }
+    }
+}
+
+fun View.fadeOut(duration: Long = 30): Completable {
+    return Completable.create {
+        animate().setDuration(duration)
+            .alpha(0f)
+            .withEndAction {
+                visibility = View.GONE
+                it.onComplete()
+            }
+    }
+}
+
+fun View.fadeIn(): Completable {
+    return Completable.create {
+        //visibility = View.VISIBLE
+        alpha = 0f
+        animate().alpha(1f)
+            .setDuration(200)
+            .withEndAction(it::onComplete)
+    }
+}
+
+fun View.rotate(degree: Float): Completable {
+    return Completable.create {
+        rotation=degree
+        animate().rotation(0f)
+            .setDuration(200)
+            .withEndAction(it::onComplete)
+    }
+}
+
+fun View.blink(degree: Float): Completable {
+    return Completable.create {
+        rotation=degree
+        animate().rotation(0f)
+            .setDuration(200)
+            .withEndAction(it::onComplete)
+    }
+}
+fun View.blink(
+    times: Int = Animation.INFINITE,
+    duration: Long = 150L,
+    offset: Long = 20L,
+    minAlpha: Float = 0.0f,
+    maxAlpha: Float = 1.0f,
+    repeatMode: Int = Animation.REVERSE
+) {
+    startAnimation(AlphaAnimation(minAlpha, maxAlpha).also {
+        it.duration = duration
+        it.startOffset = offset
+        it.repeatMode = repeatMode
+        it.repeatCount = times
+    })
+
+
+}
+
+
+fun View.zoomIn(): Completable {
+    return Completable.create {
+        //alpha = 0f
+        //pivotX = 0.5f
+       // pivotY = 0.5f
+        scaleX = 4f
+        scaleY = 4f
+        //translationY = 0f
+        //translationX = 0f
+        animate().alpha(1f)
+            //.translationY(0f)
+            //.translationX(0f)
+            .scaleX(1f)
+            .scaleY(1f)
+            .setDuration(200)
+            .setInterpolator(LinearInterpolator())
+            .withEndAction(it::onComplete)
+    }
+}
+fun View.waitingLotto(): Completable {
+    return Completable.create {
+//        alpha = 0f
+//        scaleX = 0.5f
+//        scaleY = 0f
+//        translationY = 0f
+//        translationX = 20f
+//        animate().alpha(1f)
+//            .translationY(0f)
+//            .translationX(0f)
+//            .scaleX(1f)
+//            .scaleY(1f)
+//            .setDuration(200)
+//            .setInterpolator(OvershootInterpolator())
+//            .withEndAction(it::onComplete)
+        alpha = 0f
+        animate().alpha(1f)
+            .setDuration(50)
+            .withEndAction(it::onComplete)
+    }
+}
+fun View.btnClick(): Completable {
+    return Completable.create {
+        //visibility = View.VISIBLE
+        alpha = 0f
+        animate().alpha(1f)
+            .setDuration(30)
+            .withEndAction(it::onComplete)
+    }
+}
+fun View.resultBlink(): Completable {
+    return Completable.create {
+        //visibility = View.VISIBLE
+        alpha = 0f
+        animate().alpha(1f)
+            .setDuration(200)
+            .withEndAction(it::onComplete)
+    }
+}
+fun View.randomResult(): Completable {
+    return Completable.create {
+        //visibility = View.VISIBLE
+        alpha = 0f
+        animate().alpha(1f)
+//            .also {
+//                val rdns = (1..80).random()
+//                tvNumber.text= "$rdns"
+//            }
+            .setDuration(5)
+            .withEndAction(it::onComplete)
+    }
+}
+fun AnimationDrawable.onAnimationFinished(block: () -> Unit) {
+    var duration: Long = 0
+    for (i in 0..numberOfFrames) {
+        duration += getDuration(i)
+    }
+    Handler().postDelayed({
+        block()
+    }, duration*5)
+}
+fun IntRange.random() = Random().nextInt((endInclusive + 1) - start) + start
+
+fun View.setSafeOnClickListener(onSafeClick: (View) -> Unit) {
+    val safeClickListener = SafeClickListener {
+        onSafeClick(it)
+    }
+    setOnClickListener(safeClickListener)
+}
+
+fun <T> MutableList<T>.prepend(element: T) {
+    add(0, element)
+}

+ 95 - 0
app/src/main/java/com/khmer9/lotto/remote/LoginDataModel.kt

@@ -0,0 +1,95 @@
+package com.khmer9.lotto.remote
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+class LoginRequest(
+    @Json(name = "user_name")
+    val username: String,
+    @Json(name = "password")
+    val password: String
+)
+@JsonClass(generateAdapter = true)
+data class LoginResponse(
+
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: LoginData?
+)
+
+@JsonClass(generateAdapter = true)
+data class LoginMessage(
+    @Json(name="code")
+    val code: String,
+
+    @Json(name="descriptions")
+    val description: String,
+)
+
+@JsonClass(generateAdapter = true)
+data class LoginData(
+
+    @Json(name="user")
+    val user: User?,
+
+    @Json(name="token")
+    val token: String?,
+
+    @Json(name = "lotoSetResult")
+    val lottoSet: List<LottoSet>?,
+
+    @Json(name="limit")
+    val limit: Limit?,
+
+
+    )
+@JsonClass(generateAdapter = true)
+data class Limit(
+    @Json(name="amount_min")
+    val amountMin: Int,
+
+    @Json(name="amount_max")
+    val amountMax: Int,
+)
+
+@JsonClass(generateAdapter = true)
+data class LottoSet(
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "type_of_betting")
+    val typeOfBetting: String,
+
+    @Json(name = "start_number")
+    val startNumber: Int,
+
+    @Json(name = "end_number")
+    val endNumber: Int,
+
+    @Json(name = "payment")
+    val payment: Double,
+
+    @Json(name = "category")
+    val category: String,
+
+    @Json(name = "type")
+    val type: String
+
+)
+
+@JsonClass(generateAdapter = true)
+data class User(
+    @Json(name = "_id")
+    var  id : String,
+    @Json(name = "user_name")
+    val  userName: String,
+    @Json(name = "account_balances")
+    val accountBalances: Double,
+    @Json(name = "roles")
+    val roles:String
+)
+

+ 119 - 0
app/src/main/java/com/khmer9/lotto/remote/MainDataModel.kt

@@ -0,0 +1,119 @@
+package com.khmer9.lotto.remote
+
+import com.gdtlib.lib.adapter.BaseListItem
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class MainResponse(
+
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: MainMessage,
+    @Json(name = "data")
+    val data: MainData?
+)
+
+@JsonClass(generateAdapter = true)
+data class MainMessage(
+    @Json(name = "code")
+    val code: String,
+
+    @Json(name = "descriptions")
+    val description: String
+
+)
+
+@JsonClass(generateAdapter = true)
+data class MainData(
+
+    @Json(name="accountBalances")
+    val accountBalance: String,
+
+    @Json(name = "newResult")
+    val nextNo: String?,
+
+    @Json(name = "currentResult")
+    val result: Result?,
+
+    @Json(name = "currentBetting")
+    val myBetting: MyBetting?
+    )
+
+@JsonClass(generateAdapter = true)
+data class MyBetting(
+    @Json(name = "_id")
+    var id: String?,
+
+    @Json(name = "data")
+    val data: List<ListItem>?
+)
+
+@JsonClass(generateAdapter = true)
+data class ListItem(
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "set_result_id")
+    var setId: String,
+
+    @Json(name = "type_of_betting")
+    val typeOfBetting: String,
+
+    @Json(name = "category")
+    val category: String,
+
+    @Json(name = "user_id")
+    val user_id: String,
+
+    @Json(name = "date")
+    val date: String,
+
+    @Json(name = "amount")
+    val amount: String,
+
+    @Json(name = "cast")
+    val cast: String,
+
+    @Json(name = "win_lose")
+    val win_lose: String?,
+
+    @Json(name = "amount_win")
+    val amount_win: String?
+): BaseListItem(){
+    override fun getUnique(): String = id
+
+}
+
+@JsonClass(generateAdapter = true)
+data class Result(
+
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "no")
+    var no: String,
+
+    @Json(name = "total_ramdom")
+    var totalValue: String,
+
+    @Json(name = "set_result_id")
+    var smallBigSetId: String,
+
+    @Json(name = "type_of_betting")
+    val resultSmallOrBig: String,
+
+    @Json(name = "category")
+    var categorySmallOrBig: String,
+
+    @Json(name = "set_result_id_range")
+    var rangeSetId: String,
+
+    @Json(name = "type_of_betting_range")
+    val resultRange: String,
+
+    @Json(name = "category_range")
+    var categoryRange: String
+)
+

+ 93 - 0
app/src/main/java/com/khmer9/lotto/remote/PlayDataModel.kt

@@ -0,0 +1,93 @@
+package com.khmer9.lotto.remote
+
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+
+@JsonClass(generateAdapter = true)
+class PlayRequest(
+    @Json(name = "set_result_id")
+    val setID: String,
+
+    @Json(name = "user_id")
+    val userId: String,
+
+    @Json(name = "no")
+    val no: String,
+
+//    @Json(name = "date")
+//    val date: String,
+
+    @Json(name = "cast")
+    val cast: Double,
+
+    @Json(name = "amount")
+    val amount: Int
+)
+@JsonClass(generateAdapter = true)
+data class PlayResponse(
+
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: PlayMessage,
+    @Json(name = "data")
+    val data: PlayData?
+)
+@JsonClass(generateAdapter = true)
+data class PlayMessage(
+    @Json(name="code")
+    val code: String,
+
+    @Json(name="descriptions")
+    val description: String,
+)
+@JsonClass(generateAdapter = true)
+data class PlayData(
+
+    @Json(name = "objCurrentBetting")
+    val myBetting: CurrentBetting?,
+
+    @Json(name = "accountBalances")
+    val accountBalance: String?,
+)
+
+@JsonClass(generateAdapter = true)
+data class CurrentBetting(
+
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "no")
+    var no: String,
+
+    @Json(name = "set_result_id")
+    var setId: String,
+
+    @Json(name = "type_of_betting")
+    val typeOfBetting: String,
+
+    @Json(name = "category")
+    val category: String,
+
+    @Json(name = "user_id")
+    val userId: String,
+
+    @Json(name = "date")
+    val date: String,
+
+    @Json(name = "amount")
+    val amount: String,
+
+    @Json(name = "cast")
+    val cast: String,
+
+    @Json(name = "win_lose")
+    val win_lose: String?,
+
+    @Json(name = "amount_win")
+    val amount_win: String?
+
+)
+

+ 153 - 0
app/src/main/java/com/khmer9/lotto/remote/ReportDataModel.kt

@@ -0,0 +1,153 @@
+package com.khmer9.lotto.remote
+
+import com.gdtlib.lib.adapter.BaseListItem
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class ReportResponse(
+
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: ReportMessage,
+    @Json(name = "data")
+    val data: ReportData?
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportMessage(
+    @Json(name = "code")
+    val code: String,
+
+    @Json(name = "descriptions")
+    val description: String)
+
+@JsonClass(generateAdapter = true)
+data class ReportData(
+
+    @Json(name = "objLotoBettingWin")
+    val winList: List<Win>?,
+
+    @Json(name = "objLotoBettingWinLose")
+    val winLostLst: List<WinLost>?,
+
+    @Json(name = "objGroupStatement")
+    val statementList: List<Statement>?
+
+)
+
+@JsonClass(generateAdapter = true)
+data class Win(
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "date")
+    val date: String,
+
+    @Json(name = "filter_date")
+    var filterDate: String,
+
+    @Json(name = "no")
+    val no: String,
+
+    @Json(name = "user_name")
+    val userName: String,
+
+    @Json(name = "bank_account")
+    val bankAccount: String,
+
+    @Json(name = "total_ramdom")
+    val totalRandom: String,
+
+    @Json(name = "type_of_betting")
+    val typeOfBetting: String,
+
+    @Json(name = "color")
+    val color: String,
+
+    @Json(name = "amount")
+    val amount: String,
+
+    @Json(name = "cast")
+    val cast: String,
+
+    @Json(name = "win_lose")
+    val win_lose: String?,
+
+    @Json(name = "amount_win")
+    val amount_win: String?
+): BaseListItem(){
+    override fun getUnique(): String = id
+
+}
+@JsonClass(generateAdapter = true)
+data class WinLost(
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "date")
+    val date: String,
+
+    @Json(name = "filter_date")
+    var filterDate: String,
+
+    @Json(name = "no")
+    val no: String,
+
+    @Json(name = "user_name")
+    val userName: String,
+
+    @Json(name = "bank_account")
+    val bankAccount: String,
+
+    @Json(name = "total_ramdom")
+    val totalRandom: String,
+
+    @Json(name = "type_of_betting")
+    val typeOfBetting: String,
+
+    @Json(name = "color")
+    val color: String,
+
+    @Json(name = "amount")
+    val amount: String,
+
+    @Json(name = "cast")
+    val cast: String,
+
+    @Json(name = "win_lose")
+    val win_lose: String?,
+
+    @Json(name = "amount_win")
+    val amount_win: String?
+): BaseListItem(){
+    override fun getUnique(): String = id
+
+}
+
+@JsonClass(generateAdapter = true)
+data class Statement(
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "date")
+    val date: String,
+
+    @Json(name = "note")
+    val note: String,
+
+    @Json(name = "note_khmer")
+    val khmerNote: String?,
+
+    @Json(name = "amount")
+    val amount: Double?,
+
+    @Json(name = "amount_win")
+    val amount_win: Double?
+
+    ): BaseListItem(){
+    override fun getUnique(): String = id
+
+}
+

+ 57 - 0
app/src/main/java/com/khmer9/lotto/remote/ResultDataModel.kt

@@ -0,0 +1,57 @@
+package com.khmer9.lotto.remote
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class ResultResponse(
+
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: ResultMessage,
+    @Json(name = "data")
+    val data: ResultData?
+)
+
+@JsonClass(generateAdapter = true)
+data class ResultMessage(
+    @Json(name = "code")
+    val code: String,
+
+    @Json(name = "descriptions")
+    val description: String)
+
+@JsonClass(generateAdapter = true)
+data class ResultData(
+    @Json(name = "object")
+    val resultList: List<ResultLotto>?
+)
+
+@JsonClass(generateAdapter = true)
+data class ResultLotto(
+
+    @Json(name = "_id")
+    var id: String,
+
+    @Json(name = "no")
+    var no: String,
+
+
+    @Json(name = "set_result_id")
+    var smallBigSetId: String,
+
+    @Json(name = "type_of_betting")
+    val resultSmallOrBig: String,
+
+    @Json(name = "category")
+    var categorySmallOrBig: String,
+
+    @Json(name = "set_result_id_range")
+    var rangeSetId: String,
+
+    @Json(name = "type_of_betting_range")
+    val resultRange: String,
+
+    @Json(name = "category_range")
+    var categoryRange: String
+)

+ 18 - 0
app/src/main/java/com/khmer9/lotto/remote/SocketMessageDataModel.kt

@@ -0,0 +1,18 @@
+package com.khmer9.lotto.remote
+
+import org.json.JSONArray
+
+
+data class SocketMessageDataModel(
+    val type: String,
+    val countDown: Int?= null,
+    val resultArray: JSONArray? = null,
+    val totalValue: Int?= null,
+    val isBonus: Boolean?= false,
+    val bonusNumber : Int?= null,
+    val bonusValue : Int?= null
+
+){
+    fun isCountDowning() = countDown != null && resultArray == null
+
+}

+ 30 - 0
app/src/main/java/com/khmer9/lotto/remote/UpdatePwdDataModel.kt

@@ -0,0 +1,30 @@
+package com.khmer9.lotto.remote
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+class UpdatePwdRequest(
+    @Json(name = "user_name")
+    val username: String,
+    @Json(name = "password")
+    val password: String
+)
+@JsonClass(generateAdapter = true)
+data class UpdatePwdResponse(
+
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+
+)
+@JsonClass(generateAdapter = true)
+data class UpdatePwdMessage(
+    @Json(name="code")
+    val code: String,
+
+    @Json(name="descriptions")
+    val description: String,
+)
+

+ 30 - 0
app/src/main/java/com/khmer9/lotto/remote/service/ApiService.kt

@@ -0,0 +1,30 @@
+package com.khmer9.lotto.remote.service
+
+import com.khmer9.lotto.remote.*
+import io.reactivex.Single
+import retrofit2.http.*
+
+interface ApiService {
+
+
+    @POST("/v2/mobile/login")
+    @Headers("No-Authentication: true")
+    fun login(@Body loginRequest: LoginRequest): Single<LoginResponse>
+
+    @GET("/v2/mobile/getMasterDataLoto/{userId}")
+    fun remoteMainScreen(@Path(value = "userId") userId: String?): Single<MainResponse>
+
+    @POST("/v2/mobile/createBetting")
+    fun createBetting(@Body request: PlayRequest): Single<PlayResponse>
+
+    @GET("/v2/mobile/getList17LotoRamdomResult")
+    fun remoteResultScreen(): Single<ResultResponse>
+
+    @GET("/v2/mobile/getStatement/{userId}")
+    fun remoteReportScreen(@Path(value = "userId") userId: String?): Single<ReportResponse>
+
+    @FormUrlEncoded
+    @PUT("/v2/mobile/changePassword/{userId}")
+    fun updatePassword(@Path(value = "userId") userId: String?, @Field(value="user_name") userName: String, @Field(value="password") password: String): Single<UpdatePwdResponse>
+
+}

+ 19 - 0
app/src/main/java/com/khmer9/lotto/remote/service/ConnectivityStates.java

@@ -0,0 +1,19 @@
+package com.khmer9.lotto.remote.service;
+
+public class ConnectivityStates {
+
+    private ConnectivityStates() {
+        // non-instantiable class
+    }
+
+    public static final int STATE_NOT_CONNECTED = 0 ;
+
+    public static final int STATE_RECONNECTING = 1 ;
+
+    public static final int STATE_CONNECTED = 2 ;
+
+    public static final int STATE_DISCONNECTED = 3 ;
+
+    public static final int STATE_TIMEOUT = 4 ;
+
+}

+ 23 - 0
app/src/main/java/com/khmer9/lotto/remote/service/EventListener.java

@@ -0,0 +1,23 @@
+package com.khmer9.lotto.remote.service;
+
+import com.khmer9.lotto.remote.SocketMessageDataModel;
+
+import org.json.JSONObject;
+
+public interface EventListener {
+
+    void onConnect();
+
+    void onConnectionError() ;
+
+    void onReconnect();
+
+    void onReconnectionTimeout();
+
+    void onDisconnect();
+
+    void onNewLottoMessage(SocketMessageDataModel message);
+
+    void onNewCreatedBettingMessage(JSONObject createdBettingJsonObject);
+
+}

+ 155 - 0
app/src/main/java/com/khmer9/lotto/remote/service/SocketService.java

@@ -0,0 +1,155 @@
+package com.khmer9.lotto.remote.service;
+
+import android.util.Log;
+
+import com.github.nkzawa.emitter.Emitter;
+import com.github.nkzawa.socketio.client.IO;
+import com.github.nkzawa.socketio.client.Socket;
+import com.khmer9.lotto.remote.SocketMessageDataModel;
+import com.khmer9.lotto.util.BaseObservable;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URISyntaxException;
+
+import com.khmer9.lotto.config.Config;
+
+public class SocketService extends BaseObservable<EventListener> {
+
+    private static final String TAG = "Socket";
+
+    private static final String SOCKET_URL = Config.SOCKET_URL;
+    private static final String EVENT_CONNECT = Socket.EVENT_CONNECT;
+    private static final String EVENT_RECONNECT = Socket.EVENT_RECONNECT;
+    private static final String EVENT_CONNECT_ERROR = Socket.EVENT_CONNECT_ERROR;
+    private static final String EVENT_DISCONNECT = Socket.EVENT_DISCONNECT;
+    private static final String EVENT_CONNECT_TIMEOUT = Socket.EVENT_CONNECT_TIMEOUT;
+    private static final String EVENT_NEW_LOTTO_MESSAGE = "start-count-down-loto";
+    private static final String EVENT_NEW_CREATE_BETTING_MESSAGE = "created-betting-by-user";
+
+
+    private Socket socket ;
+    private JSONObject joinBettingObject ;
+
+    private Emitter.Listener connectListener = args -> {
+        //Log.d(TAG,"onConnect s...");
+        socket.emit("join", joinBettingObject);
+        for(EventListener listener: getListeners())
+            listener.onConnect();
+    };
+
+    public void startEmitCreateBetting(JSONObject joinObject){
+        socket.emit("betting-loto",joinObject);
+    }
+
+    private Emitter.Listener reconnectListener = args -> {
+        //Log.d(TAG,"onReconnect s...");
+        for(EventListener listener: getListeners())
+            listener.onReconnect();
+    };
+
+    private Emitter.Listener connectTimeoutListener = args -> {
+        //Log.d(TAG,"onConnectTimeout s...");
+        for(EventListener listener: getListeners())
+            listener.onReconnectionTimeout();
+    };
+
+    private Emitter.Listener connectionErrorListener = args -> {
+        //Log.d(TAG,"onConnectionError s...");
+        for(EventListener listener: getListeners())
+            listener.onConnectionError();
+    };
+
+    private Emitter.Listener disconnectListener = args -> {
+        //Log.d(TAG,"onDisconnect s...");
+        socket.off();
+        for(EventListener listener: getListeners()){
+            listener.onDisconnect();
+
+        }
+
+    };
+
+    //    {"countDown":[12,34,11,69],
+//        "type":"random",
+//        "object":{"objRandom":
+//                            {"total":806,
+//                            "numbers":[12,34,11,69,59,74,30,9,38,65,52,29,8,14,68,55,31,10,60,78]
+//                            }
+//                }
+//    }
+    // {"countDown":129,"type":"count"}
+
+    private Emitter.Listener newOtherCreatedBettingMessageListener = args -> {
+        final String rawMessage = args[0].toString() ;
+        //Log.d(TAG,"onCreateMessage: "+rawMessage);
+        try {
+            JSONObject rawMessageObject = new JSONObject(rawMessage);
+            //String userID = rawMessageObject.getString("user_id");
+            for (EventListener listener : getListeners())
+                listener.onNewCreatedBettingMessage(rawMessageObject);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    };
+
+    private Emitter.Listener newLottoMessageListener = args -> {
+        final String rawMessage = args[0].toString() ;
+        //Log.d(TAG,"onNewLottoMessage: "+rawMessage);
+        try {
+            SocketMessageDataModel lottoMessage;
+            JSONObject rawMessageObject = new JSONObject(rawMessage);
+            final String type = rawMessageObject.getString("type");
+            if (type.equals("count")){
+                lottoMessage = new SocketMessageDataModel(type,rawMessageObject.getInt("countDown"),null, null,false, null, null);
+
+            }else {//type =random
+                JSONObject objectTotal = rawMessageObject.getJSONObject("object");
+                int totalVale = objectTotal.getInt("objRandom");
+                JSONObject objectBonus = objectTotal.getJSONObject("bornus");
+                boolean isBonus = objectBonus.getBoolean("bornusStatus");
+                int bonusNumer = objectBonus.getInt("bornus");
+                int bonusValue = objectBonus.getInt("paymentBornus");
+                lottoMessage = new SocketMessageDataModel(type,null,rawMessageObject.getJSONArray("countDown"), totalVale, isBonus, bonusNumer, bonusValue);
+            }
+            // final long timeStamp = System.currentTimeMillis();
+            for (EventListener listener : getListeners())
+                listener.onNewLottoMessage(lottoMessage);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    };
+
+    public void startListening(JSONObject joinBettingObject) throws URISyntaxException {
+        this.joinBettingObject = joinBettingObject;
+
+        if(socket==null)
+            socket = IO.socket(SOCKET_URL) ;
+
+        socket.on(EVENT_CONNECT, connectListener);
+        socket.on(EVENT_CONNECT_TIMEOUT,connectTimeoutListener);
+        socket.on(EVENT_DISCONNECT, disconnectListener);
+        socket.on(EVENT_NEW_LOTTO_MESSAGE, newLottoMessageListener);
+        socket.on(EVENT_NEW_CREATE_BETTING_MESSAGE, newOtherCreatedBettingMessageListener);
+        socket.on(EVENT_RECONNECT,reconnectListener);
+        socket.on(EVENT_CONNECT_ERROR,connectionErrorListener);
+
+        socket.connect();
+    }
+
+    public void stopListening() {
+        if (socket != null)
+            socket.disconnect();
+    }
+
+//    public Single<ChatMessage> sendMessage(ChatMessage chatMessage) {
+//        return Single.create(singleEmitter -> {
+//            if (socket == null)
+//                singleEmitter.onError(new NullSocketException());
+//            socket.emit(EVENT_NEW_MESSAGE, chatMessage.getMessageText());
+//            chatMessage.setSent(true);
+//            singleEmitter.onSuccess(chatMessage);
+//        });
+//    }
+}

+ 86 - 0
app/src/main/java/com/khmer9/lotto/screen/login/LoginActivity.kt

@@ -0,0 +1,86 @@
+package com.khmer9.lotto.screen.login
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.Observer
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.app.ShareActivity
+import com.khmer9.lotto.remote.User
+import com.khmer9.lotto.util.Const
+import com.khmer9.lotto.util.ModelPreferencesManager
+import kotlinx.android.synthetic.main.activity_login.*
+
+class LoginActivity : AppCompatActivity() {
+    //private val loginViewModel = App.injectLoginViewModel()
+    private lateinit var loginViewModel: LoginViewModel
+    private var user: User?=null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        loginViewModel = LoginViewModel(App.injectApiService(), App.injectPrefHelper())
+
+        super.onCreate(savedInstanceState)
+
+        setContentView(R.layout.activity_login)
+        user = ModelPreferencesManager.get<User>(Const.USER_KEY)
+        if (user != null) et_username.setText(user?.userName)
+
+        //et_username.setText("AAVVAAAG002")
+        //et_username.setText("AAVVAAAH007")
+        //et_password.setText("1234567")
+
+        loginViewModel.state.observe(this, Observer(this::render))
+
+
+        btn_login.setOnClickListener {
+            til_username.isErrorEnabled = false
+            til_username.error = null
+            til_password.isErrorEnabled = false
+            til_password.error= null
+            val username = et_username.text
+            val password = et_password.text
+            if (username.isNullOrEmpty()){
+                til_username.error = getString(R.string.err_not_empty)
+                til_username.requestFocus()
+                return@setOnClickListener
+            }
+            if (password.isNullOrEmpty()){
+                til_password.error = getString(R.string.err_not_empty)
+                til_password.requestFocus()
+                return@setOnClickListener
+            }
+            loginViewModel.login(username.toString(),password.toString())
+
+        }
+
+    }
+    private fun render(state: LoginViewState) {
+
+        if (state.isProgress){
+            //Toast.makeText(this@LoginActivity, "Loading", Toast.LENGTH_LONG).show()
+            tv_error.text = ""
+
+        }
+        if (state.isLoginSuccess){
+            //Toast.makeText(this@LoginActivity, "ចូលប្រព័ន្ធជោគជ័យ", Toast.LENGTH_LONG).show()
+            val intent = Intent(this, ShareActivity::class.java)
+            startActivity(intent)
+            finishAffinity()
+
+        }
+        if (state.error != null){
+            //Toast.makeText(this@LoginActivity, "Error", Toast.LENGTH_LONG).show()
+            tv_error.text = state.error
+
+        }
+
+    }
+
+    override fun onDestroy() {
+       // loginViewModel.state.removeObservers(this)
+        super.onDestroy()
+        //Toast.makeText(this@LoginActivity, "On Destroy Login", Toast.LENGTH_LONG).show()
+
+    }
+}

+ 75 - 0
app/src/main/java/com/khmer9/lotto/screen/login/LoginViewModel.kt

@@ -0,0 +1,75 @@
+package com.khmer9.lotto.screen.login
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.khmer9.lotto.app.getErrorCode
+import com.khmer9.lotto.base.BaseViewModel
+import com.khmer9.lotto.remote.service.ApiService
+import com.khmer9.lotto.remote.LoginRequest
+import com.khmer9.lotto.util.Const
+import com.khmer9.lotto.util.ModelPreferencesManager
+import com.khmer9.lotto.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class LoginViewModel(val apiService: ApiService, val prefHelper: PrefHelper) : BaseViewModel(){
+
+
+    private val _state = MutableLiveData<LoginViewState>(LoginViewState())
+    val state: LiveData<LoginViewState> = _state
+
+    fun login(username: String, password: String) {
+        if (_state.value!!.isProgress) return
+        val request = LoginRequest(username,password)
+        _state.value = prev().copy(isProgress = true)
+
+        disposables.add(
+            apiService.login(request)
+                .timeout(60,TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                if (it.resultCode == "1") {
+                    if (it.data?.user?.roles == Const.USER_ROLE){
+                        _state.value = prev().copy(isProgress = false, isLoginSuccess = true)
+                        prefHelper.setUserToken(it.data.token ?: "")
+                        ModelPreferencesManager.put(it.data.user,Const.USER_KEY)
+                        it.data.limit?.let { limit ->
+                            prefHelper.setMinBetting(limit.amountMin)
+                            prefHelper.setMaxBetting(limit.amountMax)
+                        }
+                        it.data.lottoSet?.let { lottoList -> ModelPreferencesManager.putList(lottoList, Const.LOTTO_KEY) }
+                    }else{
+                        _state.value = prev().copy(isProgress = false, error = "Sorry, you are not allow to play!")
+                    }
+
+                } else {
+                    _state.value = prev().copy(isProgress = false, error = "[${it.message.description}]")
+                }
+            }, {
+                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
+//                    if (it is AppException && it.isEmpty) {
+//                        _state.value =
+//                            _state.value?.copy(isProgress = false, data = empty(), isEmpty = true)
+//                    } else {
+//                        val message: String =
+//                            if (it is AppException)
+//                                "មិនអាចទាញយកទិន្នន័យបាន\nError[${it.message}]"
+//                            else if (it is ConnectException || it is HttpException)
+//                                "មិនអាចភ្ជាប់ទៅប្រព័ន្ធបាន\nError[Client Connection]"
+//                            else if (it is TimeoutException)
+//                                "មិនអាចភ្ជាប់ទៅប្រព័ន្ធបាន\nError[Timeout]"
+//                            else
+//                                "មិនអាចភ្ជាប់ទៅប្រព័ន្ធបាន\nError[Client]"
+//                        _state.value =
+//                            _state.value?.copy(isProgress = false, error = message, data = null)
+//                    }
+                _state.value = prev().copy(isProgress = false, error = message)
+            })
+        )
+    }
+
+    private fun prev() = _state.value!!
+
+
+}

+ 9 - 0
app/src/main/java/com/khmer9/lotto/screen/login/LoginViewState.kt

@@ -0,0 +1,9 @@
+package com.khmer9.lotto.screen.login
+
+data class LoginViewState(
+    val initial: Boolean = false,
+    val isProgress: Boolean = false,
+    val isLoginSuccess: Boolean = false,
+
+    val error: String? = null
+)

+ 21 - 0
app/src/main/java/com/khmer9/lotto/screen/main/MainAdapter.kt

@@ -0,0 +1,21 @@
+package com.khmer9.lotto.screen.main
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.khmer9.lotto.R
+
+class MainAdapter(private val myBettingId: String): BaseListAdapter() {
+    var printButtonListener: ((String, String, String, String, String, String) -> Unit) ?= null
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
+        MainListViewHolder(
+            LayoutInflater.from(parent.context).inflate(
+                R.layout.item_table_holder,
+                parent,
+                false
+            ),myBettingId, printButtonListener
+        )
+
+
+}

+ 936 - 0
app/src/main/java/com/khmer9/lotto/screen/main/MainFragment.kt

@@ -0,0 +1,936 @@
+package com.khmer9.lotto.screen.main
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.graphics.Color
+import android.graphics.drawable.AnimationDrawable
+import android.graphics.drawable.Drawable
+import android.media.MediaPlayer
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.view.animation.AlphaAnimation
+import android.view.animation.Animation
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import androidx.constraintlayout.widget.Group
+import androidx.core.animation.doOnEnd
+import androidx.core.content.ContextCompat
+import androidx.core.content.ContextCompat.getColor
+import androidx.core.view.isInvisible
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.gdtlib.lib.adapter.BaseListItem
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.app.ShareActivity
+import com.khmer9.lotto.app.ShareViewState
+import com.khmer9.lotto.base.BaseFragment
+import com.khmer9.lotto.extension.*
+import com.khmer9.lotto.remote.CurrentBetting
+import com.khmer9.lotto.remote.SocketMessageDataModel
+import com.khmer9.lotto.remote.User
+import com.khmer9.lotto.remote.service.ConnectivityStates
+import com.khmer9.lotto.screen.play.PlayFragment
+import com.khmer9.lotto.screen.report.StatementFragment
+import com.khmer9.lotto.screen.result.ResultFragment
+import com.khmer9.lotto.screen.setting.SettingFragment
+import com.khmer9.lotto.screen.splash.SplashScreenActivity
+import com.khmer9.lotto.util.Const
+import com.khmer9.lotto.util.ModelPreferencesManager
+import com.khmer9.lotto.view.LottoView
+import com.khmer9.lotto.view.ResultView
+import com.khmer9.lotto.view.SettingButtonView
+import io.reactivex.Completable
+import kotlinx.android.synthetic.main.fragment_main.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import nl.dionsegijn.konfetti.models.Shape
+import nl.dionsegijn.konfetti.models.Size
+import org.json.JSONException
+import org.json.JSONObject
+
+
+/**
+ * A simple [Fragment] subclass as the default destination in the navigation.
+ */
+class MainFragment : BaseFragment(R.layout.fragment_main) {
+    private val shareViewModel = App.injectShareViewModel()
+    private val sharePref = App.injectPrefHelper()
+
+    private lateinit var adapter: MainAdapter
+    private lateinit var lottoView1: LottoView
+    private lateinit var lottoView2: LottoView
+    private lateinit var lottoView3: LottoView
+    private lateinit var lottoView4: LottoView
+    private lateinit var lottoView5: LottoView
+    private lateinit var lottoView6: LottoView
+    private lateinit var lottoView7: LottoView
+    private lateinit var lottoView8: LottoView
+    private lateinit var lottoView9: LottoView
+    private lateinit var lottoView10: LottoView
+    private lateinit var lottoView11: LottoView
+    private lateinit var lottoView12: LottoView
+    private lateinit var lottoView13: LottoView
+    private lateinit var lottoView14: LottoView
+    private lateinit var lottoView15: LottoView
+    private lateinit var lottoView16: LottoView
+    private lateinit var lottoView17: LottoView
+    private lateinit var lottoView18: LottoView
+    private lateinit var lottoView19: LottoView
+    private lateinit var lottoView20: LottoView
+    private lateinit var lottoTv1: TextView
+    private lateinit var lottoTv2: TextView
+    private lateinit var lottoTv3: TextView
+    private lateinit var lottoTv4: TextView
+    private lateinit var lottoTv5: TextView
+    private lateinit var lottoTv6: TextView
+    private lateinit var lottoTv7: TextView
+    private lateinit var lottoTv8: TextView
+    private lateinit var lottoTv9: TextView
+    private lateinit var lottoTv10: TextView
+    private lateinit var lottoTv11: TextView
+    private lateinit var lottoTv12: TextView
+    private lateinit var lottoTv13: TextView
+    private lateinit var lottoTv14: TextView
+    private lateinit var lottoTv15: TextView
+    private lateinit var lottoTv16: TextView
+    private lateinit var lottoTv17: TextView
+    private lateinit var lottoTv18: TextView
+    private lateinit var lottoTv19: TextView
+    private lateinit var lottoTv20: TextView
+
+    private lateinit var tvResult: TextView
+    private lateinit var tvResultSmall: TextView
+    private lateinit var vBigSmal: ResultView
+    private lateinit var vRang: ResultView
+    private lateinit var ivBigLogo: ImageView
+    private lateinit var lottoGroup: Group
+    private lateinit var arrayLottoView: ArrayList<LottoView>
+    private lateinit var arrayLottoTextView: ArrayList<TextView>
+    private lateinit var user: User
+    private var resultLength: Int = 0
+    private var lottoAnimationDrawable: AnimationDrawable? = null
+    private lateinit var btnPlay: SettingButtonView
+    private lateinit var btnPlayFrame: View
+    private lateinit var betPlease: MediaPlayer
+    private lateinit var betTouch: MediaPlayer
+    private lateinit var countDown: MediaPlayer
+    private lateinit var countDown1: MediaPlayer
+    private lateinit var countDown2: MediaPlayer
+    private lateinit var countDown3: MediaPlayer
+    private lateinit var countDown4: MediaPlayer
+    private lateinit var countDown5: MediaPlayer
+    private lateinit var countDown6: MediaPlayer
+    private lateinit var countDown7: MediaPlayer
+    private lateinit var countDown8: MediaPlayer
+    private lateinit var countDown9: MediaPlayer
+    private lateinit var countDown10: MediaPlayer
+    private lateinit var congrat: MediaPlayer
+
+
+    private lateinit var goodLuck: MediaPlayer
+    lateinit var result: MediaPlayer
+    private var bgDefaultLotto: Drawable? = null
+    private var bgBlueLotto: Drawable? = null
+    private var bgGreenLotto: Drawable? = null
+    private var bgPinkLotto: Drawable? = null
+    private var bgYellowLotto: Drawable? = null
+    private var bgWhiteLotto: Drawable? = null
+
+    private var bgCircleBlue: Drawable? = null
+    private var bgCircleRed: Drawable? = null
+    private var bgCircleGreen: Drawable? = null
+    private var bgCircleYellow: Drawable? = null
+    private var bgCirclePink: Drawable? = null
+
+    private var textBig: Drawable? = null
+    private var textSmall: Drawable? = null
+    private var colorWhite: Int? = null
+    private var colorRed: Int? = null
+
+    private var anim: AlphaAnimation?= null
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        //companyInfoId =arguments?.getInt(COM_INTO_ID_KEY) ?: 0
+        (requireActivity() as ShareActivity).apply {
+            betPlease = MediaPlayer.create(this, R.raw.betplease)
+            betTouch = MediaPlayer.create(this, R.raw.bettouch)
+            countDown = MediaPlayer.create(this, R.raw.countdown)
+            goodLuck = MediaPlayer.create(this, R.raw.goodluck)
+            result = MediaPlayer.create(this, R.raw.result)
+            countDown1 = MediaPlayer.create(this, R.raw.countdown)
+            countDown2 = MediaPlayer.create(this, R.raw.countdown)
+            countDown3 = MediaPlayer.create(this, R.raw.countdown)
+            countDown4 = MediaPlayer.create(this, R.raw.countdown)
+            countDown5 = MediaPlayer.create(this, R.raw.countdown)
+            countDown6 = MediaPlayer.create(this, R.raw.countdown)
+            countDown7 = MediaPlayer.create(this, R.raw.countdown)
+            countDown8 = MediaPlayer.create(this, R.raw.countdown)
+            countDown9 = MediaPlayer.create(this, R.raw.countdown)
+            countDown10 = MediaPlayer.create(this, R.raw.countdown)
+            congrat = MediaPlayer.create(this, R.raw.cong)
+            user = userShare
+
+
+
+        }
+
+        bgDefaultLotto = ContextCompat.getDrawable(requireContext(), R.drawable.ic_logo)
+        bgBlueLotto = ContextCompat.getDrawable(requireContext(), R.drawable.ic_blue_circle)
+        bgPinkLotto = ContextCompat.getDrawable(requireContext(), R.drawable.ic_pink_circle)
+        bgYellowLotto = ContextCompat.getDrawable(requireContext(), R.drawable.ic_yellow_circle)
+        bgGreenLotto = ContextCompat.getDrawable(requireContext(), R.drawable.ic_green_circle)
+        bgWhiteLotto = ContextCompat.getDrawable(requireContext(), R.drawable.bg_circle_white)
+
+        bgCircleBlue = ContextCompat.getDrawable(requireContext(), R.drawable.bg_circle_blue_stroke)
+        bgCircleRed = ContextCompat.getDrawable(requireContext(), R.drawable.bg_circle_red_stroke)
+        bgCirclePink = ContextCompat.getDrawable(requireContext(), R.drawable.bg_circle_pink_stroke)
+        bgCircleYellow =
+            ContextCompat.getDrawable(requireContext(), R.drawable.bg_circle_yellow_stroke)
+        bgCircleGreen =
+            ContextCompat.getDrawable(requireContext(), R.drawable.bg_circle_green_stroke)
+
+        textBig = ContextCompat.getDrawable(requireContext(), R.drawable.text_main_big)
+        textSmall = ContextCompat.getDrawable(requireContext(), R.drawable.text_main_small)
+
+
+        colorWhite = getColor(requireContext(), R.color.color_white)
+        colorRed = getColor(requireContext(), R.color.color_red_600)
+
+        anim = AlphaAnimation(0.0f, 1.0f)
+        anim?.duration = 50 //You can manage the blinking time with this parameter
+        anim?.startOffset = 50
+        anim?.repeatMode = Animation.REVERSE
+        anim?.repeatCount = Animation.INFINITE
+    }
+
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        (requireActivity() as ShareActivity).apply {
+            userNameTextView.text = user.userName
+
+        }
+
+        shareViewModel.getConnectivityStates.observe(viewLifecycleOwner, Observer {
+            getSocketConectionStatus(it)
+        })
+        shareViewModel.getLottoMessage.observe(viewLifecycleOwner, Observer {
+            getLottoMessage(it)
+        })
+        shareViewModel.getBettingCreated.observe(viewLifecycleOwner, Observer {
+            getOtherCreatedBetting(it)
+        })
+
+        shareViewModel.getShareState.observe(viewLifecycleOwner, Observer {
+            getMain(it)
+        })
+
+
+        lottoView1 = view.findViewById(R.id.v1)
+        lottoView2 = view.findViewById(R.id.v2)
+        lottoView3 = view.findViewById(R.id.v3)
+        lottoView4 = view.findViewById(R.id.v4)
+        lottoView5 = view.findViewById(R.id.v5)
+        lottoView6 = view.findViewById(R.id.v6)
+        lottoView7 = view.findViewById(R.id.v7)
+        lottoView8 = view.findViewById(R.id.v8)
+        lottoView9 = view.findViewById(R.id.v9)
+        lottoView10 = view.findViewById(R.id.v10)
+        lottoView11 = view.findViewById(R.id.v11)
+        lottoView12 = view.findViewById(R.id.v12)
+        lottoView13 = view.findViewById(R.id.v13)
+        lottoView14 = view.findViewById(R.id.v14)
+        lottoView15 = view.findViewById(R.id.v15)
+        lottoView16 = view.findViewById(R.id.v16)
+        lottoView17 = view.findViewById(R.id.v17)
+        lottoView18 = view.findViewById(R.id.v18)
+        lottoView19 = view.findViewById(R.id.v19)
+        lottoView20 = view.findViewById(R.id.v20)
+
+        lottoTv1 = view.findViewById(R.id.tv1)
+        lottoTv2 = view.findViewById(R.id.tv2)
+        lottoTv3 = view.findViewById(R.id.tv3)
+        lottoTv4 = view.findViewById(R.id.tv4)
+        lottoTv5 = view.findViewById(R.id.tv5)
+        lottoTv6 = view.findViewById(R.id.tv6)
+        lottoTv7 = view.findViewById(R.id.tv7)
+        lottoTv8 = view.findViewById(R.id.tv8)
+        lottoTv9 = view.findViewById(R.id.tv9)
+        lottoTv10 = view.findViewById(R.id.tv10)
+        lottoTv11 = view.findViewById(R.id.tv11)
+        lottoTv12 = view.findViewById(R.id.tv12)
+        lottoTv13 = view.findViewById(R.id.tv13)
+        lottoTv14 = view.findViewById(R.id.tv14)
+        lottoTv15 = view.findViewById(R.id.tv15)
+        lottoTv16 = view.findViewById(R.id.tv16)
+        lottoTv17 = view.findViewById(R.id.tv17)
+        lottoTv18 = view.findViewById(R.id.tv18)
+        lottoTv19 = view.findViewById(R.id.tv19)
+        lottoTv20 = view.findViewById(R.id.tv20)
+
+        arrayLottoView = arrayListOf(
+            lottoView1,
+            lottoView2,
+            lottoView3,
+            lottoView4,
+            lottoView5,
+            lottoView6,
+            lottoView7,
+            lottoView8,
+            lottoView9,
+            lottoView10,
+            lottoView11,
+            lottoView12,
+            lottoView13,
+            lottoView14,
+            lottoView15,
+            lottoView16,
+            lottoView17,
+            lottoView18,
+            lottoView19,
+            lottoView20
+        )
+
+        arrayLottoTextView = arrayListOf(
+            lottoTv1,
+            lottoTv2,
+            lottoTv3,
+            lottoTv4,
+            lottoTv5,
+            lottoTv6,
+            lottoTv7,
+            lottoTv8,
+            lottoTv9,
+            lottoTv10,
+            lottoTv11,
+            lottoTv12,
+            lottoTv13,
+            lottoTv14,
+            lottoTv15,
+            lottoTv16,
+            lottoTv17,
+            lottoTv18,
+            lottoTv19,
+            lottoTv20
+        )
+
+        tvResult = view.findViewById(R.id.tv_result_show)
+        tvResultSmall = view.findViewById(R.id.tv_result_number)
+        ivBigLogo = view.findViewById(R.id.iv_big_logo)
+        lottoGroup = view.findViewById(R.id.group_lotto)
+        vBigSmal = view.findViewById(R.id.v_big_small)
+        vRang = view.findViewById(R.id.v_range)
+
+        btnPlay = view.findViewById(R.id.btn_play)
+        btnPlayFrame = view.findViewById(R.id.v_frame_play)
+
+        btnPlay.setOnClickListener {
+            if (!sharePref.getIsMute()) betTouch.start()
+            it.btnClick().subscribe {
+
+                (requireActivity() as? ShareActivity)?.apply {
+                    supportFragmentManager.beginTransaction()
+                        .setCustomAnimations(
+                            R.anim.slide_in,
+                            R.anim.slide_out,
+                            R.anim.slide_in_exit,
+                            R.anim.slide_out_exit
+                        )
+                        .add(R.id.container, PlayFragment().apply {
+                            arguments =
+                                Bundle().apply {
+                                    // putInt(Fragment7.COM_INFO_ID_KEY, companyInfoId)
+                                }
+
+                        })
+                        .addToBackStack(null)
+                        .commit()
+                }
+            }
+        }
+        view.findViewById<SettingButtonView>(R.id.btn_result).setOnClickListener {
+            if (!sharePref.getIsMute()) betTouch.start()
+            it.btnClick().subscribe {
+                (requireActivity() as? ShareActivity)?.apply {
+                    supportFragmentManager.beginTransaction()
+                        .setCustomAnimations(
+                            R.anim.slide_in,
+                            R.anim.slide_out,
+                            R.anim.slide_in_exit,
+                            R.anim.slide_out_exit
+                        )
+                        .add(R.id.container, ResultFragment().apply {
+                            arguments =
+                                Bundle().apply {
+                                    // putInt(Fragment7.COM_INFO_ID_KEY, companyInfoId)
+                                }
+
+                        })
+                        .addToBackStack(null)
+                        .commit()
+                }
+            }
+
+        }
+        (requireActivity() as? ShareActivity)?.apply {
+            groupToolbarIcons.isVisible = true
+
+            settingImageView.setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+                it.btnClick().subscribe {
+                    supportFragmentManager.beginTransaction()
+                        .setCustomAnimations(
+                            R.anim.slide_in,
+                            R.anim.slide_out,
+                            R.anim.slide_in_exit,
+                            R.anim.slide_out_exit
+                        )
+                        .add(R.id.container, SettingFragment())
+                        .addToBackStack(null)
+                        .commit()
+                }
+
+            }
+
+            refreshImageView.setOnClickListener {
+                shareViewModel.remoteMainScreenAPI(userId = user.id)
+            }
+
+            reportImageView.setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+                it.btnClick().subscribe {
+                    supportFragmentManager.beginTransaction()
+                        .setCustomAnimations(
+                            R.anim.slide_in,
+                            R.anim.slide_out,
+                            R.anim.slide_in_exit,
+                            R.anim.slide_out_exit
+                        )
+                        .add(R.id.container, StatementFragment().apply {
+                            arguments =
+                                Bundle().apply {
+                                    // putInt(Fragment7.COM_INFO_ID_KEY, companyInfoId)
+                                }
+
+                        })
+                        .addToBackStack(null)
+                        .commit()
+                }
+
+
+            }
+        }
+
+
+    }
+
+    @SuppressLint("CheckResult")
+    override fun onActivityCreated(savedInstanceState: Bundle?) {
+        super.onActivityCreated(savedInstanceState)
+        //viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
+
+
+    }
+
+    private fun animateSmallLogo() {
+        GlobalScope.launch(Dispatchers.Main) {
+            var i = 0
+            while (i < 20) {
+                arrayLottoTextView[i].background = bgDefaultLotto
+                arrayLottoTextView[i].waitingLotto().subscribe()
+                i++
+                delay(5)
+            }
+        }
+    }
+
+
+    private fun animateLottoView(lottoTextView: TextView, number: Int): Completable {
+        return Completable.create {
+            lottoTextView.setBackgroundResource(R.drawable.spin_animation)
+            lottoAnimationDrawable = lottoTextView.background as AnimationDrawable
+
+            lottoAnimationDrawable!!.start()
+
+            GlobalScope.launch(Dispatchers.Main) {
+                var i = 0
+                while (i < 12) {
+                    val rdns = (1..80).random()
+                    lottoTextView.text = "$rdns"
+
+                    i++
+                    delay(100)
+                    if (i == 12) {
+                        when (number) {
+
+                            in 1..20 -> {
+                                lottoTextView.background = bgBlueLotto
+                            }
+                            in 21..40 -> {
+                                lottoTextView.background = bgYellowLotto
+
+                            }
+                            in 41..60 -> {
+                                lottoTextView.background = bgPinkLotto
+                            }
+                            else -> {
+                                lottoTextView.background = bgGreenLotto
+
+                            }
+
+                        }
+                        lottoTextView.setText("$number")
+                        it.onComplete()
+
+                    }
+
+                }
+            }
+
+        }
+
+
+    }
+
+
+    private fun animateALotto(lottoTextView: TextView, number: Int): Completable {
+        return animateLottoView(lottoTextView, number)
+            .andThen(animateLottoZoom(lottoTextView))
+    }
+
+
+    private fun animateLottoZoom(view: View): Completable {
+        return view.zoomIn()
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+
+    }
+
+    override fun onResume() {
+        super.onResume()
+    }
+
+    fun getOtherCreatedBetting(createBettingJsonObject: JSONObject){
+
+        try {
+            val accountBalances = createBettingJsonObject.getString("accountBalances")
+            val createdJsonObject = createBettingJsonObject.getJSONObject("objCurrentBetting")
+            createdJsonObject.let {
+                val currentBetting = CurrentBetting(
+                    id = it.getString("_id"),
+                    no = it.getString("no"),
+                    setId = it.getString("set_result_id"),
+                    typeOfBetting = it.getString("type_of_betting"),
+                    category = it.getString("category"),
+                    userId = it.getString("user_id"),
+                    date = it.getString("date"),
+                    amount = it.getString("amount"),
+                    cast = it.getString("cast"),
+                    win_lose = null,
+                    amount_win = null
+
+                )
+                shareViewModel.addOtherCreatedBetting(accountBalances, currentBetting)
+
+            }
+
+
+        }catch (exception: JSONException){
+            exception.printStackTrace()
+        }
+
+
+    }
+    @SuppressLint("ResourceAsColor", "CheckResult", "SetTextI18n")
+    fun getLottoMessage(loto: SocketMessageDataModel) {
+
+        if (loto.isCountDowning()) {
+
+            when (loto.countDown) {
+                1 -> if (!sharePref.getIsMute()) countDown1.start()
+                2 -> if (!sharePref.getIsMute()) countDown2.start()
+                3 -> if (!sharePref.getIsMute()) countDown3.start()
+                4 -> if (!sharePref.getIsMute()) countDown4.start()
+                5 -> if (!sharePref.getIsMute()) countDown5.start()
+                6 -> if (!sharePref.getIsMute()) countDown6.start()
+                7 -> if (!sharePref.getIsMute()) countDown7.start()
+                8 -> if (!sharePref.getIsMute()) countDown8.start()
+                9 -> if (!sharePref.getIsMute()) countDown9.start()
+                10 -> if (!sharePref.getIsMute()) countDown10.start()
+
+
+            }
+            when (loto.countDown) {
+                in 1..8 -> {
+
+                    if (lottoGroup.isInvisible) lottoGroup.isVisible = true
+                    if (ivBigLogo.isVisible) ivBigLogo.isInvisible = true
+                    if (btnPlayFrame.isInvisible) {
+                        btnPlayFrame.isVisible = true
+                        btnPlay.isEnabled = false
+
+                    }
+                    tvResult.text = "${loto.countDown}"
+                    tv_game_number.text = shareViewModel.getShareState.value?.nextNo
+                    colorRed?.let { tvResult.setTextColor(it) }
+                    vRang.vBox.background = bgWhiteLotto
+                    vRang.tvResult.text = ""
+                    vBigSmal.vBox.background = bgWhiteLotto
+                    vBigSmal.tvResult.background = null
+
+                }
+                9 -> {
+                    if (lottoGroup.isInvisible) lottoGroup.isVisible = true
+                    if (ivBigLogo.isVisible) ivBigLogo.isInvisible = true
+                    if (btnPlayFrame.isInvisible) {
+                        btnPlayFrame.isVisible = true
+                        btnPlay.isEnabled = false
+
+                    }
+                    tvResult.text = "${loto.countDown}"
+                    tv_game_number.text = shareViewModel.getShareState.value?.nextNo
+                    colorRed?.let { tvResult.setTextColor(it) }
+                    vRang.vBox.background = bgWhiteLotto
+                    vRang.tvResult.text = ""
+                    vBigSmal.vBox.background = bgWhiteLotto
+                    vBigSmal.tvResult.background = null
+
+                    ivBigLogo.slideOut(0f).doOnComplete {
+                        arrayLottoTextView.forEachIndexed { _, lottoTextView ->
+                            lottoTextView.background = null
+
+                        }
+                    }.andThen(lottoGroup.slideIn(0f)).subscribe {
+                        animateSmallLogo()
+                    }
+
+
+                }
+                10 -> {
+                    if (lottoGroup.isInvisible) lottoGroup.isVisible = true
+                    if (ivBigLogo.isVisible) ivBigLogo.isInvisible = true
+                    if (btnPlayFrame.isInvisible) {
+                        btnPlayFrame.isVisible = true
+                        btnPlay.isEnabled = false
+
+                    }
+                    tvResult.text = "${loto.countDown}"
+                    tv_game_number.text = shareViewModel.getShareState.value?.nextNo
+                    colorRed?.let { tvResult.setTextColor(it) }
+                    vRang.vBox.background = bgWhiteLotto
+                    vRang.tvResult.text = ""
+                    vBigSmal.vBox.background = bgWhiteLotto
+                    vBigSmal.tvResult.background = null
+
+                }
+                0 -> {
+                    if (lottoGroup.isInvisible) lottoGroup.isVisible = true
+                    if (ivBigLogo.isVisible) ivBigLogo.isInvisible = true
+                    if (btnPlayFrame.isInvisible) {
+                        btnPlayFrame.isVisible = true
+                        btnPlay.isEnabled = false
+                    }
+                    tvResult.text = "${loto.countDown}"
+                    tv_game_number.text = shareViewModel.getShareState.value?.nextNo
+                    colorRed?.let { tvResult.setTextColor(it) }
+                    vRang.vBox.background = bgWhiteLotto
+                    vRang.tvResult.text = ""
+                    vBigSmal.vBox.background = bgWhiteLotto
+                    vBigSmal.tvResult.background = null
+
+                    tvResult.blink(1)
+                    if (!sharePref.getIsMute()) goodLuck.start()
+
+                }
+                119 -> {
+                    if (lottoGroup.isVisible) lottoGroup.isInvisible = true
+                    if (ivBigLogo.isInvisible) ivBigLogo.isVisible = true
+                    if (btnPlayFrame.isVisible) {
+                        btnPlayFrame.isVisible = false
+                        btnPlay.isEnabled = true
+                    }
+                    colorWhite?.let { tvResult.setTextColor(it) }
+                    arrayLottoTextView.forEachIndexed { _, lottoTextView ->
+                        lottoTextView.background = bgDefaultLotto
+                        lottoTextView.text = ""
+
+                    }
+                    //show big logo
+                    lottoGroup.slideOut(0f).andThen(ivBigLogo.slideIn(0f)).subscribe()//{
+
+                }
+                in 120..128 -> {
+                    if (lottoGroup.isInvisible) lottoGroup.isVisible = true
+                    if (ivBigLogo.isVisible) ivBigLogo.isInvisible = true
+                    if (btnPlayFrame.isVisible) {
+                        btnPlayFrame.isInvisible = true
+                        btnPlay.isEnabled = true
+                    }
+                    tvResult.text = "${loto.countDown}"
+                    colorWhite?.let { tvResult.setTextColor(it) }
+                }
+                129 -> {
+                    if (lottoGroup.isInvisible) lottoGroup.isVisible = true
+                    if (ivBigLogo.isVisible) ivBigLogo.isInvisible = true
+                    if (ivBigLogo.isVisible) ivBigLogo.isVisible = false
+                    if (!sharePref.getIsMute()) betPlease.start()
+                    if (btnPlayFrame.isVisible) {
+                        btnPlayFrame.isInvisible = true
+                        btnPlay.isEnabled = true
+                    }
+                    colorWhite?.let { tvResult.setTextColor(it) }
+                    //shareViewModel.remoteMainScreenAPI(userId = user.id)
+                }
+                else -> {
+                    if (lottoGroup.isVisible) lottoGroup.isInvisible = true
+                    if (ivBigLogo.isInvisible) ivBigLogo.isVisible = true
+                    if (btnPlayFrame.isVisible) {
+                        btnPlayFrame.isInvisible = true
+                        btnPlay.isEnabled = true
+                    }
+                    tvResult.text = "${loto.countDown}"
+                    colorWhite?.let { tvResult.setTextColor(it) }
+                    tv_bonus.setText("")
+                    tv_bonus.clearAnimation()
+
+                }
+
+            }
+            //Log.d("Socket", "not release, counting:"+loto.countDown)
+        } else {
+
+            if (lottoGroup.isInvisible) lottoGroup.isVisible = true
+            if (ivBigLogo.isVisible) ivBigLogo.isInvisible = true
+            if (btnPlayFrame.isInvisible) {
+                btnPlayFrame.isVisible = true
+                btnPlay.isEnabled = false
+
+            }
+            resultLength = loto.resultArray!!.length()
+            if(loto.isBonus == true){
+
+                tv_bonus.setText("${loto.bonusNumber}(x${loto.bonusValue})")
+                tv_bonus.startAnimation(anim)
+
+                if (resultLength == 1){
+                    if (!sharePref.getIsMute()) congrat.start()
+                    viewKonfetti.build()
+                        .addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA)
+                        .setDirection(0.0, 359.0)
+                        .setSpeed(1f, 5f)
+                        .setFadeOutEnabled(true)
+                        .setTimeToLive(2000L)
+                        .addShapes(Shape.Square, Shape.Circle)
+                        .addSizes(Size(12))
+                        .setPosition(-50f, viewKonfetti.width + 50f, -50f, -50f)
+                        .streamFor(300, 5000L)
+                }
+
+            }
+
+            var totalResult = 0
+            for (i in 0 until resultLength) {
+                val eachResult = loto.resultArray.getInt(i)
+                totalResult += eachResult
+                when (eachResult) {
+                    in 1..20 -> {
+                        arrayLottoTextView[i].background = bgBlueLotto
+                        arrayLottoTextView[i].text = "${eachResult}"
+                    }
+
+                    in 21..40 -> {
+                        arrayLottoTextView[i].background = bgYellowLotto
+                        arrayLottoTextView[i].text = "${eachResult}"
+
+                    }
+                    in 41..60 -> {
+                        arrayLottoTextView[i].background = bgPinkLotto
+                        arrayLottoTextView[i].text = "${eachResult}"
+                    }
+                    else -> {
+                        arrayLottoTextView[i].background = bgGreenLotto
+                        arrayLottoTextView[i].text = "${eachResult}"
+
+                    }
+                }
+                //Log.d("Socket", "loto Result:"+eachResult)
+            }
+
+            colorWhite?.let { tvResult.setTextColor(it) }
+            vRang.vBox.background = bgWhiteLotto
+            vRang.tvResult.text = ""
+            vBigSmal.vBox.background = bgWhiteLotto
+            vBigSmal.tvResult.background = null
+            tv_game_number.text = shareViewModel.getShareState.value?.nextNo
+            val index = resultLength - 1
+            animateALotto(arrayLottoTextView[index], loto.resultArray.getInt(index)).subscribe {
+                if (!sharePref.getIsMute()) result.start()
+                animateTextView(loto.resultArray.getInt(index), totalResult, tvResult).doOnEnd {
+                    if (resultLength == 20) {//last lotto
+                        shareViewModel.remoteMainScreenAPI(userId = user.id)
+                        shareViewModel.getLottoMessage.value?.totalValue?.let {
+                            getResultSmallOrBig(it)
+                            getResultRange(it)
+
+                        }
+
+                        tvResult.resultBlink().subscribe {
+                            vBigSmal.zoomIn().subscribe()
+                            vRang.zoomIn().subscribe()
+                        }
+
+                    } else if (resultLength == 1) {
+                        tvResult.text = "${loto.resultArray.getInt(index)}"
+                        tvResultSmall.text = "${loto.resultArray.getInt(index)}"
+
+                    }
+                }
+
+                tvResultSmall.text = "$totalResult"
+
+
+            }
+
+
+        }
+    }
+
+    fun getSocketConectionStatus(status: Int) {
+
+        when (status) {
+
+            ConnectivityStates.STATE_DISCONNECTED -> {
+                Log.d("Socket", "onDisconnect...")
+
+                val mStartActivity = Intent(requireContext(), SplashScreenActivity::class.java)
+                startActivity(mStartActivity)
+                System.exit(0)
+
+
+            }
+            ConnectivityStates.STATE_NOT_CONNECTED -> {
+                Log.d("Socket", "onNotconnected...")
+                Toast.makeText(requireContext(), "មិនមាន Internet", Toast.LENGTH_LONG).show()
+
+
+            }
+            ConnectivityStates.STATE_RECONNECTING -> {
+                Log.d("Socket", "onReconnecting...")
+
+
+            }
+            ConnectivityStates.STATE_TIMEOUT -> {
+                Log.d("Socket", "onTimout...")
+                val intent = Intent(requireContext(), SplashScreenActivity::class.java)
+                startActivity(intent)
+                requireActivity().finishAffinity()
+
+
+            }
+            ConnectivityStates.STATE_CONNECTED -> {
+                Log.d("Socket", "onConnected...")
+                shareViewModel.remoteMainScreenAPI(userId = user.id)
+//                Handler().postDelayed(
+//                    {
+//                       // binding.connectivityStatusTV.setVisibility(View.GONE)
+//                    },
+//                    500
+//                )
+            }
+        }
+
+    }
+
+    fun getMain(state: ShareViewState) {
+        if (!state.myBettingList.isNullOrEmpty()) {
+            adapter = MainAdapter(state.myBettingId!!)
+            adapter.submitList(state.myBettingList as List<BaseListItem>?)
+            rv.setHasFixedSize(true)
+            rv.layoutManager = LinearLayoutManager(context)
+            rv.adapter = adapter
+            adapter.printButtonListener = { ticketID, gameID, betDate, betType, betCast, winLose ->
+                //val item = adapter.currentList[index] as ListItem
+                printSomePrintable(
+                    user.userName,
+                    ticketID,
+                    gameID,
+                    betDate,
+                    betType,
+                    betCast,
+                    winLose
+                )
+            }
+        }
+
+        if (state.result != null) {
+            tv_game_number.text = state.result.no
+            tvResultSmall.text = state.result.totalValue
+            getResultSmallOrBig(state.result.totalValue.toInt())
+            getResultRange(state.result.totalValue.toInt())
+
+
+        }
+
+        if (state.accountBalance != null) {
+            (requireActivity() as? ShareActivity)?.apply {
+
+                balanceTextView.text = currencyFormat(state.accountBalance.toInt())
+            }
+
+        }
+
+    }
+
+    fun getResultSmallOrBig(resultNumber: Int) {
+        when (resultNumber) {
+            in 210..810 -> {
+                vBigSmal.vBox.background = bgCircleBlue
+                vBigSmal.tvResult.background = textSmall
+            }
+            in 811..1410 -> {
+                vBigSmal.vBox.background = bgCircleRed
+                vBigSmal.tvResult.background = textBig
+            }
+
+        }
+
+    }
+
+    fun getResultRange(resultNumber: Int) {
+
+        when (resultNumber) {
+            in 210..695 -> {
+                vRang.vBox.background = bgCircleYellow
+                vRang.tvResult.text = "1"
+            }
+            in 696..763 -> {
+                vRang.vBox.background = bgCircleBlue
+                vRang.tvResult.text = "2"
+            }
+            in 764..855 -> {
+                vRang.vBox.background = bgCircleGreen
+                vRang.tvResult.text = "3"
+            }
+            in 856..923 -> {
+                vRang.vBox.background = bgCircleRed
+                vRang.tvResult.text = "4"
+            }
+            in 924..1410 -> {
+                vRang.vBox.background = bgCirclePink
+                vRang.tvResult.text = "5"
+            }
+
+        }
+    }
+
+}
+

+ 10 - 0
app/src/main/java/com/khmer9/lotto/screen/main/MainListItem.kt

@@ -0,0 +1,10 @@
+package com.khmer9.lotto.screen.main
+
+import com.gdtlib.lib.adapter.BaseListItem
+
+data class MainListItem(
+    val Id: Int,
+
+    ) : BaseListItem() {
+    override fun getUnique(): String = Id.toString()
+}

+ 75 - 0
app/src/main/java/com/khmer9/lotto/screen/main/MainListViewHolder.kt

@@ -0,0 +1,75 @@
+package com.khmer9.lotto.screen.main
+
+import android.annotation.SuppressLint
+import android.graphics.Color
+import android.view.View
+import android.widget.TextView
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.khmer9.lotto.R
+import com.khmer9.lotto.extension.btnClick
+import com.khmer9.lotto.extension.setSafeOnClickListener
+import com.khmer9.lotto.remote.ListItem
+
+class MainListViewHolder(itemView: View, private val myBettingId : String,private val printButtonListener: ((String, String, String, String, String, String) -> Unit)?) : BaseListViewHolder(itemView) {
+
+    val tvId = itemView.findViewById<TextView>(R.id.tv_id)
+    val tvBet = itemView.findViewById<TextView>(R.id.tv_bet)
+    val tvAmount =itemView.findViewById<TextView>(R.id.tv_amount)
+    val tvCode = itemView.findViewById<TextView>(R.id.tv_code)
+
+    @SuppressLint("SetTextI18n")
+    override fun bindView(item: BaseListItem) {
+
+        when(item){
+
+            is ListItem ->{
+
+                val ticketID= item.id.substring(item.id.length-7)
+                val betType = getTypeOfBetting(item.typeOfBetting)
+                val betCast = "${getCurrency(item.amount.toInt())}x${item.cast}"
+                val winLose: String
+
+                tvId.text = myBettingId
+                tvBet.text = betType
+                tvCode.text = ticketID
+                if (item.win_lose != null){
+                    winLose = "${item.amount_win}"
+                    tvAmount.text = "$betCast=$winLose"
+                    when (item.win_lose) {
+                        "false" -> {//lost
+                            tvAmount.setTextColor(Color.RED)
+
+                        }
+                        "true" -> {//win
+                            tvAmount.setTextColor(Color.BLUE)
+
+                        }
+                    }
+                }else{
+                    //waiting result
+                    winLose = "???"
+
+                    tvAmount.text = "$betCast=$winLose"
+
+
+                }
+
+                tvCode.setSafeOnClickListener{
+                    it.btnClick().subscribe {
+                        printButtonListener?.invoke(ticketID, myBettingId,item.date,betType,betCast,winLose)
+
+                    }
+                }
+
+
+            }
+
+
+        }
+
+    }
+
+
+
+}

+ 385 - 0
app/src/main/java/com/khmer9/lotto/screen/play/PlayFragment.kt

@@ -0,0 +1,385 @@
+package com.khmer9.lotto.screen.play
+
+import android.annotation.SuppressLint
+import android.media.MediaPlayer
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.View
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import androidx.core.view.isVisible
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder.Companion.getCurrency
+import com.gdtlib.lib.viewholder.BaseListViewHolder.Companion.getTypeOfBetting
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.extension.btnClick
+import com.khmer9.lotto.app.ShareActivity
+import com.khmer9.lotto.app.ShareViewState
+import com.khmer9.lotto.base.BaseFragment
+import com.khmer9.lotto.remote.LottoSet
+import com.khmer9.lotto.remote.SocketMessageDataModel
+import com.khmer9.lotto.remote.User
+import com.khmer9.lotto.screen.main.MainAdapter
+import com.khmer9.lotto.util.Const
+import com.khmer9.lotto.util.ModelPreferencesManager
+import com.khmer9.lotto.view.CircleView
+import com.khmer9.lotto.view.RectangleView
+import com.khmer9.lotto.view.SquareView
+import kotlinx.android.synthetic.main.fragment_play.*
+
+/**
+ * A simple [Fragment] subclass as the second destination in the navigation.
+ */
+class PlayFragment : BaseFragment(R.layout.fragment_play) {
+    private lateinit var tvPlayBigSmall: TextView
+    private lateinit var tvAmount: TextView
+    private val shareViewModel = App.injectShareViewModel()
+    private lateinit var adapter: MainAdapter
+    private lateinit var betTouch : MediaPlayer
+    private lateinit var user: User
+    private lateinit var btnOk: Button
+    private var totalAmount: Int =0
+    private lateinit var lottoSet: LottoSet
+    private lateinit var lottoSetList : List<LottoSet>
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        lottoSetList = ModelPreferencesManager.getList(Const.LOTTO_KEY)!!
+        //Log.d("Data:","---Categpru-"+lottoSetList[0].category)
+        (requireActivity() as ShareActivity).apply {
+            betTouch = MediaPlayer.create(this, R.raw.bettouch)
+            user = userShare
+           
+        }
+
+
+    }
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+
+
+        (requireActivity() as? ShareActivity)?.apply {
+
+            refreshImageView.setOnClickListener {
+                shareViewModel.remoteMainScreenAPI(userId = user.id)
+
+            }
+
+            shareViewModel.getLottoMessage.observe(viewLifecycleOwner, Observer {getLottoMessage(it)
+
+            })
+
+            shareViewModel.getShareState.observe(viewLifecycleOwner, Observer {
+                getPlay(it)
+            })
+
+            groupToolbarIcons.isVisible=false
+            tvAmount = findViewById(R.id.tv_amount_play)
+            tvPlayBigSmall = findViewById(R.id.tv_game_number_big_small)
+
+            view.findViewById<ImageView>(R.id.btn_close).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+            }
+            btnOk = view.findViewById<Button>(R.id.btn_ok)
+            btnOk.setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                //val date = formatShowDate(Date())
+                it.btnClick().subscribe {
+                    val minValue = sharePref.getMinBetting()
+                    val maxValue = sharePref.getMaxBetting()
+                    if (totalAmount in minValue..maxValue) {
+
+                        if (tvPlayBigSmall.text.isNotEmpty()) shareViewModel.remoteCreateBettingAPI(lottoSet,totalAmount, userId = user.id)
+                        else Toast.makeText(applicationContext, "សូមជ្រើសរើសភ្នាល់", Toast.LENGTH_LONG).show()
+
+                    }else {
+                        val message = "ទឹកប្រាក់ភ្នាល់ត្រូវនៅចន្លោះ $minValue ទៅ $maxValue"
+                        Toast.makeText(applicationContext, message, Toast.LENGTH_LONG).show()
+                    }
+
+                }
+
+            }
+            view.findViewById<ImageView>(R.id.tv_clear).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount=0
+                    tvAmount.text =""
+                    tvPlayBigSmall.text=""
+                }
+
+            }
+            view.findViewById<CircleView>(R.id.v_1k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                        1000
+
+                    }else{
+
+                        val amount = tvAmount.text.toString().replace(",","").toInt()
+                        amount + 1000
+                    }
+                    tvAmount.text=currencyFormat(totalAmount)
+                }
+            }
+            view.findViewById<CircleView>(R.id.v_2k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                        2000
+
+                    }else{
+
+                        val amount = tvAmount.text.toString().replace(",","").toInt()
+                        amount + 2000
+                    }
+                    tvAmount.text=currencyFormat(totalAmount)
+                }
+            }
+            view.findViewById<CircleView>(R.id.v_5k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                    5000
+
+                }else{
+
+                    val amount = tvAmount.text.toString().replace(",","").toInt()
+                    amount + 5000
+                }
+                tvAmount.text=currencyFormat(totalAmount)
+            }
+            }
+            view.findViewById<CircleView>(R.id.v_10k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                        10000
+
+                    }else{
+
+                        val amount = tvAmount.text.toString().replace(",","").toInt()
+                        amount + 10000
+                    }
+                    tvAmount.text=currencyFormat(totalAmount)
+                }
+            }
+            view.findViewById<CircleView>(R.id.v_20k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                        20000
+
+                    }else{
+
+                        val amount = tvAmount.text.toString().replace(",","").toInt()
+                        amount + 20000
+                    }
+                    tvAmount.text=currencyFormat(totalAmount)
+                }
+            }
+            view.findViewById<CircleView>(R.id.v_50k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                        50000
+
+                    }else{
+
+                        val amount = tvAmount.text.toString().replace(",","").toInt()
+                        amount + 50000
+                    }
+                    tvAmount.text=currencyFormat(totalAmount)
+                }
+            }
+            view.findViewById<CircleView>(R.id.v_200k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                        200000
+
+                    }else{
+
+                        val amount = tvAmount.text.toString().replace(",","").toInt()
+                        amount + 200000
+                    }
+                    tvAmount.text=currencyFormat(totalAmount)
+                }
+            }
+            view.findViewById<CircleView>(R.id.v_500k).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    totalAmount = if (tvAmount.text.toString().trim().isBlank()){
+                        500000
+
+                    }else{
+
+                        val amount = tvAmount.text.toString().replace(",","").toInt()
+                        amount + 500000
+                    }
+                    tvAmount.text=currencyFormat(totalAmount)
+                }
+            }
+            view.findViewById<RectangleView>(R.id.v_small).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    tvPlayBigSmall.text = "តូច"
+                    lottoSet = findLottoSet(lottoSetList,"Small")
+
+                }
+            }
+            view.findViewById<RectangleView>(R.id.v_big).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    tvPlayBigSmall.text = "ធំ"
+                    lottoSet = findLottoSet(lottoSetList,"Large")
+
+                }
+            }
+            view.findViewById<SquareView>(R.id.v_1).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    tvPlayBigSmall.text = "1"
+                    lottoSet = findLottoSet(lottoSetList,"1")
+
+
+                }
+            }
+            view.findViewById<SquareView>(R.id.v_2).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    tvPlayBigSmall.text = "2"
+                    lottoSet = findLottoSet(lottoSetList,"2")
+
+                }
+            }
+            view.findViewById<SquareView>(R.id.v_3).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    tvPlayBigSmall.text = "3"
+                    lottoSet = findLottoSet(lottoSetList,"3")
+
+
+                }
+            }
+            view.findViewById<SquareView>(R.id.v_4).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    tvPlayBigSmall.text = "4"
+                    lottoSet = findLottoSet(lottoSetList,"4")
+
+                }
+            }
+            view.findViewById<SquareView>(R.id.v_5).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+
+                it.btnClick().subscribe {
+                    tvPlayBigSmall.text = "5"
+                    lottoSet = findLottoSet(lottoSetList,"5")
+
+
+                }
+            }
+        }
+
+    }
+
+    private fun getPlay(state: ShareViewState) {
+
+        if (state.accountBalance != null){
+            (requireActivity() as? ShareActivity)?.apply {
+
+                balanceTextView.text = currencyFormat(state.accountBalance.toInt())
+            }
+
+        }
+         if (!state.myBettingList.isNullOrEmpty()) {
+
+             adapter = MainAdapter(state.myBettingId!!)
+             adapter.submitList(state.myBettingList as List<BaseListItem>?)
+             rv_tb1.setHasFixedSize(true)
+             rv_tb1.layoutManager = LinearLayoutManager(context)
+             rv_tb1.adapter = adapter
+             adapter.printButtonListener={
+                     ticketID, gameID, betDate, betType, betCast, winLose->
+                 printSomePrintable(user.userName,ticketID, gameID, betDate, betType, betCast, winLose)
+             }
+
+             state.isAutoPrint?.getContentIfNotHandled()?.let {isAuto->
+                 totalAmount =0
+                 tvAmount.text =""
+                 tvPlayBigSmall.text=""
+                // shareViewModel.setIsCall(false)
+                 state.currentBetting?.let {
+                     item ->
+                     if (isAuto){
+
+                         val betType = getTypeOfBetting(item.typeOfBetting)
+                         val ticketID= item.id.substring(item.id.length-7)
+                         val betCast = "${getCurrency(item.amount.toInt())}x${item.cast}"
+                         val winLose = if (item.win_lose != null) { "${item.amount_win}" }else "???"
+
+                         printSomePrintable(user.userName,ticketID, item.id, item.date, betType, betCast, winLose)
+
+                     }
+                     shareViewModel.emitCreateBetting(user.id, state.accountBalance.toString(),item)
+
+                 }
+
+             }
+
+         }
+
+    }
+
+    @SuppressLint("SetTextI18n")
+    fun getLottoMessage(loto: SocketMessageDataModel){
+
+        if (loto.isCountDowning() && loto.countDown!! <=10){
+            (requireActivity() as? ShareActivity)?.apply {
+                onBackPressed()
+
+            }
+        }
+        if (!loto.isCountDowning()){
+            (requireActivity() as? ShareActivity)?.apply {
+                onBackPressed()
+
+            }
+        }
+
+        when(loto.countDown){
+            in 15 downTo 11 ->{
+                btnOk.setText("OK(${loto.countDown!!-10})")
+            }
+        }
+    }
+
+
+}

+ 48 - 0
app/src/main/java/com/khmer9/lotto/screen/report/ReportAdapter.kt

@@ -0,0 +1,48 @@
+package com.khmer9.lotto.screen.report
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.khmer9.lotto.R
+
+class ReportAdapter(private val type: Type): BaseListAdapter() {
+    var printButtonListener: ((String, String, String, String, String, String) -> Unit) ?= null
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+        when (type) {
+
+            Type.WIN -> {
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_table_holder,
+                        parent,
+                        false
+                    ), printButtonListener
+                )
+            }
+            Type.WIN_LOST -> {
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_table_holder,
+                        parent,
+                        false
+                    ), printButtonListener
+                )
+            }
+            Type.STATEMENT -> {//Statement
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_report,
+                        parent,
+                        false
+                    )
+                )
+            }
+
+        }
+    }
+}
+enum class Type{
+    WIN, WIN_LOST, STATEMENT
+}

+ 159 - 0
app/src/main/java/com/khmer9/lotto/screen/report/ReportListViewHolder.kt

@@ -0,0 +1,159 @@
+package com.khmer9.lotto.screen.report
+
+import android.annotation.SuppressLint
+import android.graphics.Color
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.khmer9.lotto.R
+import com.khmer9.lotto.extension.btnClick
+import com.khmer9.lotto.extension.setSafeOnClickListener
+import com.khmer9.lotto.remote.Statement
+import com.khmer9.lotto.remote.Win
+import com.khmer9.lotto.remote.WinLost
+import java.text.DecimalFormat
+
+
+class ReportListViewHolder(itemView: View, private val printButtonListener: ((String, String, String, String, String, String) -> Unit)? = null) : BaseListViewHolder(itemView) {
+
+
+    @SuppressLint("SetTextI18n")
+    override fun bindView(item: BaseListItem) {
+
+        when(item){
+
+            is Win ->{
+                val tvId = itemView.findViewById<TextView>(R.id.tv_id)
+                val tvBet = itemView.findViewById<TextView>(R.id.tv_bet)
+                val tvAmount =itemView.findViewById<TextView>(R.id.tv_amount)
+                val tvCode = itemView.findViewById<TextView>(R.id.tv_code)
+
+                val ticketID= item.id.substring(item.id.length-7)
+                val betType = getTypeOfBetting(item.typeOfBetting)
+                val betCast = "${getCurrency(item.amount.toInt())}x${item.cast}"
+                val winLose: String
+
+                tvId.text = item.no
+                tvBet.text = betType
+                tvCode.text = ticketID
+
+                if (item.win_lose != null){
+                    winLose = "${item.amount_win}"
+                    tvAmount.text = "$betCast=$winLose"
+                    when (item.win_lose) {
+                        "false" -> {//lost
+                            tvAmount.setTextColor(Color.RED)
+                        }
+                        "true" -> {//win
+                            tvAmount.setTextColor(Color.BLUE)
+
+                        }
+                    }
+                }else{
+                    //waiting result
+                    winLose = "???"
+
+                    tvAmount.text = "$betCast=$winLose"
+
+                }
+                tvCode.setSafeOnClickListener{
+                    it.btnClick().subscribe {
+                        printButtonListener?.invoke(ticketID, item.no,item.date,betType,betCast,winLose)
+
+                    }
+                }
+
+            }
+            is WinLost ->{
+                val tvId = itemView.findViewById<TextView>(R.id.tv_id)
+                val tvBet = itemView.findViewById<TextView>(R.id.tv_bet)
+                val tvAmount =itemView.findViewById<TextView>(R.id.tv_amount)
+                val tvCode = itemView.findViewById<TextView>(R.id.tv_code)
+
+                val ticketID= item.id.substring(item.id.length-7)
+                val betType = getTypeOfBetting(item.typeOfBetting)
+                val betCast = "${getCurrency(item.amount.toInt())}x${item.cast}"
+                val winLose: String
+
+                tvId.text = item.no
+                tvBet.text = betType
+                tvCode.text = ticketID
+
+                if (item.win_lose != null){
+                    winLose = "${item.amount_win}"
+                    tvAmount.text = "$betCast=$winLose"
+                    when (item.win_lose) {
+                        "false" -> {//lost
+                            tvAmount.setTextColor(Color.RED)
+                        }
+                        "true" -> {//win
+                            tvAmount.setTextColor(Color.BLUE)
+
+                        }
+                    }
+                }else{
+                    //waiting result
+                    winLose = "???"
+
+                    tvAmount.text = "$betCast=$winLose"
+
+                }
+                tvCode.setSafeOnClickListener{
+                    it.btnClick().subscribe {
+                        printButtonListener?.invoke(ticketID, item.no,item.date,betType,betCast,winLose)
+
+                    }
+                }
+
+            }
+            is Statement ->{//Statement
+                val imgC1 = itemView.findViewById<ImageView>(R.id.img_c1)
+                val tvC2 = itemView.findViewById<TextView>(R.id.tv_c2)
+                val tvC3 = itemView.findViewById<TextView>(R.id.tv_c3)
+                val tvC4 =itemView.findViewById<TextView>(R.id.tv_c4)
+               // val tvC5 = itemView.findViewById<TextView>(R.id.tv_c5)
+                tvC2.text = item.date
+                tvC3.text = currencyFormat(item.amount!!.toInt())
+                when(item.note){
+
+                    "Loto"->{
+                        if (item.amount_win!! < 0){//lost
+                            imgC1.setImageResource(R.drawable.bet)
+                            tvC4.text = currencyFormat(item.amount_win.toInt())
+                            tvC4.setTextColor(Color.RED)
+
+
+                        }else{//win
+                            imgC1.setImageResource(R.drawable.bet)
+                            tvC4.text = currencyFormat(item.amount_win.toInt())
+                            tvC4.setTextColor(Color.BLUE)
+                        }
+
+                    }
+                    "Widthraw"->{
+                        imgC1.setImageResource(R.drawable.withdraw)
+
+
+                    }
+                    "Deposite"->{
+                        imgC1.setImageResource(R.drawable.deposit)
+
+                    }
+                }
+
+
+            }
+
+
+        }
+
+    }
+    fun currencyFormat(amount: Int): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+
+}

+ 16 - 0
app/src/main/java/com/khmer9/lotto/screen/report/ReportViewState.kt

@@ -0,0 +1,16 @@
+package com.khmer9.lotto.screen.report
+
+import com.khmer9.lotto.remote.Statement
+import com.khmer9.lotto.remote.Win
+import com.khmer9.lotto.remote.WinLost
+
+data class ReportViewState(
+
+    val initial: Boolean = true,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var winList: List<Win> ?= null,
+    var winLostList: List<WinLost> ?= null,
+    var statementList: List<Statement> ?= null
+
+)

+ 174 - 0
app/src/main/java/com/khmer9/lotto/screen/report/StatementFragment.kt

@@ -0,0 +1,174 @@
+package com.khmer9.lotto.screen.report
+
+import android.annotation.SuppressLint
+import android.media.MediaPlayer
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.View
+import android.widget.ImageView
+import androidx.core.view.isVisible
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.extension.btnClick
+import com.khmer9.lotto.app.ShareActivity
+import com.khmer9.lotto.base.BaseFragment
+import com.khmer9.lotto.remote.SocketMessageDataModel
+import com.khmer9.lotto.remote.User
+import com.khmer9.lotto.util.Const
+import com.khmer9.lotto.util.ModelPreferencesManager
+import kotlinx.android.synthetic.main.fragment_report.*
+
+/**
+ * A simple [Fragment] subclass as the second destination in the navigation.
+ */
+class StatementFragment : BaseFragment(R.layout.fragment_report) {
+
+    private val shareViewModel = App.injectShareViewModel()
+    lateinit var adapterTb1: ReportAdapter
+    lateinit var adapterTb2: ReportAdapter
+    lateinit var adapterTb3: ReportAdapter
+
+    lateinit var rvTab1: RecyclerView
+    lateinit var rvTab2: RecyclerView
+    lateinit var rvTab3: RecyclerView
+    private lateinit var betTouch : MediaPlayer
+    lateinit var user: User
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        (requireActivity() as ShareActivity).apply {
+            betTouch = MediaPlayer.create(this, R.raw.bettouch)
+            user = userShare
+
+        }
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        rvTab1 = view.findViewById(R.id.rv_tb1)
+        rvTab2 = view.findViewById(R.id.rv_tb2)
+        rvTab3 = view.findViewById(R.id.rv_tb3)
+
+
+
+        (requireActivity() as? ShareActivity)?.apply {
+
+            groupToolbarIcons.isVisible=false
+
+            view.findViewById<ImageView>(R.id.btn_close).setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+
+            }
+
+            refreshImageView.setOnClickListener {
+                shareViewModel.remoteReport(userId = user.id)
+            }
+        }
+        shareViewModel.remoteReport(userId = user.id)
+
+        shareViewModel.getReportState.observe(viewLifecycleOwner, Observer {
+            getReport(it)
+        })
+        shareViewModel.getLottoMessage.observe(viewLifecycleOwner, Observer {getMessage(it)
+
+        })
+
+
+        v_tab1.setOnClickListener {
+            bg_select_tab1.visibility=View.VISIBLE
+            bg_select_tab2.visibility=View.INVISIBLE
+            bg_select_tab3.visibility= View.INVISIBLE
+
+            rvTab1.visibility=View.VISIBLE
+            rvTab2.visibility=View.INVISIBLE
+            tab3.visibility=View.INVISIBLE
+
+        }
+
+        v_tab2.setOnClickListener {
+            bg_select_tab1.visibility=View.INVISIBLE
+            bg_select_tab2.visibility=View.VISIBLE
+            bg_select_tab3.visibility= View.INVISIBLE
+            rvTab1.visibility=View.INVISIBLE
+            rvTab2.visibility=View.VISIBLE
+            tab3.visibility=View.INVISIBLE
+
+        }
+
+        v_tab3.setOnClickListener {
+            bg_select_tab1.visibility=View.INVISIBLE
+            bg_select_tab2.visibility=View.INVISIBLE
+            bg_select_tab3.visibility= View.VISIBLE
+            rvTab1.visibility=View.INVISIBLE
+            rvTab2.visibility=View.INVISIBLE
+            tab3.visibility=View.VISIBLE
+
+
+        }
+
+    }
+
+    fun getReport(state: ReportViewState){
+
+        progress.isVisible = state.isProgress
+
+        if (!state.winList.isNullOrEmpty()){
+            adapterTb1 = ReportAdapter(Type.WIN)
+            adapterTb1.submitList(state.winList)
+            rvTab1.setHasFixedSize(true)
+            rvTab1.layoutManager = LinearLayoutManager(context)
+            rvTab1.adapter = adapterTb1
+
+            adapterTb1.printButtonListener={
+                    ticketID, gameID, betDate, betType, betCast, winLose->
+                //val item = adapter.currentList[index] as ListItem
+                printSomePrintable(user.userName,ticketID, gameID, betDate, betType, betCast, winLose)
+            }
+
+        }
+
+        if (!state.winLostList.isNullOrEmpty()){
+            adapterTb2 = ReportAdapter(Type.WIN_LOST)
+            adapterTb2.submitList(state.winLostList)
+            rvTab2.setHasFixedSize(true)
+            rvTab2.layoutManager = LinearLayoutManager(context)
+            rvTab2.adapter = adapterTb2
+
+            adapterTb2.printButtonListener={
+                    ticketID, gameID, betDate, betType, betCast, winLose->
+                //val item = adapter.currentList[index] as ListItem
+                printSomePrintable(user.userName,ticketID, gameID, betDate, betType, betCast, winLose)
+            }
+
+
+        }
+        if (!state.statementList.isNullOrEmpty()){
+            adapterTb3 = ReportAdapter(Type.STATEMENT)
+            adapterTb3.submitList(state.statementList)
+            rvTab3.setHasFixedSize(true)
+            rvTab3.layoutManager = LinearLayoutManager(context)
+            rvTab3.adapter = adapterTb3
+
+
+        }
+
+    }
+    @SuppressLint("SetTextI18n")
+    fun getMessage(loto: SocketMessageDataModel){
+
+        if (loto.isCountDowning() && loto.countDown ==128){
+            (requireActivity() as? ShareActivity)?.apply {
+                shareViewModel.remoteReport(userId = user.id)
+
+            }
+        }
+
+    }
+}

+ 280 - 0
app/src/main/java/com/khmer9/lotto/screen/result/ResultFragment.kt

@@ -0,0 +1,280 @@
+package com.khmer9.lotto.screen.result
+
+import android.annotation.SuppressLint
+import android.media.MediaPlayer
+import android.os.Bundle
+import android.view.View
+import android.widget.ImageView
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.GridLayoutManager
+import com.gdtlib.lib.adapter.BaseListItem
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.app.ShareActivity
+import com.khmer9.lotto.base.BaseFragment
+import com.khmer9.lotto.extension.btnClick
+import com.khmer9.lotto.remote.SocketMessageDataModel
+import com.khmer9.lotto.util.MiddleDividerItemDecoration
+import kotlinx.android.synthetic.main.fragment_result.*
+
+
+/**
+ * A simple [Fragment] subclass as the second destination in the navigation.
+ */
+class ResultFragment : BaseFragment(R.layout.fragment_result) {
+    private lateinit var adapterTable1: Table1Adapter
+    private lateinit var adapterTable2: Table2Adapter
+    private val shareViewModel = App.injectShareViewModel()
+    private lateinit var itemDecoration: MiddleDividerItemDecoration
+    private lateinit var betTouch : MediaPlayer
+
+    //private val sharePref = App.injectPrefHelper()
+
+    var itemsTable2 : MutableList<Table2ListItem> ?= mutableListOf()
+    val itemsTable1 : MutableList<Table1ListItem> ?= mutableListOf()
+
+
+    //val itemsTable1 = mutableListOf<Table1ListItem>()
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        (requireActivity() as ShareActivity).apply {
+            betTouch = MediaPlayer.create(this, R.raw.bettouch)
+
+        }
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+
+        (requireActivity() as? ShareActivity)?.apply {
+
+            groupToolbarIcons.isVisible = false
+
+            view.findViewById<ImageView>(R.id.btn_close).setOnClickListener {
+
+                if (!sharePref.getIsMute()) betTouch.start()
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+
+
+            }
+            refreshImageView.setOnClickListener {
+                shareViewModel.remoteResult()
+
+            }
+            shareViewModel.getLottoMessage.observe(viewLifecycleOwner, Observer {getMessage(it)
+
+            })
+        }
+
+        itemDecoration =
+            MiddleDividerItemDecoration(requireContext(), MiddleDividerItemDecoration.ALL)
+        itemDecoration.setDividerColor(
+            ContextCompat.getColor(
+                requireContext(),
+                R.color.color_gray_800
+            )
+        )
+        shareViewModel.remoteResult()
+        shareViewModel.getResultState.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+            getResult(it)
+        })
+        adapterTable1 = Table1Adapter()
+
+        for (n in 1..117) {
+            itemsTable1?.add(Table1ListItem(n, 0))
+
+        }
+        rv_tb1.addItemDecoration(itemDecoration)
+        rv_tb1.setHasFixedSize(true)
+        rv_tb1.layoutManager = GridLayoutManager(requireContext(), 13)
+        rv_tb1.adapter = adapterTable1
+        adapterTable1.submitList(itemsTable1 as List<BaseListItem>?)
+
+
+        adapterTable2 = Table2Adapter()
+        for (n in 1..117) {
+            itemsTable2?.add(Table2ListItem(n, 0))
+        }
+        rv_tb2.addItemDecoration(itemDecoration)
+        rv_tb2.setHasFixedSize(true)
+        rv_tb2.layoutManager = GridLayoutManager(requireContext(), 13)
+        rv_tb2.adapter = adapterTable2
+        //adapterTable1.submitList(itemsTable1 as List<BaseListItem>?)
+
+        adapterTable2.submitList(itemsTable2 as List<Table2ListItem>)
+
+
+    }
+
+
+    fun getResult(state: ResultViewState){
+        if (state.isProgress){
+
+            progress_tb1.isVisible= true
+            progress_tb2.isVisible= true
+
+        }else{
+            progress_tb1.isVisible= false
+            progress_tb2.isVisible= false
+
+        }
+        if (!state.resultList.isNullOrEmpty()){
+            //1 row have 13 column
+            var bigSmallIndex=0
+            var nDuplicateBigSmall = 0
+
+            var rangeIndex = 0
+            var nDuplicateRange = 0
+
+            val listBigSmall = arrayListOf<Table1ListItem>()
+            for (n in 1..117) {
+                listBigSmall.add(Table1ListItem(n, 0))
+
+            }
+            val listRange = arrayListOf<Table2ListItem>()
+            for (n in 1..117) {
+                listRange.add(Table2ListItem(n, 0))
+
+            }
+            state.resultList?.forEachIndexed { index, result ->
+
+                if (index == 0){
+                    listBigSmall[index].color=getLargeSmall(result.resultSmallOrBig)
+                    listRange[index].rangeNumber= getRange(result.resultRange)
+
+                } else{
+                    if (result.resultSmallOrBig == state.resultList!![index-1].resultSmallOrBig){
+                        val isBigSmall = getLargeSmall(result.resultSmallOrBig)
+                        nDuplicateBigSmall+=1
+                        bigSmallIndex += sameBigSmall(index, listBigSmall, bigSmallIndex,isBigSmall,nDuplicateBigSmall)
+
+
+                    }else{
+                        listBigSmall[index-bigSmallIndex].color=getLargeSmall(result.resultSmallOrBig)
+                        nDuplicateBigSmall=0
+                    }
+
+                    if (result.resultRange == state.resultList!![index-1].resultRange){
+                        val range = getRange(result.resultRange)
+                        nDuplicateRange+=1
+                        rangeIndex += sameRange(index, listRange, rangeIndex,range,nDuplicateRange)
+
+
+
+                    }else{
+                        listRange[index-rangeIndex].rangeNumber=getRange(result.resultRange)
+                        nDuplicateRange=0
+                    }
+
+
+
+                }
+
+            }
+
+
+            adapterTable1.submitList(listBigSmall as List<BaseListItem>?)
+
+            adapterTable2.submitList(listRange as List<BaseListItem>?)
+
+
+
+
+        }
+
+    }
+    fun sameBigSmall(columnIndex: Int, arrayList: ArrayList<Table1ListItem>, bigSmallIndex: Int, isBigSmall: Int, nDuplicateBigSmall: Int): Int{
+        var betweenIndex=0
+
+            if (arrayList[columnIndex+12].color == 0){//free space
+
+                if (nDuplicateBigSmall>1){
+
+                    for (i in 2..nDuplicateBigSmall) arrayList[(columnIndex-bigSmallIndex)+(i*13)-1].color=isBigSmall
+
+
+                }else {
+                    arrayList[(columnIndex-bigSmallIndex+12)].color=isBigSmall
+                }
+
+                betweenIndex++
+                return betweenIndex
+            }
+
+        return 0
+
+    }
+    fun sameRange(columnIndex: Int, arrayList: ArrayList<Table2ListItem>, rangeIndex: Int, range: Int, nDuplicateRange: Int): Int{
+        var betweenIndex=0
+
+        if (arrayList[columnIndex+12].rangeNumber == 0){//free space
+
+            if (nDuplicateRange>1){
+
+                for (i in 2..nDuplicateRange) arrayList[(columnIndex-rangeIndex)+(i*13)-1].rangeNumber=range
+
+
+            }else {
+                arrayList[(columnIndex-rangeIndex+12)].rangeNumber=range
+            }
+
+            betweenIndex++
+            return betweenIndex
+        }
+
+        return 0
+
+    }
+    fun getLargeSmall(type: String): Int{
+        when (type) {
+            "Small" -> {
+                return 1//blue
+            }
+            "Large" -> {
+                return 2//red
+            }
+        }
+        return 0
+    }
+
+    fun getRange(type: String): Int{
+        when (type) {
+            "1" -> {
+                return 1
+            }
+            "2" -> {
+                return 2
+            }
+            "3" -> {
+                return 3
+            }
+            "4" -> {
+                return 4
+            }
+            "5" -> {
+                return 5
+            }
+        }
+
+        return 0
+    }
+    @SuppressLint("SetTextI18n")
+    fun getMessage(loto: SocketMessageDataModel){
+
+        if (loto.isCountDowning() && loto.countDown ==128){
+            (requireActivity() as? ShareActivity)?.apply {
+                shareViewModel.remoteResult()
+
+            }
+        }
+
+    }
+}

+ 11 - 0
app/src/main/java/com/khmer9/lotto/screen/result/ResultViewState.kt

@@ -0,0 +1,11 @@
+package com.khmer9.lotto.screen.result
+
+import com.khmer9.lotto.remote.ResultLotto
+
+data class ResultViewState(
+
+    val initial: Boolean = true,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var resultList: List<ResultLotto> ?= null,
+)

+ 20 - 0
app/src/main/java/com/khmer9/lotto/screen/result/Table1Adapter.kt

@@ -0,0 +1,20 @@
+package com.khmer9.lotto.screen.result
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.khmer9.lotto.R
+
+class Table1Adapter : BaseListAdapter() {
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
+        Table1ListViewHolder(
+            LayoutInflater.from(parent.context).inflate(
+                R.layout.item_box,
+                parent,
+                false
+            ))
+
+
+}

+ 11 - 0
app/src/main/java/com/khmer9/lotto/screen/result/Table1ListItem.kt

@@ -0,0 +1,11 @@
+package com.khmer9.lotto.screen.result
+
+import com.gdtlib.lib.adapter.BaseListItem
+
+data class Table1ListItem(
+    val Id: Int,
+    var color: Int //1 is blue small, 2 is red big, other is white
+
+) : BaseListItem() {
+    override fun getUnique(): String = Id.toString()//"${Id}${color}"
+}

+ 34 - 0
app/src/main/java/com/khmer9/lotto/screen/result/Table1ListViewHolder.kt

@@ -0,0 +1,34 @@
+package com.khmer9.lotto.screen.result
+
+import android.view.View
+import android.widget.ImageView
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.khmer9.lotto.R
+
+class Table1ListViewHolder(
+    itemView: View
+
+) : BaseListViewHolder(itemView) {
+    private val ivCircle = itemView.findViewById<ImageView>(R.id.img_color)
+
+
+    override fun bindView(item: BaseListItem) {
+        when (item) {
+            is Table1ListItem -> {
+
+                with(item) {
+                    if (color == 1){//1 is blue small
+                        ivCircle.setImageResource(R.drawable.bg_circle_blue)
+
+                    }else if (color ==2){//2 is red big
+                        ivCircle.setImageResource(R.drawable.bg_circle_red)
+
+                    }
+                }
+
+
+            }
+        }
+    }
+}

+ 20 - 0
app/src/main/java/com/khmer9/lotto/screen/result/Table2Adapter.kt

@@ -0,0 +1,20 @@
+package com.khmer9.lotto.screen.result
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.khmer9.lotto.R
+
+class Table2Adapter : BaseListAdapter() {
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
+        Table2ListViewHolder(
+            LayoutInflater.from(parent.context).inflate(
+                R.layout.item_box_number,
+                parent,
+                false
+            ))
+
+
+}

+ 11 - 0
app/src/main/java/com/khmer9/lotto/screen/result/Table2ListItem.kt

@@ -0,0 +1,11 @@
+package com.khmer9.lotto.screen.result
+
+import com.gdtlib.lib.adapter.BaseListItem
+
+data class Table2ListItem(
+    val Id: Int,
+    var rangeNumber : Int //1->5
+
+) : BaseListItem() {
+    override fun getUnique(): String = Id.toString()
+}

+ 47 - 0
app/src/main/java/com/khmer9/lotto/screen/result/Table2ListViewHolder.kt

@@ -0,0 +1,47 @@
+package com.khmer9.lotto.screen.result
+
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.khmer9.lotto.R
+
+class Table2ListViewHolder(
+    itemView: View
+
+) : BaseListViewHolder(itemView) {
+    private val ivCircle = itemView.findViewById<ImageView>(R.id.img_color)
+
+     private val tvNumber = itemView.findViewById<TextView>(R.id.tv_number)
+
+
+    override fun bindView(item: BaseListItem) {
+        when (item) {
+            is Table2ListItem -> {
+
+                with(item) {
+                    if (rangeNumber == 1){//1 is yellow
+                        ivCircle.setImageResource(R.drawable.bg_circle_yellow)
+                        tvNumber.text = rangeNumber.toString()
+
+                    }else if (rangeNumber ==2){//2 is blue
+                        ivCircle.setImageResource(R.drawable.bg_circle_blue)
+                        tvNumber.text = rangeNumber.toString()
+                    }else if (rangeNumber ==3){//3 is green
+                        ivCircle.setImageResource(R.drawable.bg_circle_green)
+                        tvNumber.text = rangeNumber.toString()
+                    }else if (rangeNumber ==4){//4 is red
+                        ivCircle.setImageResource(R.drawable.bg_circle_red)
+                        tvNumber.text = rangeNumber.toString()
+                    }else if (rangeNumber ==5){//5 is pink
+                        ivCircle.setImageResource(R.drawable.bg_circle_pink)
+                        tvNumber.text = rangeNumber.toString()
+                    }
+                }
+            }
+
+        }
+
+    }
+}

+ 184 - 0
app/src/main/java/com/khmer9/lotto/screen/setting/SettingFragment.kt

@@ -0,0 +1,184 @@
+package com.khmer9.lotto.screen.setting
+
+import android.app.Activity
+import android.content.Intent
+import android.media.MediaPlayer
+import android.os.Bundle
+import android.view.View
+import android.widget.ImageView
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import com.google.android.material.textfield.TextInputLayout
+import com.mazenrashed.printooth.Printooth
+import com.mazenrashed.printooth.ui.ScanningActivity
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.app.ShareActivity
+import com.khmer9.lotto.base.BaseFragment
+import com.khmer9.lotto.extension.btnClick
+import com.khmer9.lotto.remote.User
+import com.khmer9.lotto.screen.login.LoginActivity
+import com.khmer9.lotto.util.Const
+import com.khmer9.lotto.util.ModelPreferencesManager
+import kotlinx.android.synthetic.main.fragment_setting.*
+
+/**
+ * A simple [Fragment] subclass as the second destination in the navigation.
+ */
+class SettingFragment : BaseFragment(R.layout.fragment_setting) {
+
+    private lateinit var btnClose: ImageView
+    private lateinit var user: User
+    private lateinit var betTouch : MediaPlayer
+    private val sharePref = App.injectPrefHelper()
+    private lateinit var settingViewModel: SettingViewModel
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        settingViewModel= SettingViewModel(App.injectApiService(), App.injectPrefHelper())
+        super.onCreate(savedInstanceState)
+        (requireActivity() as ShareActivity).apply {
+            betTouch = MediaPlayer.create(this, R.raw.bettouch)
+            user = userShare
+
+        }
+    }
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        settingViewModel.state.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+            getResult(it)
+        })
+
+        (requireActivity() as? ShareActivity)?.apply {
+
+            groupToolbarIcons.isVisible=false
+            btnClose=view.findViewById<ImageView>(R.id.btn_close)
+            btnClose.setOnClickListener {
+                if (!sharePref.getIsMute()) betTouch.start()
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+            }
+
+        }
+
+        val tilNewPwd = view.findViewById<TextInputLayout>(R.id.til_new_pwd)
+        val tilConfirmPwd = view.findViewById<TextInputLayout>(R.id.til_confirm_pwd)
+        sw_print.isChecked = sharePref.getIsAutoPrint()
+
+        val hasPair= Printooth.hasPairedPrinter()
+
+        if (hasPair){
+            v_print.setImageViewIcon(R.drawable.blue_text_dc)
+            val pair =Printooth.getPairedPrinter()
+
+            text_connect.text = pair?.name
+
+        }
+
+
+        v_save.setOnClickListener {
+            if (!sharePref.getIsMute()) betTouch.start()
+            it.btnClick().subscribe {
+                tv_error.text = ""
+                tilNewPwd.error = null
+                tilNewPwd.isErrorEnabled= false
+                tilConfirmPwd.error = null
+                tilConfirmPwd.isErrorEnabled= false
+                val newPwd = et_new_pwd.text
+                val confirmPwd = et_confirm_pwd.text
+                if (newPwd.isNullOrEmpty()){
+                    tilNewPwd.error = getString(R.string.err_not_empty)
+                    tilNewPwd.requestFocus()
+                    tv_error.text = getString(R.string.err_not_empty)
+                    return@subscribe
+                }
+                if (confirmPwd.isNullOrEmpty()){
+                    tilConfirmPwd.error = getString(R.string.err_not_empty)
+                    tilConfirmPwd.requestFocus()
+                    tv_error.text = getString(R.string.err_not_empty)
+                    return@subscribe
+                }
+                if (newPwd.toString() != confirmPwd.toString()){
+                    tilNewPwd.error = getString(R.string.err_wrong_pwd)
+                    tilConfirmPwd.error = getString(R.string.err_wrong_pwd)
+                    tv_error.text = getString(R.string.err_wrong_pwd)
+                    return@subscribe
+                }
+
+                settingViewModel.updatePassword(userId = user.id,username = user.userName,password = newPwd.toString())
+
+            }
+
+
+        }
+
+        sw_print.setOnCheckedChangeListener { _, isChecked ->
+            if (!sharePref.getIsMute()) betTouch.start()
+            sharePref.setIsAutoPrint(isChecked)
+        }
+        sw_bluetooth.setOnCheckedChangeListener { _, _ ->
+            if (!sharePref.getIsMute()) betTouch.start()
+
+        }
+        v_print.setOnClickListener {
+            if (!sharePref.getIsMute()) betTouch.start()
+            it.btnClick().subscribe {
+                if (hasPair){
+                    Printooth.removeCurrentPrinter()
+                    v_print.setImageViewIcon(R.drawable.blue_text_connect)
+                    text_connect.text = ""
+
+                }else startActivityForResult(Intent(requireActivity(), ScanningActivity::class.java), ScanningActivity.SCANNING_FOR_PRINTER)
+
+            }
+        }
+        v_logout.setOnClickListener {
+            if (!sharePref.getIsMute()) betTouch.start()
+            it.btnClick().subscribe {
+                sharePref.logout()
+
+                val intent = Intent(requireContext(), LoginActivity::class.java)
+                startActivity(intent)
+                requireActivity().finishAffinity()
+
+            }
+        }
+
+    }
+    private fun getResult(state: UpdatePwdViewState) {
+
+       // if (state.isProgress){
+           // Toast.makeText(requireContext(), "Loading", Toast.LENGTH_LONG).show()
+
+        //}
+        if (state.isUpdateSuccess){
+             //Toast.makeText(requireContext(), "Update Sucess", Toast.LENGTH_LONG).show()
+            val intent = Intent(requireContext(), LoginActivity::class.java)
+            startActivity(intent)
+            requireActivity().finishAffinity()
+
+        }
+        if (state.error != null){
+            //Toast.makeText(requireContext(), "Error", Toast.LENGTH_LONG).show()
+            tv_error.text = state.error
+
+
+        }
+
+    }
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        if (requestCode == ScanningActivity.SCANNING_FOR_PRINTER && resultCode == Activity.RESULT_OK){
+
+            val pair =Printooth.getPairedPrinter()
+            v_print.setImageViewIcon(R.drawable.blue_text_dc)
+            text_connect.text = pair?.name
+
+
+            //Printooth.removeCurrentPrinter()
+//https://github.com/mazenrashed/Printooth
+
+        }
+        //Printer is ready now
+    }
+}

+ 49 - 0
app/src/main/java/com/khmer9/lotto/screen/setting/SettingViewModel.kt

@@ -0,0 +1,49 @@
+package com.khmer9.lotto.screen.setting
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.khmer9.lotto.app.getErrorCode
+import com.khmer9.lotto.base.BaseViewModel
+import com.khmer9.lotto.remote.service.ApiService
+import com.khmer9.lotto.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class SettingViewModel(val apiService: ApiService, val prefHelper: PrefHelper) : BaseViewModel(){
+
+
+    private val _state = MutableLiveData<UpdatePwdViewState>(UpdatePwdViewState())
+    val state: LiveData<UpdatePwdViewState> = _state
+
+    fun updatePassword(userId: String, username: String, password: String) {
+        if (_state.value!!.isProgress) return
+        _state.value = prev().copy(isProgress = true)
+
+        disposables.add(
+            apiService.updatePassword(userId,username,password)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+
+                        _state.value = prev().copy(isProgress = false, isUpdateSuccess = true)
+
+                        prefHelper.logout()
+
+                    } else {
+                        _state.value = prev().copy(isProgress = false, error = "[${it.message.description}]")
+                    }
+                }, {
+                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
+
+                    _state.value = prev().copy(isProgress = false, error = message)
+                })
+        )
+    }
+
+    private fun prev() = _state.value!!
+
+
+}

+ 10 - 0
app/src/main/java/com/khmer9/lotto/screen/setting/UpdatePwdViewState.kt

@@ -0,0 +1,10 @@
+package com.khmer9.lotto.screen.setting
+
+
+
+data class UpdatePwdViewState(
+    val initial: Boolean = false,
+    val isProgress: Boolean = false,
+    val isUpdateSuccess: Boolean = false,
+    val error: String? = null
+)

+ 102 - 0
app/src/main/java/com/khmer9/lotto/screen/splash/SplashScreenActivity.kt

@@ -0,0 +1,102 @@
+package com.khmer9.lotto.screen.splash
+
+import android.content.Intent
+import android.os.Bundle
+import android.os.Handler
+import android.view.animation.Animation
+import android.view.animation.LinearInterpolator
+import android.view.animation.RotateAnimation
+import android.widget.ImageView
+import com.khmer9.lotto.R
+import com.khmer9.lotto.app.App
+import com.khmer9.lotto.app.ShareActivity
+import com.khmer9.lotto.base.BaseActivity
+import com.khmer9.lotto.screen.login.LoginActivity
+
+
+class SplashScreenActivity : BaseActivity() {
+    lateinit var imageLading: ImageView
+    lateinit var rotateAnimation: Animation
+    val prefHelper = App.injectPrefHelper()
+    private val handler by lazy {
+        Handler()
+    }
+
+    private val runnable by lazy {
+        Runnable {
+            //imageLading.clearAnimation()
+
+        }
+    }
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_splash)
+        imageLading = findViewById(R.id.image_loading)
+        val rotate = RotateAnimation(
+            0f,
+            180f,
+            Animation.RELATIVE_TO_SELF,
+            0.5f,
+            Animation.RELATIVE_TO_SELF,
+            0.5f
+        )
+        rotate.duration = 500
+        rotate.repeatCount = 5
+        rotate.fillAfter = true
+        rotate.startOffset = 0
+        //rotate.repeatMode= Animation.INFINITE
+        rotate.interpolator = LinearInterpolator()
+        imageLading.startAnimation(rotate)
+
+        rotate.setAnimationListener(object : Animation.AnimationListener{
+            override fun onAnimationRepeat(animation: Animation?) {
+            }
+
+            override fun onAnimationEnd(animation: Animation?) {
+                    //var nextScreen: Any = LoginActivity::class.java
+                    if (prefHelper.getToken().isNotEmpty()) {
+                       // nextScreen = ShareActivity::class.java
+                        val intent = Intent(this@SplashScreenActivity, ShareActivity::class.java)
+                        startActivity(intent)
+                    }else{
+                        val intent = Intent(this@SplashScreenActivity, LoginActivity::class.java)
+                        startActivity(intent)
+                    }
+
+                    finishAffinity()
+
+            }
+
+            override fun onAnimationStart(animation: Animation?) {
+            }
+
+        }
+        )
+
+
+    }
+    override fun onDestroy() {
+        //handler.removeCallbacks(runnable)
+        super.onDestroy()
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        //handler.postDelayed(runnable, 800)
+
+//        Handler().postDelayed({
+//            imageLading.clearAnimation()
+//
+//        }, 1000)
+
+//        val intent = Intent(this, nextScreen as Class<*>)
+//        val intent = Intent(this, MainActivity::class.java)
+//        Handler().postDelayed({
+//            imageLading.clearAnimation()
+//            startActivity(intent)
+//           // finishAffinity()
+//        }, 800)
+//
+   }
+}

+ 36 - 0
app/src/main/java/com/khmer9/lotto/util/AnimationDrawableWithCallback.java

@@ -0,0 +1,36 @@
+package com.khmer9.lotto.util;
+
+import android.graphics.drawable.AnimationDrawable;
+
+public class AnimationDrawableWithCallback extends AnimationDrawable {
+
+    interface IAnimationFinishListener {
+        void onAnimationChanged(int index, boolean finished);
+    }
+
+    private IAnimationFinishListener animationFinishListener;
+
+    public IAnimationFinishListener getAnimationFinishListener() {
+        return animationFinishListener;
+    }
+
+    public void setAnimationFinishListener(IAnimationFinishListener animationFinishListener) {
+        this.animationFinishListener = animationFinishListener;
+    }
+
+    @Override
+    public boolean selectDrawable(int index) {
+
+        boolean drawableChanged = super.selectDrawable(index);
+
+        if (drawableChanged && animationFinishListener != null) {
+            boolean animationFinished = (index == getNumberOfFrames() - 1);
+            animationFinishListener.onAnimationChanged(index, animationFinished);
+        }
+
+        return drawableChanged;
+
+    }
+
+}
+

+ 25 - 0
app/src/main/java/com/khmer9/lotto/util/BaseObservable.java

@@ -0,0 +1,25 @@
+package com.khmer9.lotto.util;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class BaseObservable<LISTENER_CLASS> {
+
+    private final Set<LISTENER_CLASS> mListeners = Collections.newSetFromMap(
+            new ConcurrentHashMap<LISTENER_CLASS, Boolean>(1));
+
+
+    public final void registerListener(LISTENER_CLASS listener) {
+        mListeners.add(listener);
+    }
+
+    public final void unregisterListener(LISTENER_CLASS listener) {
+        mListeners.remove(listener);
+    }
+
+    protected final Set<LISTENER_CLASS> getListeners() {
+        return Collections.unmodifiableSet(mListeners);
+    }
+
+}

+ 52 - 0
app/src/main/java/com/khmer9/lotto/util/ConfirmDialog.kt

@@ -0,0 +1,52 @@
+package com.khmer9.lotto.util;
+
+import android.content.Context
+import android.view.LayoutInflater
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.widget.AppCompatButton
+import androidx.appcompat.widget.AppCompatTextView
+import com.khmer9.lotto.R
+
+class ConfirmDialog {
+
+    companion object {
+        fun create(
+            context: Context,
+            title: String? = null,
+            message: String? = null,
+            onConfirm: (() -> Unit)? = null
+        ): AlertDialog {
+            val builder = AlertDialog.Builder(context)
+            val view =
+                LayoutInflater.from(context)
+                    .inflate(R.layout.dialog_yearly_tax_confirm, null, false)
+
+            val btnConfirm = view.findViewById<AppCompatButton>(R.id.btn_confirm)
+            val btnCancel = view.findViewById<AppCompatButton>(R.id.btn_cancel)
+
+            title?.let {
+                val tvTitle = view.findViewById<AppCompatTextView>(R.id.tv_title)
+                tvTitle.text = it
+            }
+            message?.let {
+                val tvMessage = view.findViewById<AppCompatTextView>(R.id.tv_message)
+                tvMessage.text = it
+            }
+
+            builder.setView(view)
+            val dialog = builder.create()
+
+            btnCancel.setOnClickListener {
+                dialog.dismiss()
+            }
+            btnConfirm.setOnClickListener {
+                onConfirm?.invoke()
+                dialog.dismiss()
+            }
+
+            dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
+            return dialog
+        }
+    }
+
+}

+ 16 - 0
app/src/main/java/com/khmer9/lotto/util/Const.kt

@@ -0,0 +1,16 @@
+package com.khmer9.lotto.util
+
+class Const {
+
+    companion object{
+        val USER_KEY = "user_key"
+        val LOTTO_KEY = "lotto_key"
+        val MIN_KEY = "min_key"
+        val MAX_KEY = "max_key"
+        val USER_ROLE = "5f801651aceefc261088ee73"
+        val MUTE_KEY = "isMute"
+        val AUTO_PRINT_KEY="autoPrintKey"
+        val TOKEN_KEY = "tokenCode"
+
+    }
+}

+ 66 - 0
app/src/main/java/com/khmer9/lotto/util/CustomAnimationDrawable.java

@@ -0,0 +1,66 @@
+package com.khmer9.lotto.util;
+
+import android.graphics.drawable.AnimationDrawable;
+import android.os.Handler;
+
+public abstract class CustomAnimationDrawable extends AnimationDrawable {
+
+    /** Handles the animation callback. */
+    Handler mAnimationHandler;
+
+    public CustomAnimationDrawable(AnimationDrawable aniDrawable) {
+        /* Add each frame to our animation drawable */
+        for (int i = 0; i < aniDrawable.getNumberOfFrames(); i++) {
+            this.addFrame(aniDrawable.getFrame(i), aniDrawable.getDuration(i));
+        }
+    }
+
+    @Override
+    public void start() {
+        super.start();
+        /*
+         * Call super.start() to call the base class start animation method.
+         * Then add a handler to call onAnimationFinish() when the total
+         * duration for the animation has passed
+         */
+        mAnimationHandler = new Handler();
+        mAnimationHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                onAnimationStart();
+            }
+        });
+        mAnimationHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                onAnimationFinish();
+            }
+        }, getTotalDuration());
+
+    }
+
+    /**
+     * Gets the total duration of all frames.
+     *
+     * @return The total duration.
+     */
+    public int getTotalDuration() {
+
+        int iDuration = 0;
+
+        for (int i = 0; i < this.getNumberOfFrames(); i++) {
+            iDuration += this.getDuration(i);
+        }
+
+        return iDuration;
+    }
+
+    /**
+     * Called when the animation finishes.
+     */
+    public abstract void onAnimationFinish();
+    /**
+     * Called when the animation starts.
+     */
+    public abstract void onAnimationStart();
+}

+ 25 - 0
app/src/main/java/com/khmer9/lotto/util/DimensionUtil.kt

@@ -0,0 +1,25 @@
+package com.gdt.dev.gdtevaluationAdmin.util
+
+
+import android.content.Context
+import android.content.res.Resources
+
+class DimensionUtil {
+
+    companion object {
+        fun dpToPx(dp: Float): Int {
+            return (dp * Resources.getSystem().displayMetrics.density).toInt()
+        }
+
+        fun pxToDp(px: Float): Int {
+            return (px / Resources.getSystem().displayMetrics.density).toInt()
+        }
+        fun spToPx( spValue: Float): Int {
+            val fontScale = Resources.getSystem().displayMetrics.scaledDensity
+            return (spValue * fontScale + 0.5f).toInt()
+        }
+    }
+
+
+
+}

+ 23 - 0
app/src/main/java/com/khmer9/lotto/util/DimensionUtils.kt

@@ -0,0 +1,23 @@
+package com.khmer9.lotto.util
+
+
+import android.content.res.Resources
+import android.graphics.Rect
+import android.graphics.RectF
+import android.util.DisplayMetrics
+import kotlin.math.roundToInt
+
+
+private val displayMetrics: DisplayMetrics by lazy { Resources.getSystem().displayMetrics }
+
+val screenRectPx: Rect
+    get() = displayMetrics.run { Rect(0, 0, widthPixels, heightPixels) }
+
+val screenRectDp: RectF
+    get() = displayMetrics.run { RectF(0f, 0f, widthPixels.px2dp, heightPixels.px2dp) }
+
+val Number.px2dp: Float
+    get() = this.toFloat() / displayMetrics.density
+
+val Number.dp2px: Int
+    get() = (this.toFloat() * displayMetrics.density).roundToInt()

+ 27 - 0
app/src/main/java/com/khmer9/lotto/util/Event.kt

@@ -0,0 +1,27 @@
+package com.khmer9.lotto.util;
+
+/**
+ * Used as a wrapper for data that is exposed via a LiveData that represents an event.
+ */
+open class Event<out T>(private val content: T) {
+
+  var hasBeenHandled = false
+    private set // Allow external read but not write
+
+  /**
+   * Returns the content and prevents its use again.
+   */
+  fun getContentIfNotHandled(): T? {
+    return if (hasBeenHandled) {
+      null
+    } else {
+      hasBeenHandled = true
+      content
+    }
+  }
+
+  /**
+   * Returns the content, even if it's already been handled.
+   */
+  fun peekContent(): T = content
+}

+ 135 - 0
app/src/main/java/com/khmer9/lotto/util/GridDividerItemDecoration.java

@@ -0,0 +1,135 @@
+package com.khmer9.lotto.util;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Adds interior dividers to a RecyclerView with a GridLayoutManager.
+ */
+public class GridDividerItemDecoration extends RecyclerView.ItemDecoration {
+
+    private Drawable mHorizontalDivider;
+    private Drawable mVerticalDivider;
+    private int mNumColumns;
+
+    /**
+     * Sole constructor. Takes in {@link Drawable} objects to be used as
+     * horizontal and vertical dividers.
+     *
+     * @param horizontalDivider A divider {@code Drawable} to be drawn on the
+     *                          rows of the grid of the RecyclerView
+     * @param verticalDivider A divider {@code Drawable} to be drawn on the
+     *                        columns of the grid of the RecyclerView
+     * @param numColumns The number of columns in the grid of the RecyclerView
+     */
+    public GridDividerItemDecoration(Drawable horizontalDivider, Drawable verticalDivider, int numColumns) {
+        mHorizontalDivider = horizontalDivider;
+        mVerticalDivider = verticalDivider;
+        mNumColumns = numColumns;
+    }
+
+    /**
+     * Draws horizontal and/or vertical dividers onto the parent RecyclerView.
+     *
+     * @param canvas The {@link Canvas} onto which dividers will be drawn
+     * @param parent The RecyclerView onto which dividers are being added
+     * @param state The current RecyclerView.State of the RecyclerView
+     */
+    @Override
+    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
+        drawHorizontalDividers(canvas, parent);
+//        drawVerticalDividers(canvas, parent);
+
+    }
+
+    /**
+     * Determines the size and location of offsets between items in the parent
+     * RecyclerView.
+     *
+     * @param outRect The {@link Rect} of offsets to be added around the child view
+     * @param view The child view to be decorated with an offset
+     * @param parent The RecyclerView onto which dividers are being added
+     * @param state The current RecyclerView.State of the RecyclerView
+     */
+    @Override
+    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+        super.getItemOffsets(outRect, view, parent, state);
+
+        boolean childIsInLeftmostColumn = (parent.getChildAdapterPosition(view) % mNumColumns) == 0;
+        if (!childIsInLeftmostColumn) {
+            outRect.left = mHorizontalDivider.getIntrinsicWidth();
+        }
+
+        boolean childIsInFirstRow = (parent.getChildAdapterPosition(view)) < mNumColumns;
+        if (!childIsInFirstRow) {
+            outRect.top = mVerticalDivider.getIntrinsicHeight();
+        }
+    }
+
+    /**
+     * Adds horizontal dividers to a RecyclerView with a GridLayoutManager or its
+     * subclass.
+     *
+     * @param canvas The {@link Canvas} onto which dividers will be drawn
+     * @param parent The RecyclerView onto which dividers are being added
+     */
+    private void drawHorizontalDividers(Canvas canvas, RecyclerView parent) {
+        int childCount = parent.getChildCount();
+        int rowCount = childCount / mNumColumns;
+        int lastRowChildCount = childCount % mNumColumns;
+
+        for (int i = 1; i < mNumColumns; i++) {
+            int lastRowChildIndex;
+            if (i < lastRowChildCount) {
+                lastRowChildIndex = i + (rowCount * mNumColumns);
+            } else {
+                lastRowChildIndex = i + ((rowCount - 1) * mNumColumns);
+            }
+
+            View firstRowChild = parent.getChildAt(i);
+            View lastRowChild = parent.getChildAt(lastRowChildIndex);
+
+            int dividerTop = firstRowChild.getTop();
+            int dividerRight = firstRowChild.getLeft();
+            int dividerLeft = dividerRight - mHorizontalDivider.getIntrinsicWidth();
+            int dividerBottom = lastRowChild.getBottom();
+
+            mHorizontalDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
+            mHorizontalDivider.draw(canvas);
+        }
+    }
+
+    /**
+     * Adds vertical dividers to a RecyclerView with a GridLayoutManager or its
+     * subclass.
+     *
+     * @param canvas The {@link Canvas} onto which dividers will be drawn
+     * @param parent The RecyclerView onto which dividers are being added
+     */
+    private void drawVerticalDividers(Canvas canvas, RecyclerView parent) {
+        int childCount = parent.getChildCount();
+        int rowCount = childCount / mNumColumns;
+        int rightmostChildIndex;
+        for (int i = 1; i <= rowCount; i++) {
+            if (i == rowCount) {
+                rightmostChildIndex = parent.getChildCount() - 1;
+            } else {
+                rightmostChildIndex = (i * mNumColumns) + mNumColumns - 1;
+            }
+
+            View leftmostChild = parent.getChildAt(i * mNumColumns);
+            View rightmostChild = parent.getChildAt(rightmostChildIndex);
+
+            int dividerLeft = leftmostChild.getLeft();
+            int dividerBottom = leftmostChild.getTop();
+            int dividerTop = dividerBottom - mVerticalDivider.getIntrinsicHeight();
+            int dividerRight = rightmostChild.getRight();
+
+            mVerticalDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
+            mVerticalDivider.draw(canvas);
+        }
+    }
+}

+ 205 - 0
app/src/main/java/com/khmer9/lotto/util/MiddleDividerItemDecoration.kt

@@ -0,0 +1,205 @@
+package com.khmer9.lotto.util
+
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.util.Log
+import android.view.View
+import android.widget.LinearLayout
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * MiddleDividerItemDecoration is a [RecyclerView.ItemDecoration] that can be used as a divider
+ * between items of a [LinearLayoutManager]. It supports both [.HORIZONTAL] and
+ * [.VERTICAL] orientations.
+ * It can also supports [.ALL], included both the horizontal and vertical. Mainly used for GridLayout.
+ * <pre>
+ * For normal usage with LinearLayout,
+ * val mItemDecoration = MiddleDividerItemDecoration(context!!,DividerItemDecoration.VERTICAL)
+ * For GridLayoutManager with inner decorations,
+ * val mItemDecoration = MiddleDividerItemDecoration(context!!,MiddleDividerItemDecoration.ALL)
+ * recyclerView.addItemDecoration(mItemDecoration);
+</pre> *
+ */
+class MiddleDividerItemDecoration
+/**
+ * Creates a divider [RecyclerView.ItemDecoration] that can be used with a
+ * [LinearLayoutManager].
+ *
+ * @param context Current context, it will be used to access resources.
+ * @param orientation Divider orientation. Should be [.HORIZONTAL] or [.VERTICAL].
+ */
+    (context: Context, orientation: Int) : RecyclerView.ItemDecoration() {
+
+    private var mDivider: Drawable? = null
+
+    /**
+     * Current orientation. Either [.HORIZONTAL] or [.VERTICAL].
+     */
+    private var mOrientation: Int = 0
+
+    private val mBounds = Rect()
+
+    init {
+        val a = context.obtainStyledAttributes(ATTRS)
+        mDivider = a.getDrawable(0)
+        if (mDivider == null) {
+            Log.w(
+                TAG,
+                "@android:attr/listDivider was not set in the theme used for this " + "DividerItemDecoration. Please set that attribute all call setDrawable()"
+            )
+        }
+        a.recycle()
+        setOrientation(orientation)
+    }
+
+    fun setDividerColor(color: Int) {
+        mDivider!!.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.ADD)
+    }
+
+    /**
+     * Sets the orientation for this divider. This should be called if
+     * [RecyclerView.LayoutManager] changes orientation.
+     *
+     * @param orientation [.HORIZONTAL] or [.VERTICAL]
+     */
+    fun setOrientation(orientation: Int) {
+        if (orientation != HORIZONTAL && orientation != VERTICAL && orientation != ALL) {
+            throw IllegalArgumentException(
+                "Invalid orientation. It should be either HORIZONTAL or VERTICAL"
+            )
+        }
+        mOrientation = orientation
+    }
+
+    /**
+     * Sets the [Drawable] for this divider.
+     *
+     * @param drawable Drawable that should be used as a divider.
+     */
+    fun setDrawable(drawable: Drawable) {
+        mDivider = drawable
+    }
+
+    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
+        if (parent.layoutManager == null || mDivider == null) {
+            return
+        }
+
+        when (mOrientation) {
+            ALL -> {
+                drawVertical(c, parent)
+                drawHorizontal(c, parent)
+            }
+            VERTICAL -> drawVertical(c, parent)
+            else -> drawHorizontal(c, parent)
+        }
+    }
+
+    private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
+        canvas.save()
+        val left: Int
+        val right: Int
+
+        if (parent.clipToPadding) {
+            left = parent.paddingLeft
+            right = parent.width - parent.paddingRight
+            canvas.clipRect(
+                left, parent.paddingTop, right,
+                parent.height - parent.paddingBottom
+            )
+        } else {
+            left = 0
+            right = parent.width
+        }
+
+        var childCount = parent.childCount
+        if (parent.layoutManager is GridLayoutManager) {
+            var leftItems = childCount % (parent.layoutManager as GridLayoutManager).spanCount
+            if (leftItems == 0) {
+                leftItems = (parent.layoutManager as GridLayoutManager).spanCount
+            }
+            //Identify last row, and don't draw border for these items
+            childCount -= leftItems
+        }
+
+        for (i in 0 until childCount - 1) {
+            val child = parent.getChildAt(i) ?: return
+            parent.getDecoratedBoundsWithMargins(child, mBounds)
+            val bottom = mBounds.bottom + Math.round(child.translationY)
+            val top = bottom - mDivider!!.intrinsicHeight
+            mDivider!!.setBounds(left, top, right, bottom)
+            mDivider!!.draw(canvas)
+        }
+        canvas.restore()
+    }
+
+    private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
+        canvas.save()
+        val top: Int
+        val bottom: Int
+
+        if (parent.clipToPadding) {
+            top = parent.paddingTop
+            bottom = parent.height - parent.paddingBottom
+            canvas.clipRect(
+                parent.paddingLeft, top,
+                parent.width - parent.paddingRight, bottom
+            )
+        } else {
+            top = 0
+            bottom = parent.height
+        }
+
+        var childCount = parent.childCount
+        if (parent.layoutManager is GridLayoutManager) {
+            childCount = (parent.layoutManager as GridLayoutManager).spanCount
+        }
+
+        for (i in 0 until childCount - 1) {
+            val child = parent.getChildAt(i) ?: return
+            parent.layoutManager!!.getDecoratedBoundsWithMargins(child, mBounds)
+            val right = mBounds.right + Math.round(child.translationX)
+            val left = right - mDivider!!.intrinsicWidth
+            mDivider!!.setBounds(left, top, right, bottom)
+            mDivider!!.draw(canvas)
+        }
+        canvas.restore()
+    }
+
+    override fun getItemOffsets(
+        outRect: Rect, view: View, parent: RecyclerView,
+        state: RecyclerView.State
+    ) {
+        if (mDivider == null) {
+            outRect.set(0, 0, 0, 0)
+            return
+        }
+        if (mOrientation == ALL){
+            outRect.set(mDivider!!.intrinsicWidth/2,  mDivider!!.intrinsicHeight/2, mDivider!!.intrinsicWidth/2,  mDivider!!.intrinsicHeight/2)
+
+
+        }
+//        if (mOrientation == VERTICAL) {
+//            outRect.set(0, 0, 0, mDivider!!.intrinsicHeight)
+//        } else {
+//            outRect.set(0, 0, mDivider!!.intrinsicWidth, 0)
+//        }
+        //when (mOrientation) { ALL -> { outRect.set(0, 0, mDivider!!.intrinsicWidth, mDivider!!.intrinsicHeight) } VERTICAL -> {outRect.set(0, 0, 0, mDivider!!.intrinsicHeight) } else -> { outRect.set(0, 0, mDivider!!.intrinsicWidth, 0) } }
+    }
+
+    companion object {
+        val HORIZONTAL = LinearLayout.HORIZONTAL
+        val VERTICAL = LinearLayout.VERTICAL
+        //mainly used for GridLayoutManager
+        val ALL = 2
+
+        private val TAG = "DividerItem"
+        private val ATTRS = intArrayOf(android.R.attr.listDivider)
+    }
+}

+ 81 - 0
app/src/main/java/com/khmer9/lotto/util/ModelPreferencesManager.kt

@@ -0,0 +1,81 @@
+package com.khmer9.lotto.util
+
+
+import android.app.Application
+import android.content.Context
+import android.content.SharedPreferences
+import com.google.gson.GsonBuilder
+import com.google.gson.reflect.TypeToken
+import com.khmer9.lotto.remote.LottoSet
+
+
+/**
+ * Singleton class for managing preferences for POJO or model class's object.
+
+ */
+object ModelPreferencesManager {
+
+    //Shared Preference field used to save and retrieve JSON string
+    lateinit var preferences: SharedPreferences
+
+    //Name of Shared Preference file
+    private const val PREFERENCES_FILE_NAME = "PREFERENCES_MODEL_FILE"
+
+    /**
+     * Call this first before retrieving or saving object.
+     *
+     * @param application Instance of application class
+     */
+    fun with(application: Application) {
+        preferences = application.getSharedPreferences(
+            PREFERENCES_FILE_NAME, Context.MODE_PRIVATE)
+    }
+
+    /**
+     * Saves object into the Preferences.
+     *
+     * @param `object` Object of model class (of type [T]) to save
+     * @param key Key with which Shared preferences to
+     **/
+    fun <T> put(`object`: T, key: String) {
+        //Convert object to JSON String.
+        val jsonString = GsonBuilder().create().toJson(`object`)
+        //Save that String in SharedPreferences
+        preferences.edit().putString(key, jsonString).apply()
+    }
+    fun putList(list: List<LottoSet>, key: String) {
+        val jsonString = GsonBuilder().create().toJson(list)
+
+        preferences.edit().putString(key, jsonString).apply()
+    }
+    /**
+     * Used to retrieve object from the Preferences.
+     *
+     * @param key Shared Preference key with which object was saved.
+     **/
+     fun  getList(key: String): List<LottoSet>? {
+        val value = preferences.getString(key, null)
+        val type = object : TypeToken<List<LottoSet>>() {}.type
+        return GsonBuilder().create().fromJson<List<LottoSet>>(value, type)
+
+    }
+
+    inline fun <reified T> get(key: String): T? {
+        //We read JSON String which was saved.
+        val value = preferences.getString(key, null)
+        //JSON String was found which means object can be read.
+        //We convert this JSON String to model object. Parameter "c" (of
+        //type Class < T >" is used to cast.
+        return GsonBuilder().create().fromJson(value, T::class.java)
+    }
+//    fun saveLottoToSharedPrefs(lottoSetList: List<LottoSet>) {
+//        //val gson = Gson()
+//        val json = GsonBuilder().create().toJson(lottoSetList)
+//        preferences.edit().putString(Const.LOTTO_KEY, json).apply()
+//    }
+//    fun getLottoFromSharedPrefs(): List<*>? {
+//        val json = preferences.getString(Const.LOTTO_KEY, null)
+//        val tasks = GsonBuilder().create().fromJson<Any>(json, object : TypeToken<ArrayList<LottoSet>?>() {}.type)
+//        return tasks as List<*>?
+//    }
+}

+ 42 - 0
app/src/main/java/com/khmer9/lotto/util/PrefHelper.kt

@@ -0,0 +1,42 @@
+package com.khmer9.lotto.util
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.khmer9.lotto.util.Const.Companion.AUTO_PRINT_KEY
+import com.khmer9.lotto.util.Const.Companion.MAX_KEY
+import com.khmer9.lotto.util.Const.Companion.MIN_KEY
+import com.khmer9.lotto.util.Const.Companion.MUTE_KEY
+import com.khmer9.lotto.util.Const.Companion.TOKEN_KEY
+
+
+class PrefHelper constructor(val context: Context) {
+
+
+    private var sharedPreferences: SharedPreferences =
+        context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
+
+    fun setIsMute(value: Boolean) = sharedPreferences.edit().putBoolean(MUTE_KEY, value).apply()
+    fun setIsAutoPrint(value: Boolean) = sharedPreferences.edit().putBoolean(AUTO_PRINT_KEY, value).apply()
+
+    fun setUserToken(token: String) = sharedPreferences.edit().putString(TOKEN_KEY, token).apply()
+
+    fun getIsMute() = sharedPreferences.getBoolean(MUTE_KEY, false)
+    fun getIsAutoPrint() = sharedPreferences.getBoolean(AUTO_PRINT_KEY, false)
+
+    fun setMinBetting(value: Int) = sharedPreferences.edit().putInt(MIN_KEY, value).apply()
+    fun setMaxBetting(value: Int) = sharedPreferences.edit().putInt(MAX_KEY, value).apply()
+
+    fun getMinBetting() =
+        sharedPreferences.getInt(MIN_KEY, 0)
+
+    fun getMaxBetting() =
+        sharedPreferences.getInt(MAX_KEY, 0)
+
+
+    fun getToken() =
+        sharedPreferences.getString(TOKEN_KEY, "") ?: ""
+
+    fun logout() {
+        sharedPreferences.edit().remove(TOKEN_KEY).apply()
+    }
+}

+ 18 - 0
app/src/main/java/com/khmer9/lotto/util/SafeClickListener.kt

@@ -0,0 +1,18 @@
+package com.khmer9.lotto.util
+
+import android.os.SystemClock
+import android.view.View
+
+class SafeClickListener(
+    private var defaultInterval: Int = 1000,
+    private val onSafeCLick: (View) -> Unit
+) : View.OnClickListener {
+    private var lastTimeClicked: Long = 0
+    override fun onClick(v: View) {
+        if (SystemClock.elapsedRealtime() - lastTimeClicked < defaultInterval) {
+            return
+        }
+        lastTimeClicked = SystemClock.elapsedRealtime()
+        onSafeCLick(v)
+    }
+}

+ 63 - 0
app/src/main/java/com/khmer9/lotto/util/UnsafeOkHttpClient.java

@@ -0,0 +1,63 @@
+package com.khmer9.lotto.util;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import okhttp3.OkHttpClient;
+import okhttp3.logging.HttpLoggingInterceptor;
+import timber.log.Timber;
+
+public class UnsafeOkHttpClient {
+    public static OkHttpClient getClient() {
+        try {
+            // Create a trust manager that does not validate certificate chains
+            final TrustManager[] trustAllCerts = new TrustManager[]{
+                    new X509TrustManager() {
+                        @Override
+                        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+
+                        }
+
+                        @Override
+                        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+
+                        }
+
+                        @Override
+                        public X509Certificate[] getAcceptedIssuers() {
+                            return new X509Certificate[]{};
+                        }
+                    }
+            };
+
+            // Install the all-trusting trust manager
+            final SSLContext sslContext = SSLContext.getInstance("SSL");
+            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+
+            // Create an ssl socket factory with our all-trusting manager
+            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+            OkHttpClient.Builder builder = new OkHttpClient.Builder();
+            //if (BuildConfig.DEBUG) {
+                //builder.addInterceptor(new OkHttpProfilerInterceptor());
+           // }
+            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
+            builder.hostnameVerifier((hostname, session) -> true);
+
+            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> {
+                Timber.d("===> " + message);
+            });
+            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+            builder.addInterceptor(loggingInterceptor);
+
+            return builder.build();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 81 - 0
app/src/main/java/com/khmer9/lotto/view/CircleView.java

@@ -0,0 +1,81 @@
+package com.khmer9.lotto.view;
+
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.khmer9.lotto.R;
+
+public class CircleView  extends ConstraintLayout {
+    ImageView imageViewLoto;
+    TextView tvValue;
+
+    public CircleView(@NonNull Context context) {
+        super(context);
+        init();
+
+    }
+
+    public CircleView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init();
+        setStyle(attrs);
+
+    }
+
+    public CircleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+        setStyle(attrs);
+    }
+
+    public CircleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+        setStyle(attrs);
+    }
+    private void init() {
+        View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.view_circle, this, true);
+        imageViewLoto = view.findViewById(R.id.iv_logo) ;
+        tvValue = view.findViewById(R.id.tv_value);
+
+    }
+
+    private void setStyle(AttributeSet attrs){
+        TypedArray a = getContext().getTheme().obtainStyledAttributes(
+                attrs,
+                R.styleable.CircleView,
+                0, 0);
+
+        try {
+           // Drawable drawable = a.getDrawable(R.styleable.CircleView_currencyImage);
+            int symbol_resID = a.getResourceId(R.styleable.CircleView_currencyImage, R.drawable.text_k);
+            imageViewLoto.setImageResource(symbol_resID);
+            String text = a.getString(R.styleable.CircleView_currencyValue);
+           // imageViewLoto.setBackground(drawable);
+            tvValue.setText(text);
+
+        } finally {
+            a.recycle();
+        }
+    }
+//    public boolean isShowText() {
+//        return mShowText;
+//    }
+//
+//    public void setShowText(boolean showText) {
+//        mShowText = showText;
+//        invalidate();
+//        requestLayout();
+//    }
+}

+ 40 - 0
app/src/main/java/com/khmer9/lotto/view/LottoView.java

@@ -0,0 +1,40 @@
+package com.khmer9.lotto.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import com.khmer9.lotto.R;
+
+public class LottoView  extends FrameLayout {
+    public View vBox;
+
+    public LottoView(@NonNull Context context) {
+        super(context);
+        init();
+    }
+
+    public LottoView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public LottoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    public LottoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+    private void init() {
+        View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.view_lotto, this, true);
+        vBox = view.findViewById(R.id.v_box);
+
+    }
+}

+ 21 - 0
app/src/main/java/com/khmer9/lotto/view/MaterialTextBTB.kt

@@ -0,0 +1,21 @@
+package com.khmer9.lotto.util
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.core.content.res.ResourcesCompat
+import com.google.android.material.textfield.TextInputEditText
+import com.khmer9.lotto.R
+
+class MaterialEditTextBTB : TextInputEditText {
+    constructor(context: Context) : super(context)
+    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
+    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
+        context,
+        attributeSet,
+        defStyleAttr
+    )
+
+    init {
+        setTypeface(ResourcesCompat.getFont(context, R.font.kh_battambang), typeface?.style ?: 0)
+    }
+}

+ 75 - 0
app/src/main/java/com/khmer9/lotto/view/NoPaddingTextView.java

@@ -0,0 +1,75 @@
+package com.khmer9.lotto.view;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+
+import com.google.android.material.textview.MaterialTextView;
+
+public class NoPaddingTextView extends MaterialTextView {
+
+    private int mAdditionalPadding;
+
+    public NoPaddingTextView(Context context) {
+        super(context);
+        init();
+    }
+
+
+    public NoPaddingTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init() {
+        setIncludeFontPadding(false);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int yOff = -mAdditionalPadding / 6;
+        canvas.translate(0, yOff);
+        super.onDraw(canvas);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        getAdditionalPadding();
+
+        int mode = MeasureSpec.getMode(heightMeasureSpec);
+        if (mode != MeasureSpec.EXACTLY) {
+            int measureHeight = measureHeight(getText().toString(), widthMeasureSpec);
+
+            int height = measureHeight - mAdditionalPadding;
+            height += getPaddingTop() + getPaddingBottom();
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    private int measureHeight(String text, int widthMeasureSpec) {
+        float textSize = getTextSize();
+
+        MaterialTextView textView = new MaterialTextView(getContext());
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+        textView.setText(text);
+        textView.measure(widthMeasureSpec, 0);
+        return textView.getMeasuredHeight();
+    }
+
+    private int getAdditionalPadding() {
+        float textSize = getTextSize();
+
+        MaterialTextView textView = new MaterialTextView(getContext());
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+        textView.setLines(1);
+        textView.measure(0, 0);
+        int measuredHeight = textView.getMeasuredHeight();
+        if (measuredHeight - textSize > 0) {
+            mAdditionalPadding = (int) (measuredHeight - textSize);
+            Log.v("NoPaddingTextView", "onMeasure: height=" + measuredHeight + " textSize=" + textSize + " mAdditionalPadding=" + mAdditionalPadding);
+        }
+        return mAdditionalPadding;
+    }
+}

+ 76 - 0
app/src/main/java/com/khmer9/lotto/view/RectangleView.java

@@ -0,0 +1,76 @@
+package com.khmer9.lotto.view;
+
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.khmer9.lotto.R;
+
+public class RectangleView  extends ConstraintLayout {
+    ImageView imageViewLoto;
+    TextView tvValue;
+    ConstraintLayout bgView;
+
+    public RectangleView(@NonNull Context context) {
+        super(context);
+        init();
+
+    }
+
+    public RectangleView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init();
+        setStyle(attrs);
+
+    }
+
+    public RectangleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+        setStyle(attrs);
+    }
+
+    public RectangleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+        setStyle(attrs);
+    }
+    private void init() {
+        View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.view_rectangle, this, true);
+        bgView = view.findViewById(R.id.iv_bg);
+        imageViewLoto = view.findViewById(R.id.iv_logo) ;
+        tvValue = view.findViewById(R.id.tv_value);
+
+    }
+
+    private void setStyle(AttributeSet attrs){
+        TypedArray a = getContext().getTheme().obtainStyledAttributes(
+                attrs,
+                R.styleable.RectangleView,
+                0, 0);
+
+        try {
+             Drawable bgDrawable = a.getDrawable(R.styleable.RectangleView_bgImage);
+            int bigSmall_resID = a.getResourceId(R.styleable.RectangleView_bigSmallImage, R.drawable.btn_rectangle_blue);
+            String textRange = a.getString(R.styleable.RectangleView_rangeNumber);
+            bgView.setBackground(bgDrawable);
+            imageViewLoto.setImageResource(bigSmall_resID);
+            tvValue.setText(textRange);
+
+        } finally {
+            a.recycle();
+        }
+    }
+
+}

+ 44 - 0
app/src/main/java/com/khmer9/lotto/view/ResultView.java

@@ -0,0 +1,44 @@
+package com.khmer9.lotto.view;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.khmer9.lotto.R;
+
+public class ResultView  extends FrameLayout {
+    public View vBox;
+    public TextView tvResult;
+
+    public ResultView(@NonNull Context context) {
+        super(context);
+        init();
+    }
+
+    public ResultView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public ResultView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    public ResultView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+    private void init() {
+        View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.view_result, this, true);
+        vBox = view.findViewById(R.id.v_box);
+        tvResult = view.findViewById(R.id.tv_result);
+
+    }
+}

+ 77 - 0
app/src/main/java/com/khmer9/lotto/view/SettingButtonView.java

@@ -0,0 +1,77 @@
+package com.khmer9.lotto.view;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+
+import com.khmer9.lotto.R;
+
+public class SettingButtonView  extends FrameLayout {
+    ImageView imageViewIcon;
+    View bgView;
+
+    public SettingButtonView(@NonNull Context context) {
+        super(context);
+        init();
+
+    }
+
+    public SettingButtonView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init();
+        setStyle(attrs);
+
+    }
+
+    public SettingButtonView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+        setStyle(attrs);
+    }
+
+    public SettingButtonView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+        setStyle(attrs);
+    }
+    private void init() {
+        View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.view_setting_button, this, true);
+        bgView = view.findViewById(R.id.v_bg);
+        imageViewIcon = view.findViewById(R.id.iv_icon) ;
+
+
+    }
+
+    private void setStyle(AttributeSet attrs){
+        TypedArray a = getContext().getTheme().obtainStyledAttributes(
+                attrs,
+                R.styleable.SettingButtonView,
+                0, 0);
+
+        try {
+            Drawable bgDrawable = a.getDrawable(R.styleable.SettingButtonView_bgDrawable);
+            int bigSmall_resID = a.getResourceId(R.styleable.SettingButtonView_textIcon, R.drawable.text_save);
+            bgView.setBackground(bgDrawable);
+            imageViewIcon.setImageResource(bigSmall_resID);
+
+        } finally {
+            a.recycle();
+        }
+    }
+
+    public void setImageViewIcon(@DrawableRes int drawable) {
+        imageViewIcon.setImageResource(drawable);
+    }
+}

+ 64 - 0
app/src/main/java/com/khmer9/lotto/view/SquareView.java

@@ -0,0 +1,64 @@
+package com.khmer9.lotto.view;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import com.khmer9.lotto.R;
+
+public class SquareView  extends ConstraintLayout {
+    TextView tvNumber;
+    TextView tvRangNumber;
+
+    public SquareView(@NonNull Context context) {
+        super(context);
+        init();
+
+    }
+
+    public SquareView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init();
+        setStyle(attrs);
+
+    }
+
+    public SquareView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+        setStyle(attrs);
+    }
+
+    public SquareView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+        setStyle(attrs);
+    }
+    private void init() {
+        View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.view_square, this, true);
+        tvNumber = view.findViewById(R.id.tv_number) ;
+        tvRangNumber = view.findViewById(R.id.tv_range);
+
+    }
+    private void setStyle(AttributeSet attrs){
+        TypedArray a = getContext().getTheme().obtainStyledAttributes(
+                attrs,
+                R.styleable.SquareView,
+                0, 0);
+        try {
+            String textNumber = a.getString(R.styleable.SquareView_numberValue);
+            String textRangeNumber = a.getString(R.styleable.SquareView_rangNumber);
+            tvNumber.setText(textNumber);
+            tvRangNumber.setText(textRangeNumber);
+
+        } finally {
+            a.recycle();
+        }
+    }
+
+}

+ 8 - 0
app/src/main/res/anim/blink.xml

@@ -0,0 +1,8 @@
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha android:fromAlpha="0.0"
+        android:toAlpha="1.0"
+        android:interpolator="@android:anim/accelerate_interpolator"
+        android:duration="600"
+        android:repeatMode="reverse"
+        android:repeatCount="0"/>
+</set>

+ 10 - 0
app/src/main/res/anim/fade_in.xml

@@ -0,0 +1,10 @@
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fillAfter="true" >
+
+    <alpha
+        android:duration="1000"
+        android:fromAlpha="0.0"
+        android:interpolator="@android:anim/accelerate_interpolator"
+        android:toAlpha="1.0" />
+
+</set>

+ 11 - 0
app/src/main/res/anim/rotation.xml

@@ -0,0 +1,11 @@
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <rotate android:fromDegrees="0"
+        android:toDegrees="360"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:duration="400"
+        android:repeatMode="restart"
+        android:repeatCount="infinite"
+        android:interpolator="@android:anim/cycle_interpolator"/>
+
+</set>

Some files were not shown because too many files changed in this diff