Dola TENG 1 yıl önce
işleme
467ea65dde
100 değiştirilmiş dosya ile 8029 ekleme ve 0 silme
  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. 20 0
      .idea/gradle.xml
  8. 35 0
      .idea/jarRepositories.xml
  9. 6 0
      .idea/kotlinc.xml
  10. 81 0
      .idea/misc.xml
  11. 6 0
      .idea/vcs.xml
  12. 1 0
      app/.gitignore
  13. 150 0
      app/build.gradle
  14. BIN
      app/dev/release/SBC-Mobile_devRelease_1.0.0-dev.apk
  15. 18 0
      app/dev/release/output-metadata.json
  16. 39 0
      app/google-services.json
  17. BIN
      app/prod/debug/App_prodDebug_1.0_1.apk
  18. 18 0
      app/prod/debug/output-metadata.json
  19. BIN
      app/prod/release/SBC-Mobile_prodRelease_1.0.0.apk
  20. 18 0
      app/prod/release/output-metadata.json
  21. 146 0
      app/proguard-rules.pro
  22. 24 0
      app/src/androidTest/java/com/sambath/sbc/ExampleInstrumentedTest.kt
  23. 10 0
      app/src/dev/java/com/sambath/sbc/config/Config.kt
  24. 49 0
      app/src/main/AndroidManifest.xml
  25. BIN
      app/src/main/ic_launcher-playstore.png
  26. 47 0
      app/src/main/java/com/sambath/sbc/adapter/AbstractAdapter.kt
  27. 23 0
      app/src/main/java/com/sambath/sbc/adapter/AbstractViewHolder.kt
  28. 31 0
      app/src/main/java/com/sambath/sbc/adapter/BaseListAdapter.kt
  29. 17 0
      app/src/main/java/com/sambath/sbc/adapter/BaseListItem.kt
  30. 49 0
      app/src/main/java/com/sambath/sbc/adapter/BaseListViewHolder.kt
  31. 31 0
      app/src/main/java/com/sambath/sbc/adapter/MainPagerAdapter.kt
  32. 116 0
      app/src/main/java/com/sambath/sbc/app/App.kt
  33. 41 0
      app/src/main/java/com/sambath/sbc/app/ErrorInterceptor.kt
  34. 14 0
      app/src/main/java/com/sambath/sbc/app/ExceptionExtension.kt
  35. 23 0
      app/src/main/java/com/sambath/sbc/app/ServiceInterceptor.kt
  36. 375 0
      app/src/main/java/com/sambath/sbc/app/ShareActivity.kt
  37. 163 0
      app/src/main/java/com/sambath/sbc/app/ShareViewModel.kt
  38. 19 0
      app/src/main/java/com/sambath/sbc/app/ShareViewState.kt
  39. 45 0
      app/src/main/java/com/sambath/sbc/base/AutoLogoutBaseActivity.kt
  40. 54 0
      app/src/main/java/com/sambath/sbc/base/BaseActivity.kt
  41. 715 0
      app/src/main/java/com/sambath/sbc/base/BaseFragment.kt
  42. 13 0
      app/src/main/java/com/sambath/sbc/base/BaseViewModel.kt
  43. 209 0
      app/src/main/java/com/sambath/sbc/extension/ViewExtensions.kt
  44. 28 0
      app/src/main/java/com/sambath/sbc/remote/CfModel.kt
  45. 32 0
      app/src/main/java/com/sambath/sbc/remote/K.kt
  46. 628 0
      app/src/main/java/com/sambath/sbc/remote/LoginDataModel.kt
  47. 415 0
      app/src/main/java/com/sambath/sbc/remote/MainDataModel.kt
  48. 93 0
      app/src/main/java/com/sambath/sbc/remote/PlayDataModel.kt
  49. 153 0
      app/src/main/java/com/sambath/sbc/remote/ReportDataModel.kt
  50. 126 0
      app/src/main/java/com/sambath/sbc/remote/ResultDataModel.kt
  51. 15 0
      app/src/main/java/com/sambath/sbc/remote/SocketMessageDataModel.kt
  52. 30 0
      app/src/main/java/com/sambath/sbc/remote/UpdatePwdDataModel.kt
  53. 66 0
      app/src/main/java/com/sambath/sbc/remote/service/ApiService.kt
  54. 19 0
      app/src/main/java/com/sambath/sbc/remote/service/ConnectivityStates.java
  55. 29 0
      app/src/main/java/com/sambath/sbc/remote/service/EventListener.java
  56. 141 0
      app/src/main/java/com/sambath/sbc/remote/service/SocketService.java
  57. 71 0
      app/src/main/java/com/sambath/sbc/screen/login/LoginActivity.kt
  58. 67 0
      app/src/main/java/com/sambath/sbc/screen/login/LoginViewModel.kt
  59. 8 0
      app/src/main/java/com/sambath/sbc/screen/login/LoginViewState.kt
  60. 21 0
      app/src/main/java/com/sambath/sbc/screen/main/MainAdapter.kt
  61. 22 0
      app/src/main/java/com/sambath/sbc/screen/main/MainDataViewState.kt
  62. 170 0
      app/src/main/java/com/sambath/sbc/screen/main/MainFragment.kt
  63. 10 0
      app/src/main/java/com/sambath/sbc/screen/main/MainListItem.kt
  64. 75 0
      app/src/main/java/com/sambath/sbc/screen/main/MainListViewHolder.kt
  65. 122 0
      app/src/main/java/com/sambath/sbc/screen/main/MainViewModel.kt
  66. 444 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/Betting/CfBetFragment.kt
  67. 173 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/Betting/CfBetViewModel.kt
  68. 37 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/Betting/CfBetViewState.kt
  69. 18 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsAdapter.kt
  70. 113 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsFragment.kt
  71. 62 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsListViewHolder.kt
  72. 45 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsViewModel.kt
  73. 10 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsViewState.kt
  74. 193 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/result/CfResultFragment.kt
  75. 55 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/result/CfResultViewModel.kt
  76. 13 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/result/CfResultViewState.kt
  77. 301 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/StatementDialogFragment.kt
  78. 43 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/StatementDialogViewModel.kt
  79. 10 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/StatementDialogViewState.kt
  80. 66 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/report/ReportAdapter.kt
  81. 189 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/report/ReportListViewHolder.kt
  82. 15 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/report/ReportViewState.kt
  83. 16 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportAdapter.kt
  84. 67 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportFragment.kt
  85. 141 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportListViewHolder.kt
  86. 45 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportViewModel.kt
  87. 10 0
      app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportViewState.kt
  88. 16 0
      app/src/main/java/com/sambath/sbc/screen/report/StatementAdapter.kt
  89. 410 0
      app/src/main/java/com/sambath/sbc/screen/report/StatementFragment.kt
  90. 67 0
      app/src/main/java/com/sambath/sbc/screen/report/StatementListViewHolder.kt
  91. 41 0
      app/src/main/java/com/sambath/sbc/screen/report/StatementViewModel.kt
  92. 10 0
      app/src/main/java/com/sambath/sbc/screen/report/StatementViewState.kt
  93. 10 0
      app/src/main/java/com/sambath/sbc/screen/result/ResultViewState.kt
  94. 17 0
      app/src/main/java/com/sambath/sbc/screen/result/Table1Adapter.kt
  95. 11 0
      app/src/main/java/com/sambath/sbc/screen/result/Table1ListItem.kt
  96. 38 0
      app/src/main/java/com/sambath/sbc/screen/result/Table1ListViewHolder.kt
  97. 20 0
      app/src/main/java/com/sambath/sbc/screen/result/Table2Adapter.kt
  98. 11 0
      app/src/main/java/com/sambath/sbc/screen/result/Table2ListItem.kt
  99. 47 0
      app/src/main/java/com/sambath/sbc/screen/result/Table2ListViewHolder.kt
  100. 167 0
      app/src/main/java/com/sambath/sbc/screen/setting/SettingFragment.kt

+ 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>

+ 20 - 0
.idea/gradle.xml

@@ -0,0 +1,20 @@
+<?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>
+      </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>

+ 6 - 0
.idea/kotlinc.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="KotlinJpsPluginSettings">
+    <option name="version" value="1.6.21" />
+  </component>
+</project>

+ 81 - 0
.idea/misc.xml

@@ -0,0 +1,81 @@
+<project version="4">
+  <component name="DesignSurface">
+    <option name="filePathToZoomLevelMap">
+      <map>
+        <entry key="..\:/3-Work/Android/sbc-mobile/app/src/main/res/drawable/ic_baseline_add_circle_24.xml" value="0.333" />
+        <entry key="..\:/3-Work/Android/sbc-mobile/app/src/main/res/drawable/stroke_result.xml" value="0.3675" />
+        <entry key="..\:/3-Work/Android/sbc-mobile/app/src/main/res/layout/app_bar.xml" value="0.36666666666666664" />
+        <entry key="..\:/3-Work/Android/sbc-mobile/app/src/main/res/layout/fragment_cf_betting.xml" value="0.36666666666666664" />
+        <entry key="..\:/3-Work/Android/sbc-mobile/app/src/main/res/layout/fragment_cf_result.xml" value="0.36666666666666664" />
+        <entry key="..\:/3-Work/Android/sbc-mobile/app/src/main/res/layout/item_box.xml" value="0.36666666666666664" />
+        <entry key="..\:/AndroidStudioProjects/sbc-mobile/app/src/main/res/layout/app_bar.xml" value="0.20416666666666666" />
+        <entry key="..\:/AndroidStudioProjects/sbc-mobile/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.2203125" />
+        <entry key="..\:/AndroidStudioProjects/sbc-mobile/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.2203125" />
+        <entry key="..\:/PartTimeProject/CFLive/app/src/main/res/layout/activity_login.xml" value="0.28442028985507245" />
+        <entry key="..\:/PartTimeProject/CFLive/app/src/main/res/layout/activity_main.xml" value="0.28442028985507245" />
+        <entry key="..\:/PartTimeProject/CFLive/app/src/main/res/layout/activity_splash.xml" value="0.28442028985507245" />
+        <entry key="..\:/PartTimeProject/CFLive/app/src/main/res/layout/content_main.xml" value="0.28442028985507245" />
+        <entry key="..\:/PartTimeProject/CFLive/app/src/main/res/layout/fragment_cf_betting.xml" value="0.28306159420289856" />
+        <entry key="..\:/PartTimeProject/CFLive/app/src/main/res/layout/fragment_cf_result.xml" value="0.28306159420289856" />
+        <entry key="..\:/PartTimeProject/CFLive/app/src/main/res/layout/fragment_main.xml" value="0.28306159420289856" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/drawable/bg_orange.xml" value="0.196875" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/activity_login.xml" value="0.225" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/activity_main.xml" value="0.18072916666666666" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/activity_splash.xml" value="0.18072916666666666" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/app_bar.xml" value="0.22" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/content_main.xml" value="0.18072916666666666" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/fragment_cf_betting.xml" value="0.18072916666666666" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/fragment_main.xml" value="0.18072916666666666" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/layout/item_box.xml" value="0.19322916666666667" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/menu/menu_channel.xml" value="0.175" />
+        <entry key="..\:/PartTimeProject/SBClive/app/src/main/res/menu/menu_main.xml" value="0.175" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/drawable/bg_circle_blue.xml" value="0.37407407407407406" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/drawable/bg_circle_green.xml" value="0.37407407407407406" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/drawable/bg_circle_red.xml" value="0.37407407407407406" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/drawable/bg_circle_yellow.xml" value="0.37407407407407406" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/drawable/bg_table_header.xml" value="0.31296296296296294" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/activity_main.xml" value="0.33" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/app_bar.xml" value="0.14322916666666666" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/app_bar_dialog.xml" value="0.13541666666666666" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/content_main.xml" value="0.23854166666666668" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/current_bets_item.xml" value="0.36666666666666664" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/fragment_cf_result.xml" value="0.36666666666666664" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/fragment_current_bets.xml" value="0.2390625" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/fragment_dialog_report.xml" value="0.2" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/fragment_report.xml" value="0.5" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/fragment_setting.xml" value="0.25677083333333334" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/fragment_statement.xml" value="0.4650630011454754" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/fragment_today_report.xml" value="0.2390625" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/item_box.xml" value="0.25" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/item_money_transaction.xml" value="0.21145833333333333" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/item_report.xml" value="0.22" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/item_table_report.xml" value="0.20520833333333333" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/item_table_statement.xml" value="0.25" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/layout/tab_statement.xml" value="0.20520833333333333" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.22135416666666666" />
+        <entry key="..\:/PartTimeProject/Website/sbc-mobile/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.22135416666666666" />
+      </map>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="ibm-11" 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

+ 150 - 0
app/build.gradle

@@ -0,0 +1,150 @@
+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 31
+    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.sambath.sbc"
+        minSdkVersion 21
+        targetSdkVersion 31
+        versionCode 1
+        versionName "1.0.0"
+        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 = "SBC-Mobile"
+            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.4.0'
+    implementation 'androidx.core:core-ktx:1.3.2'
+    implementation 'com.google.android.material:material:1.4.0'
+    implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
+    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
+    implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
+
+    //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:$lifecycle_version"
+
+    //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.9.0'
+    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('io.socket:socket.io-client:2.0.0') {
+        exclude group: 'org.json', module: 'json'
+    }
+
+//  Logging helper
+    implementation 'com.jakewharton.timber:timber:4.7.1'
+    implementation 'com.google.code.gson:gson:2.8.6'
+
+    //Lib
+    implementation project(path: ':printooth')
+    implementation 'com.squareup.picasso:picasso:2.71828'
+
+    testImplementation 'junit:junit:4.13.2'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}

BIN
app/dev/release/SBC-Mobile_devRelease_1.0.0-dev.apk


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

@@ -0,0 +1,18 @@
+{
+  "version": 2,
+  "artifactType": {
+    "type": "APK",
+    "kind": "Directory"
+  },
+  "applicationId": "com.sambath.sbc",
+  "variantName": "processDevReleaseResources",
+  "elements": [
+    {
+      "type": "SINGLE",
+      "filters": [],
+      "versionCode": 1,
+      "versionName": "1.0.0-dev",
+      "outputFile": "SBC-Mobile_devRelease_1.0.0-dev.apk"
+    }
+  ]
+}

+ 39 - 0
app/google-services.json

@@ -0,0 +1,39 @@
+{
+  "project_info": {
+    "project_number": "352049919729",
+    "project_id": "sombath-e7d83",
+    "storage_bucket": "sombath-e7d83.appspot.com"
+  },
+  "client": [
+    {
+      "client_info": {
+        "mobilesdk_app_id": "1:352049919729:android:c9a1aaa2f22dbb29381b50",
+        "android_client_info": {
+          "package_name": "com.sambath.loto"
+        }
+      },
+      "oauth_client": [
+        {
+          "client_id": "352049919729-04apg997ana6cm330p2mjsv6kqmaoub7.apps.googleusercontent.com",
+          "client_type": 3
+        }
+      ],
+      "api_key": [
+        {
+          "current_key": "AIzaSyApUv8IWd7fYKs7t6w04OFnj70nIxtul2w"
+        }
+      ],
+      "services": {
+        "appinvite_service": {
+          "other_platform_oauth_client": [
+            {
+              "client_id": "352049919729-04apg997ana6cm330p2mjsv6kqmaoub7.apps.googleusercontent.com",
+              "client_type": 3
+            }
+          ]
+        }
+      }
+    }
+  ],
+  "configuration_version": "1"
+}

BIN
app/prod/debug/App_prodDebug_1.0_1.apk


+ 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/SBC-Mobile_prodRelease_1.0.0.apk


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

@@ -0,0 +1,18 @@
+{
+  "version": 2,
+  "artifactType": {
+    "type": "APK",
+    "kind": "Directory"
+  },
+  "applicationId": "com.sambath.sbc",
+  "variantName": "processProdReleaseResources",
+  "elements": [
+    {
+      "type": "SINGLE",
+      "filters": [],
+      "versionCode": 1,
+      "versionName": "1.0.0",
+      "outputFile": "SBC-Mobile_prodRelease_1.0.0.apk"
+    }
+  ]
+}

+ 146 - 0
app/proguard-rules.pro

@@ -0,0 +1,146 @@
+# 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.sambath.cflive.remote.**
+#-keep class com.sambath.cflive.remote.model.** { *; }
+#-keepclassmembers class com.sambath.cflive.remote.model.** { *; }
+
+##---------------Begin: proguard configuration for Gson  ----------
+# Gson uses generic type information stored in a class file when working with fields. Proguard
+# removes such information by default, so configure it to keep all of it.
+-keepattributes Signature
+
+# For using GSON @Expose annotation
+-keepattributes *Annotation*
+
+# Gson specific classes
+-dontwarn sun.misc.**
+#-keep class com.google.gson.stream.** { *; }
+
+# Application classes that will be serialized/deserialized over Gson
+#-keep class com.google.gson.examples.android.model.** { <fields>; }
+-keep class com.sambath.sbc.remote.** { <fields>; }
+
+
+# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
+# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
+-keep class * implements com.google.gson.TypeAdapter
+-keep class * implements com.google.gson.TypeAdapterFactory
+-keep class * implements com.google.gson.JsonSerializer
+-keep class * implements com.google.gson.JsonDeserializer
+
+# Prevent R8 from leaving Data object members always null
+-keepclassmembers,allowobfuscation class * {
+  @com.google.gson.annotations.SerializedName <fields>;
+}
+##---------------End: proguard configuration for Gson  ----------

+ 24 - 0
app/src/androidTest/java/com/sambath/sbc/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.sambath.sbc
+
+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)
+    }
+}

+ 10 - 0
app/src/dev/java/com/sambath/sbc/config/Config.kt

@@ -0,0 +1,10 @@
+package com.sambath.sbc.config
+
+object Config {
+    //development
+    const val BASE_URL = "http://159.89.118.124:3081"
+    const val SOCKET_1 = "http://159.89.118.124:3082/chicken-online"
+    const val SOCKET_2 = "http://159.89.118.124:3082/sabong-sl"
+    const val SOCKET_3 = "http://159.89.118.124:3082/sabong-sl-3"
+    const val SOCKET_4 = "http://159.89.118.124:3082/sabong-sl-4"
+}

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

@@ -0,0 +1,49 @@
+<?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.sambath.sbc">
+    <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.sambath.sbc.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.sambath.sbc.app.ShareActivity"
+            android:label="@string/app_name"
+            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
+            android:screenOrientation="sensorPortrait"
+            android:windowSoftInputMode="adjustResize" />
+        <activity
+            android:name="com.sambath.sbc.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.sambath.sbc.screen.splash.SplashScreenActivity"
+            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
+            android:screenOrientation="sensorPortrait"
+            android:windowSoftInputMode="adjustResize"
+            android:exported="true">
+            <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/sambath/sbc/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/sambath/sbc/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/sambath/sbc/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()
+      }
+    }
+  }
+}

+ 17 - 0
app/src/main/java/com/sambath/sbc/adapter/BaseListItem.kt

@@ -0,0 +1,17 @@
+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
+}

+ 49 - 0
app/src/main/java/com/sambath/sbc/adapter/BaseListViewHolder.kt

@@ -0,0 +1,49 @@
+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
+            }
+        }
+    }
+}

+ 31 - 0
app/src/main/java/com/sambath/sbc/adapter/MainPagerAdapter.kt

@@ -0,0 +1,31 @@
+package com.sambath.sbc.adapter
+
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.Fragment
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import com.sambath.sbc.screen.main.cflive.currentbets.CurrentBetsFragment
+import com.sambath.sbc.screen.main.cflive.todayreport.TodayReportFragment
+
+private val TAB_TITLES = arrayOf(
+    "Current Bets",
+    "Today Report",
+)
+class MainPagerAdapter(
+    var activity: AppCompatActivity
+) : FragmentStateAdapter(activity) {
+    override fun getItemCount(): Int {
+        return 2
+    }
+
+    override fun createFragment(position: Int): Fragment {
+        return when (position) {
+            0 -> {
+                CurrentBetsFragment.newInstance(position + 1)
+            }
+            1 -> {
+                TodayReportFragment.newInstance(position + 1)
+            }
+            else -> CurrentBetsFragment.newInstance(position + 1)
+        }
+    }
+}

+ 116 - 0
app/src/main/java/com/sambath/sbc/app/App.kt

@@ -0,0 +1,116 @@
+package com.sambath.sbc.app
+
+import android.app.Application
+import android.content.Context
+import android.util.Log
+import com.itkacher.okhttpprofiler.OkHttpProfilerInterceptor
+import com.mazenrashed.printooth.Printooth
+import com.sambath.sbc.config.Config
+import com.sambath.sbc.BuildConfig
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.remote.service.SocketService
+import com.sambath.sbc.util.*
+import com.squareup.moshi.Moshi
+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
+import java.util.concurrent.TimeUnit
+
+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 shareViewModel: ShareViewModel
+        private lateinit var prefHelper: PrefHelper
+        var guidelineLeft: Float = 0f
+        var guidelineRight: Float = 100f
+        fun injectApiService() = apiService
+        fun injectShareViewModel() = shareViewModel
+        fun injectPrefHelper() = prefHelper
+        // Called on main activity create
+        fun onStartSocket(token: String, channelType: Int) {
+            Log.d("Socket", "token :: "+ token)
+            shareViewModel.startListenSocket(token, channelType)
+        }
+        // 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/sambath/sbc/app/ErrorInterceptor.kt

@@ -0,0 +1,41 @@
+package com.sambath.sbc.app
+
+import android.content.Context
+import android.content.Intent
+import com.sambath.sbc.screen.login.LoginActivity
+import com.sambath.sbc.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/sambath/sbc/app/ExceptionExtension.kt

@@ -0,0 +1,14 @@
+package com.sambath.sbc.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]"
+    }
+}

+ 23 - 0
app/src/main/java/com/sambath/sbc/app/ServiceInterceptor.kt

@@ -0,0 +1,23 @@
+package com.sambath.sbc.app
+
+import com.sambath.sbc.util.PrefHelper
+import okhttp3.Interceptor
+import okhttp3.Response
+
+class ServiceInterceptor(private val prefHelper: PrefHelper) : Interceptor {
+    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()
+                val channelType = prefHelper.getChannelType()
+                request = request.newBuilder()
+                    .addHeader("Authorization", finalToken)
+                    .addHeader("channel-type", channelType.toString())
+                    .build()
+            }
+        }
+        return chain.proceed(request)
+    }
+}

+ 375 - 0
app/src/main/java/com/sambath/sbc/app/ShareActivity.kt

@@ -0,0 +1,375 @@
+package com.sambath.sbc.app
+
+import android.annotation.SuppressLint
+import android.content.DialogInterface
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.util.Log
+import android.view.MenuInflater
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.widget.PopupMenu
+import androidx.constraintlayout.widget.Group
+import androidx.core.view.isVisible
+import androidx.lifecycle.Observer
+import com.cocking.fight.screen.dialogfragment.StatementDialogFragment
+import com.google.gson.Gson
+import com.sambath.sbc.R
+import com.sambath.sbc.base.AutoLogoutBaseActivity
+import com.sambath.sbc.remote.ChannelData
+import com.sambath.sbc.remote.K
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.remote.service.ConnectivityStates
+import com.sambath.sbc.screen.login.LoginActivity
+import com.sambath.sbc.screen.main.MainFragment
+import com.sambath.sbc.screen.main.MainViewModel
+import com.sambath.sbc.screen.splash.SplashScreenActivity
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.ModelPreferencesManager
+import com.sambath.sbc.util.PrefHelper
+import com.squareup.moshi.JsonAdapter
+import com.squareup.moshi.Moshi
+import kotlinx.android.synthetic.main.app_bar.*
+import kotlinx.android.synthetic.main.content_main.*
+import org.json.JSONObject
+
+
+class ShareActivity : AutoLogoutBaseActivity() {
+    lateinit var settingImageView: ImageView
+    lateinit var reportImageView: ImageView
+    private val gson = Gson()
+
+    //    lateinit var soundImageView: ImageView
+    lateinit var userNameTextView: TextView
+    lateinit var balanceTextView: TextView
+    lateinit var refreshImageView: ImageView
+    private lateinit var moshi: Moshi
+
+    //    private lateinit var remoteConfig: FirebaseRemoteConfig
+    lateinit var groupToolbarIcons: Group
+    lateinit var sharePref: PrefHelper
+    lateinit var layCfStatus: LinearLayout
+    lateinit var userShare: User
+    private var isOpen: String = "null"
+    private val shareViewModel = App.injectShareViewModel()
+    private lateinit var mainViewModel: MainViewModel
+    override fun onCreate(savedInstanceState: Bundle?) {
+//        Log.d("Oncreate", "before")
+        moshi = Moshi.Builder().build()
+        mainViewModel = MainViewModel(App.injectApiService(), App.injectPrefHelper())
+        ModelPreferencesManager.get<User>(Const.USER_KEY)?.let {
+            userShare = it
+        }
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        val balance = currencyFormat(userShare.accountBalances)
+        when (userShare.currencyType) {
+            1 -> {//dollar
+                tv_amount.text = "$balance $"
+            }
+            2 -> {//riel
+                tv_amount.text ="$balance ៛"
+            }
+            3 -> {//baht
+                tv_amount.text = "$balance ฿"
+            }
+        }
+        tv_user_id.text = userShare.userName
+        sharePref = App.injectPrefHelper()
+        mtxt_switch_channel.text = "CH" + sharePref.getChannelType()
+        txtStatus.text = "Status " + sharePref.getChannelType()
+        mainViewModel.getChannel()
+        mainViewModel.getUser()
+        mainViewModel.getCfResuleData()
+        mainViewModel.stateChannel.observe(this, androidx.lifecycle.Observer {
+            Log.d("stateChannel", it.toString())
+            if (it?.isChSuccess == true) {
+                it.channelInfo?.let { it1 -> getChannelData(it1) }
+            }
+        })
+        mainViewModel.stateUser.observe(this, androidx.lifecycle.Observer {
+            Log.d("stateUser", it.toString())
+            if (it?.isUserSuccess == true) {
+                it.userInfo?.let { it1 -> getUserInfo(it1) }
+            }
+        })
+        mainViewModel.state.observe(this, androidx.lifecycle.Observer {
+            if (it.isSuccess) {
+                if (it.resultList.isNullOrEmpty() || isOpen == "true") {
+                    txtWinner.text = "None"
+                } else {
+                    txtWinner.text = it.resultList!![0].name
+                }
+            }
+        })
+//        mainViewModel.getMainData()
+        //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()
+        }
+        reportImageView = findViewById<ImageView>(R.id.iv_report)
+        settingImageView = findViewById<ImageView>(R.id.iv_setting)
+        refreshImageView = findViewById<ImageView>(R.id.iv_auto_new)
+        layCfStatus = findViewById<LinearLayout>(R.id.layCfStatus)
+        groupToolbarIcons = findViewById<Group>(R.id.group_toolbar_icons)
+        userNameTextView = findViewById<TextView>(R.id.tv_user_id)
+        balanceTextView = findViewById<TextView>(R.id.tv_amount)
+        mtxt_switch_channel.setOnClickListener { v ->
+            val popup = PopupMenu(this, v)
+            val inflater: MenuInflater = popup.menuInflater
+            inflater.inflate(R.menu.menu_channel, popup.menu)
+            popup.setOnMenuItemClickListener {
+                when (it.itemId) {
+                    R.id.action_channel_1 -> {
+                        sharePref.setChannelType(1)
+                        this.recreate()
+                    }
+                    R.id.action_channel_2 -> {
+                        sharePref.setChannelType(2)
+                        this.recreate()
+                    }
+                    R.id.action_channel_3 -> {
+                        sharePref.setChannelType(3)
+                        this.recreate()
+                    }
+                    R.id.action_channel_4 -> {
+                        sharePref.setChannelType(4)
+                        this.recreate()
+                    }
+
+                }
+                true
+            }
+            popup.show()
+        }
+        shareViewModel.getUpdateChannelInfo.observe(this, Observer {
+            Log.d("Socket", "getUpdateChannelInfo" + it.toString())
+            if (!it.isNullOrEmpty()) {
+                val adapter: JsonAdapter<ChannelData> = moshi.adapter(
+                    ChannelData::class.java
+                )
+                val channelDataResponse = adapter.fromJson(it)
+                if (channelDataResponse != null) {
+                    getChannelData(channelDataResponse)
+                }
+            }
+        })
+        shareViewModel.getDefinedResultAndChannel.observe(this, Observer {
+            Log.d("Socket", "getDefinedResultAndChannel" + it.toString())
+            if (!it.isNullOrEmpty()) {
+                val obj = JSONObject(it)
+                val resultArr = obj.getJSONArray("objCoResult")
+                if (resultArr.length() > 0) {
+                    txtWinner.text = resultArr.getJSONObject(0).getString("name")
+                } else {
+                    txtWinner.text = "None"
+                }
+            }
+        })
+        shareViewModel.getUpdateUserInfo.observe(this, Observer {
+            Log.d("Socket", "getUpdateUserInfo" + it.toString())
+            if (!it.isNullOrEmpty()) {
+                val obj = JSONObject(it)
+                val balance = currencyFormat(obj.getInt("balance"))
+                if (userShare.currencyType == 1){//dollar
+                    tv_amount.text = "$$balance"
+                }else if(userShare.currencyType == 2){//riel
+                    tv_amount.text ="៛$balance"
+                }else{//baht
+                    tv_amount.text = "฿$balance"
+                }
+            }
+        })
+        shareViewModel.getResult.observe(this, Observer {
+            Log.d("Socket", "getResult")
+            if (!it.isNullOrEmpty()) {
+                txtWinner.text = it
+            } else {
+                txtWinner.text = "None"
+            }
+        })
+    }
+
+    private fun alertMsgLogout() {
+        val alertDialog: AlertDialog.Builder = AlertDialog.Builder(this)
+        alertDialog.setTitle("Logout Alert!")//for set Title
+        alertDialog.setMessage("សូមទំនាក់ទំនងទៅកាន់ភ្នាក់ងាររបស់អ្នក!")// for Message
+        val alert = alertDialog.create()
+//        alertDialog.setNegativeButton(getString(R.string.ok)) { dialog, id ->
+//            timer.cancel()
+//            dialog.dismiss()
+//            logout()
+//        }
+        alert.setCanceledOnTouchOutside(false)
+        alert.setOnShowListener {
+            val timer = object : CountDownTimer(1500, 100) {
+                override fun onTick(millisUntilFinished: Long) {
+
+                }
+
+                override fun onFinish() {
+                    alert.dismiss()
+                    logout()
+                }
+            }
+            timer.start()
+        }
+        alert.show()
+        val negativeButton = alert.getButton(DialogInterface.BUTTON_NEGATIVE)
+        negativeButton.setTextColor(Color.RED)
+    }
+
+    private fun logout() {
+        sharePref.logout()
+        val intent = Intent(this, LoginActivity::class.java)
+        startActivity(intent)
+        finishAffinity()
+    }
+
+    override fun onWindowFocusChanged(hasFocus: Boolean) {
+        super.onWindowFocusChanged(hasFocus)
+        //Log.d("Window", "hase focus")
+        if (hasFocus) hideSystemUI()
+    }
+
+    private fun getUserInfo(it: User) {
+        Log.d("stateUser", it.toString())
+        tv_amount.text = it.accountBalances?.let { it1 ->
+            val balance = currencyFormat(it1)
+            if (userShare.currencyType == 1){//dollar
+                 "$$balance"
+            }else if(userShare.currencyType == 2){//riel
+                "៛$balance"
+            }else{//baht
+                "฿$balance"
+            }
+
+        }
+        btnBettingStatus.isActivated = true
+    }
+
+    private fun getChannelData(it: ChannelData) {
+        Log.d("statechannel", it.toString())
+//        if (!it.enable) {
+//            Log.d("Socket", "enable false")
+//            alertMsgLogout()
+//        }
+        shareViewModel.setChannelInfo(it)
+        txtFightNo.text = it.fightNo.toString()
+        isOpen = it.is_open.toString()
+        btnBettingStatus.isActivated = true
+        when (isOpen) {
+            "null" -> {
+                btnBettingStatus.text = K.Live
+                btnBettingStatus.isEnabled = false
+                btnBettingStatus.isActivated = false
+            }
+            "true" -> {
+                txtWinner.text = "None"
+                btnBettingStatus.text = K.Open
+                btnBettingStatus.isEnabled = true
+            }
+            "false" -> {
+                btnBettingStatus.text = K.Close
+                btnBettingStatus.isEnabled = false
+            }
+        }
+        shareViewModel.getConnectivityStates.observe(this, Observer {
+            getSocketConnectionStatus(it)
+        })
+    }
+
+    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)
+    }
+
+    private fun getSocketConnectionStatus(status: Int) {
+        when (status) {
+            ConnectivityStates.STATE_DISCONNECTED -> {
+                Log.d("Socket", "onDisconnect...")
+                val mStartActivity = Intent(this, SplashScreenActivity::class.java)
+                startActivity(mStartActivity)
+                System.exit(0)
+            }
+            ConnectivityStates.STATE_NOT_CONNECTED -> {
+                Log.d("Socket", "onNotconnected...")
+                Toast.makeText(this, "មិនអាចភ្ជាប់ទៅកាន់ម៉ាស៊ីនមេ!", Toast.LENGTH_LONG).show()
+            }
+            ConnectivityStates.STATE_RECONNECTING -> {
+                Log.d("Socket", "onReconnecting...")
+            }
+            ConnectivityStates.STATE_TIMEOUT -> {
+                Log.d("Socket", "onTimout...")
+                val intent = Intent(this, SplashScreenActivity::class.java)
+                startActivity(intent)
+                finishAffinity()
+            }
+            ConnectivityStates.STATE_CONNECTED -> {
+                Log.d("Socket", "onConnected...")
+//                shareViewModel.remoteMainScreenAPI(userId = user.id)
+            }
+        }
+
+    }
+
+    override fun onBackPressed() {
+        when (supportFragmentManager.backStackEntryCount) {
+            1 -> {
+                finish()
+            }
+            else -> {
+                groupToolbarIcons.isVisible = true
+                layCfStatus.isVisible = true
+                super.onBackPressed()
+            }
+        }
+    }
+
+    override fun onDestroy() {
+        // App.onAppStop()
+        super.onDestroy()
+        Log.d("Lifecycle", "onDestroy")
+    }
+
+    private var confirmDialog: AlertDialog? = null
+
+    override fun onPause() {
+        super.onPause()
+        App.onAppStop()
+        //Log.d("Lifecycle","onPause")
+    }
+
+    override fun onResume() {
+        super.onResume()
+        App.onStartSocket(sharePref.getToken(), sharePref.getChannelType())//userID = userShare.id)
+    }
+
+    override fun onUserInteraction() {
+        super.onUserInteraction()
+    }
+
+}

+ 163 - 0
app/src/main/java/com/sambath/sbc/app/ShareViewModel.kt

@@ -0,0 +1,163 @@
+package com.sambath.sbc.app
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.google.gson.Gson
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.*
+import com.sambath.sbc.remote.service.EventListener
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.remote.service.ConnectivityStates
+import com.sambath.sbc.remote.service.SocketService
+import com.sambath.sbc.util.PrefHelper
+import org.json.JSONObject
+import java.net.URISyntaxException
+
+class ShareViewModel(
+    private val apiService: ApiService,
+    private val prefHelper: PrefHelper,
+    private val socketService: SocketService
+) : BaseViewModel(), EventListener {
+    private val gson = Gson()
+
+    //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
+
+    // Remote
+    fun startListenSocket(token: String, channelType: Int) {
+        try {
+            socketService.registerListener(this)
+            socketService.startListening(token, channelType)
+        } catch (e: URISyntaxException) {
+            e.printStackTrace()
+        }
+    }
+
+    fun emitCfCreateBetting(createBettingObject: JSONObject) {
+        socketService.startEmitCfCreateBetting(createBettingObject)
+    }
+
+    fun stopListeningToSocketServer() {
+        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)
+    }
+
+    private val fakeBetting = MutableLiveData<String>()
+    val getFakeBetting: LiveData<String> = fakeBetting
+
+    private val viewResult = MutableLiveData<String>()
+    val getViewResult: LiveData<String> = viewResult
+
+    private val infoBalanceBetting = MutableLiveData<String>()
+    val getInfoBalanceBetting: LiveData<String> = infoBalanceBetting
+
+    private val updateChanelDeveloper = MutableLiveData<String>()
+    val onUpdateChanelDeveloper: LiveData<String> = updateChanelDeveloper
+
+    private val summaryBetting = MutableLiveData<String>()
+    val getSummaryBetting: LiveData<String> = summaryBetting
+
+    private val updateChannelInfo = MutableLiveData<String>()
+    val getUpdateChannelInfo: LiveData<String> = updateChannelInfo
+    override fun onUpdateChannelInfo(data: String?) {
+        updateChannelInfo.postValue(data)
+    }
+
+    private val definedResultAndChannel = MutableLiveData<String>()
+    val getDefinedResultAndChannel: LiveData<String> = definedResultAndChannel
+    override fun onDefinedResultAndChannel(data: String?) {
+        definedResultAndChannel.postValue(data)
+    }
+
+    private val updateUserInfo = MutableLiveData<String>()
+    val getUpdateUserInfo: LiveData<String> = updateUserInfo
+    override fun onUpdateUserInfo(data: String?) {
+        updateUserInfo.postValue(data)
+    }
+
+    private val updateBettingAmount = MutableLiveData<String>()
+    val onUpdateBettingAmount: LiveData<String> = updateBettingAmount
+    override fun onUpdateBettingAmount(data: String?) {
+        updateBettingAmount.postValue(data)
+    }
+
+    private val updatePayout = MutableLiveData<String>()
+    val getUpdatePayout: LiveData<String> = updatePayout
+    override fun onUpdatePayout(data: String?) {
+        updatePayout.postValue(data)
+    }
+
+    private val reverseRseult = MutableLiveData<String>()
+    val onReverseRseult: LiveData<String> = reverseRseult
+    override fun onReverseRseult(data: String?) {
+        reverseRseult.postValue(data)
+    }
+
+    private val resetAmount = MutableLiveData<String>()
+    val getResetAmount: LiveData<String> = resetAmount
+    override fun onResetAmount(data: String?) {
+        resetAmount.postValue(data)
+    }
+
+    private val currentBetting = MutableLiveData<Boolean>()
+    val getUpdateFlagMain: LiveData<Boolean> get() = currentBetting
+    fun setUpdateFlagMain(isUpdate: Boolean) {
+        currentBetting.postValue(isUpdate)
+    }
+
+//    private val channel = MutableLiveData<ChannelData>()
+//    val getChannel: LiveData<ChannelData> get() = channel
+//
+//    fun setChannel(channelObj: ChannelData) {
+//        channel.postValue(channelObj)
+//    }
+
+    private val channelInfo = MutableLiveData<ChannelData>()
+    val getChannelInfo: LiveData<ChannelData> get() = channelInfo
+
+    fun setChannelInfo(channelObj: ChannelData) {
+        channelInfo.postValue(channelObj)
+    }
+
+    private val result = MutableLiveData<String>()
+    val getResult: LiveData<String> get() = result
+
+    fun setResult(res: String) {
+        result.postValue(res)
+    }
+
+    private val updateData = MutableLiveData<JSONObject>()
+    val getUpdateData: LiveData<JSONObject> get() = updateData
+
+    fun setUpdateData(channelObj: JSONObject) {
+        updateData.postValue(channelObj)
+    }
+}

+ 19 - 0
app/src/main/java/com/sambath/sbc/app/ShareViewState.kt

@@ -0,0 +1,19 @@
+package com.sambath.sbc.app
+
+import com.sambath.sbc.remote.CurrentBetting
+import com.sambath.sbc.remote.ListItem
+import com.sambath.sbc.remote.Result
+import com.sambath.sbc.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
+)

+ 45 - 0
app/src/main/java/com/sambath/sbc/base/AutoLogoutBaseActivity.kt

@@ -0,0 +1,45 @@
+package com.sambath.sbc.base
+
+import android.content.Intent
+import android.os.Bundle
+import com.sambath.sbc.app.App
+import com.sambath.sbc.screen.login.LoginActivity
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.Const.Companion.DEFAULT_LOGOUT_TIME
+import com.sambath.sbc.util.LogOutTimerUtil
+
+abstract class AutoLogoutBaseActivity(private val logoutTime: Int = DEFAULT_LOGOUT_TIME) : BaseActivity() {
+    private val sharePref = App.injectPrefHelper()
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        LogOutTimerUtil.isUserTimedOutLiveData
+            .observe(this, { isUserTimedOut ->
+                if (isUserTimedOut)
+                    logout()
+            })
+    }
+
+    override fun onResume() {
+        super.onResume()
+        if (LogOutTimerUtil.isUserTimedOutLiveData.value == false) {
+            Const.LOGOUT_TIME = logoutTime
+            LogOutTimerUtil.resetLogoutTimer(null, null)
+        }
+    }
+
+//    override fun onUserInteraction() {
+//        super.onUserInteraction()
+//        LogOutTimerUtil.resetLogoutTimer(null, null)
+//    }
+
+    private fun logout() {
+        LogOutTimerUtil.isUserTimedOutLiveData.postValue(false)     // Reset timeout flag for background mode
+        sharePref.logout()
+
+        val intent = Intent(this, LoginActivity::class.java)
+        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+        startActivity(intent)
+        finish()
+    }
+}

+ 54 - 0
app/src/main/java/com/sambath/sbc/base/BaseActivity.kt

@@ -0,0 +1,54 @@
+package com.sambath.sbc.base
+
+import android.os.Bundle
+import android.view.MenuItem
+import androidx.appcompat.app.AppCompatActivity
+import com.sambath.sbc.R
+import java.text.DecimalFormat
+
+abstract class BaseActivity : AppCompatActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        if (savedInstanceState == null) overridePendingTransition(
+            R.anim.slide_in,
+            R.anim.slide_out
+        )
+    }
+    fun currencyFormat(amount: Int): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+    fun currencyFormat(amount: Long): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+    fun currencyFormat(amount: Double): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+    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
+        )
+    }
+}

+ 715 - 0
app/src/main/java/com/sambath/sbc/base/BaseFragment.kt

@@ -0,0 +1,715 @@
+package com.sambath.sbc.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.fragment.app.Fragment
+import com.cocking.fight.screen.dialogfragment.StatementDialogViewModel
+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.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.remote.LottoSet
+import com.sambath.sbc.remote.ReportOne
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.ModelPreferencesManager
+import java.text.DecimalFormat
+import java.text.SimpleDateFormat
+import java.util.*
+
+abstract class BaseFragment(
+    @LayoutRes private val layoutRes: Int
+) : Fragment() {
+    private lateinit var user: User
+    private var printing: Printing? = null
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        if (Printooth.hasPairedPrinter()) printing = Printooth.printer()
+        user = ModelPreferencesManager.get<User>(Const.USER_KEY)!!
+    }
+
+    fun currencyType() : String{
+        when (user.currencyType) {
+            1 -> {//dollar
+                return "$"
+            }
+            2 -> {//riel
+                return "៛"
+            }
+            3 -> {//baht
+                return "฿"
+            }
+        }
+        return ""
+    }
+
+    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)
+    }
+
+    fun currencyFormat(amount: Int): String {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+    fun currencyFormatKh(amount: Double): 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.wa855.net")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC437)
+                .setNewLinesAfter(1)
+                .build()
+        )
+    }
+
+    fun printCfPrintable(
+        userName: String,
+        fightNo: String,
+        betDate: String,
+        betType: String,
+        amount: String,
+        payout: String
+    ) {
+        if (Printooth.hasPairedPrinter() && printing == null) printing = Printooth.printer()
+        if (printing == null) {
+            Toast.makeText(requireContext(), "No printing paired", Toast.LENGTH_SHORT).show()
+        } else {
+            printing?.print(getCfPrintables(userName, fightNo, betDate, betType, amount, payout))
+        }
+    }
+
+    fun printCfPrintable(
+        user: User,
+        fightNo: String,
+        betDate: String,
+        betType: String,
+        amount: String,
+        payoutRate: String,
+        payout: String,
+        id: String,
+        channelId: Int
+    ) {
+        if (Printooth.hasPairedPrinter() && printing == null) printing = Printooth.printer()
+        if (printing == null) {
+            Toast.makeText(requireContext(), "No printing paired", Toast.LENGTH_SHORT).show()
+        } else {
+            var currencyType: String = ""
+            when (user.currencyType) {
+                1 -> {
+                    currencyType = "Dollar"
+                }
+                2 -> {
+                    currencyType = "Riel"
+                }
+                3 -> {
+                    currencyType = "Baht"
+                }
+            }
+            printing?.print(
+                getCfPrintables(
+                    user.userName,
+                    currencyType,
+                    fightNo,
+                    betDate,
+                    betType,
+                    amount,
+                    payoutRate,
+                    payout,
+                    id,
+                    channelId
+                )
+            )
+        }
+    }
+
+    private fun getCfPrintables(
+        userName: String,
+        currencyType: String,
+        fightNo: String,
+        betDate: String,
+        betType: String,
+        amount: String,
+        payoutRate: String,
+        payout: String,
+        id: String,
+        channelId: Int
+    ) = ArrayList<Printable>().apply {
+        add(
+            TextPrintable.Builder()
+                .setText("SBC2888")
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Channel : $channelId")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Bet ID : ${id}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("----------------")
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC1252)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Fight No  : $fightNo")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Account:")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText(userName)
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Bet Type : $betType")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Date : $betDate")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+//        add(
+//            TextPrintable.Builder()
+//                .setText("Bet Point")
+//                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+//                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+//                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+//                .setNewLinesAfter(1)
+//                .build()
+//        )
+//        add(
+//            TextPrintable.Builder()
+//                .setText("$amount x $payoutRate")
+//                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+//                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+//                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+//                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+//                .setNewLinesAfter(1)
+//                .build()
+//        )
+        add(
+            TextPrintable.Builder()
+                .setText("Currency Type : $currencyType")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Bet point : $payout")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("----------------")
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("www.wa855.net")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC437)
+                .setNewLinesAfter(1)
+                .build()
+        )
+    }
+
+    private fun getCfPrintables(
+        userName: String,
+        fightNo: String,
+        betDate: String,
+        betType: String,
+        amount: String,
+        payout: String
+    ) = ArrayList<Printable>().apply {
+        add(
+            TextPrintable.Builder()
+                .setText("SBC2888")
+                .setUnderlined(DefaultPrinter.UNDERLINED_MODE_ON)
+                .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_10)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC1252)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Round  : $fightNo")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Date   : $betDate")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Account: $userName")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Type   : $betType")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Bet x Odds:")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("$amount x $payout")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Payout : $amount")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("----------------")
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_10)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("www.wa855.net")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC437)
+                .setNewLinesAfter(1)
+                .build()
+        )
+    }
+
+    private fun getLastFourChars(str: String, n: Int): String {
+        var lastChars = str
+        if (lastChars.length > n) {
+            lastChars = lastChars.substring(lastChars.length - n, lastChars.length)
+        }
+        return lastChars
+    }
+
+    fun printSBCPrintable(reportOne: ReportOne, currencyType: Int, channelId: Int) {
+        if (Printooth.hasPairedPrinter() && printing == null) printing = Printooth.printer()
+        if (printing == null) {
+            Toast.makeText(requireContext(), "No printing paired", Toast.LENGTH_SHORT).show()
+        } else {
+            var winOrLose: String = ""
+            var sign: String = ""
+            winOrLose = if (reportOne.is_win == true) {
+                "WIN"
+            } else {
+                "LOSE"
+            }
+            when (currencyType) {
+                1 -> {
+                    sign = "Dollar"
+                }
+                2 -> {
+                    sign = "Riel"
+                }
+                3 -> {
+                    sign = "Baht"
+                }
+            }
+            printing?.print(getSBCPrintables(reportOne, getLastFourChars(reportOne._id, 4), winOrLose, sign, channelId))
+        }
+    }
+
+    private fun getSBCPrintables(
+        reportOne: ReportOne,
+        betId: String,
+        winLose: String,
+        currencyType: String,
+        channelId: Int
+    ) = ArrayList<Printable>().apply {
+        add(
+            TextPrintable.Builder()
+                .setText("SBC2888")
+                .setUnderlined(DefaultPrinter.UNDERLINED_MODE_ON)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_30)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Channel : $channelId")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Bet ID : $betId")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("----------------")
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_10)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC1252)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Fight No : ${reportOne.fightNo}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Bet Type : ${reportOne.betName}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Date : ${reportOne.date}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Amount : ${reportOne.amount}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Payout : ${reportOne.payout}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Cast : ${reportOne.cast}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Amount Win : ${reportOne.amountWin}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+
+        add(
+            TextPrintable.Builder()
+                .setText("Currency Type : $currencyType")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Result : ${reportOne.resultName}")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("Win/Lose : $winLose")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setFontSize(DefaultPrinter.FONT_SIZE_SMALL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC850)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("----------------")
+                .setLineSpacing(DefaultPrinter.LINE_SPACING_10)
+                .setNewLinesAfter(1)
+                .build()
+        )
+        add(
+            TextPrintable.Builder()
+                .setText("www.wa855.net")
+                .setEmphasizedMode(DefaultPrinter.EMPHASIZED_MODE_NORMAL)
+                .setAlignment(DefaultPrinter.ALIGNMENT_CENTER)
+                .setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
+                .setCharacterCode(DefaultPrinter.CHARCODE_PC437)
+                .setNewLinesAfter(1)
+                .build()
+        )
+    }
+}

+ 13 - 0
app/src/main/java/com/sambath/sbc/base/BaseViewModel.kt

@@ -0,0 +1,13 @@
+package com.sambath.sbc.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/sambath/sbc/extension/ViewExtensions.kt

@@ -0,0 +1,209 @@
+package com.sambath.sbc.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.sambath.sbc.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)
+}

+ 28 - 0
app/src/main/java/com/sambath/sbc/remote/CfModel.kt

@@ -0,0 +1,28 @@
+package com.sambath.sbc.remote
+
+import com.google.gson.annotations.SerializedName
+
+data class TodayReport(
+    @SerializedName("_id")
+    var id: String? = null,
+    @SerializedName("t_meron")
+    var fightBet: String? = null,
+    @SerializedName("t_meron_total")
+    var type: String? = null,
+    @SerializedName("r_wala_total")
+    var result: String? = null,
+    @SerializedName("r_wala")
+    var time: String? = null,
+){}
+data class CurrentBet(
+    @SerializedName("_id")
+    var id: String? = null,
+    @SerializedName("t_meron")
+    var fight: String? = null,
+    @SerializedName("r_wala")
+    var time: String? = null,
+    @SerializedName("t_meron_total")
+    var type: String? = null,
+    @SerializedName("r_wala_total")
+    var amount: String? = null,
+){}

+ 32 - 0
app/src/main/java/com/sambath/sbc/remote/K.kt

@@ -0,0 +1,32 @@
+package com.sambath.sbc.remote
+
+class K {
+    companion object{
+        const val Column = "column"
+        const val Fix_Column = "fix_column"
+        const val Fight_No = "fight_no"
+        const val TypeOfPlay = "type_of_play"
+        const val CirBlue = "cir-blue"
+        const val CirRed = "cir-red"
+        const val CirGreen = "cir-green"
+        const val CirCancel = "cir-cancel"
+        const val Open="Open"
+        const val Close = "Close"
+        const val Live = "Live"
+        const val CastRed = "cast_red"
+        const val CastBlue = "cast_blue"
+        const val PayoutRed = "payout_red"
+        const val PayoutBlue = "payout_blue"
+        const val Red = "red"
+        const val Blue = "blue"
+        const val Meron = "MERON"
+        const val Wala = "WALA"
+        const val Tie = "TIE"
+        const val Cancel = "CANCEl"
+        const val ChannelId = "_id"
+        const val TemId = "tem_id"
+        const val AmountRed = "amount_red"
+        const val AmountBlue = "amount_blue"
+        const val date = "date"
+    }
+}

+ 628 - 0
app/src/main/java/com/sambath/sbc/remote/LoginDataModel.kt

@@ -0,0 +1,628 @@
+package com.sambath.sbc.remote
+
+import com.gdtlib.lib.adapter.BaseListItem
+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 ChangePwd(
+    @Json(name = "old_password")
+    val oldPassword: String,
+    @Json(name = "new_password")
+    val newPassword: String
+)
+
+@JsonClass(generateAdapter = true)
+data class ChangePwdResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage
+)
+
+@JsonClass(generateAdapter = true)
+data class BettingResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: BettingData ?= null
+)
+
+@JsonClass(generateAdapter = true)
+data class BettingData(
+    @Json(name = "_id")
+    val _id: String,
+    @Json(name = "fight_no")
+    val fightNo: Int,
+    @Json(name = "group_no")
+    val groupNo: Int,
+    @Json(name = "betting")
+    val betting: String,
+    @Json(name = "bet_color")
+    val bet_color: String,
+    @Json(name = "amount")
+    val amount: String,
+    @Json(name = "time")
+    val time: String,
+    @Json(name = "balance")
+    val balance: String,
+    @Json(name = "payout_wala")
+    val payoutWala: String,
+    @Json(name = "payout_meron")
+    val payoutMeron: String
+)
+
+@JsonClass(generateAdapter = true)
+data class CurrentBetData(
+    @Json(name = "amount")
+    val amount: String,
+    @Json(name = "bet_color")
+    val bet_color: String,
+    @Json(name = "betting")
+    val betting: String,
+    @Json(name = "fight_no")
+    val fightNo: Int,
+    @Json(name = "group_no")
+    val groupNo: Int,
+    @Json(name = "time")
+    val time: String,
+    @Json(name = "_id")
+    val _id: String,
+) : BaseListItem() {
+    override fun getUnique(): String = _id
+}
+
+@JsonClass(generateAdapter = true)
+data class CurrentResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: List<CurrentBetData>
+)
+
+@JsonClass(generateAdapter = true)
+data class TodayResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: List<TodayData>? = null
+)
+
+@JsonClass(generateAdapter = true)
+data class TodayData(
+    @Json(name = "amount")
+    val amount: String,
+    @Json(name = "bet_color")
+    val bet_color: String,
+    @Json(name = "betting")
+    val betting: String,
+    @Json(name = "fight_no")
+    val fightNo: Int,
+    @Json(name = "group_no")
+    val groupNo: Int,
+    @Json(name = "is_win")
+    val isWin: Boolean,
+    @Json(name = "result_color")
+    val resultColor: String,
+    @Json(name = "result_name")
+    val resultName: String,
+    @Json(name = "time")
+    val time: String,
+    @Json(name = "_id")
+    val _id: String,
+) : BaseListItem() {
+    override fun getUnique(): String = _id
+}
+
+@JsonClass(generateAdapter = true)
+data class BtnData(
+    @Json(name = "amount")
+    val amount: Int,
+    @Json(name = "currency_type")
+    val currencyType: Int,
+    @Json(name = "label")
+    val label: String,
+    @Json(name = "order")
+    val order: Int,
+    @Json(name = "_id")
+    val _id: String
+)
+
+@JsonClass(generateAdapter = true)
+data class ButtonResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: List<BtnData>
+)
+
+@JsonClass(generateAdapter = true)
+data class ChannelResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: ChannelData?
+)
+
+@JsonClass(generateAdapter = true)
+data class UserResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: User?
+)
+
+@JsonClass(generateAdapter = true)
+data class WeightResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: WeightData?
+)
+
+@JsonClass(generateAdapter = true)
+data class WeightData(
+    @Json(name = "wala")
+    val wala: Wala?,
+    @Json(name = "meron")
+    val meron: Meron?,
+    @Json(name = "amount_min")
+    val amountMin: Int,
+    @Json(name = "amount_max")
+    val amountMax: Int
+)
+
+@JsonClass(generateAdapter = true)
+data class Wala(
+    @Json(name = "payout")
+    val payout: String,
+    @Json(name = "amount")
+    val amount: String
+)
+
+@JsonClass(generateAdapter = true)
+data class Meron(
+    @Json(name = "payout")
+    val payout: String,
+    @Json(name = "amount")
+    val amount: String
+)
+
+@JsonClass(generateAdapter = true)
+data class BettingTypeResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: List<BettingTypeData>
+)
+
+@JsonClass(generateAdapter = true)
+data class BettingTypeData(
+    @Json(name = "_id")
+    val _id: String,
+    @Json(name = "name")
+    val name: String,
+    @Json(name = "desc")
+    val desc: String,
+    @Json(name = "color")
+    val color: String,
+    @Json(name = "is_betting")
+    val isBetting: Boolean
+)
+
+@JsonClass(generateAdapter = true)
+data class ResultsResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: ResultsData
+)
+
+@JsonClass(generateAdapter = true)
+data class ResultsData(
+    @Json(name = "results")
+    val results: List<Results>,
+    @Json(name = "summary")
+    val resultSummary: ResultSummary?,
+)
+
+@JsonClass(generateAdapter = true)
+data class Results(
+    @Json(name = "_id")
+    val _id: String,
+    @Json(name = "fight_no")
+    val fightNo: Int,
+    @Json(name = "name")
+    val name: String,
+    @Json(name = "cid")
+    val cid: Int,
+    @Json(name = "rid")
+    val rid: Int,
+    @Json(name = "color")
+    val color: String,
+)
+
+@JsonClass(generateAdapter = true)
+data class ResultSummary(
+    @Json(name = "MERON")
+    val meron: Int,
+    @Json(name = "WALA")
+    val wala: Int,
+    @Json(name = "TIE")
+    val tie: Int,
+    @Json(name = "CANCEL")
+    val cancel: Int
+)
+
+
+@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 ChannelData(
+    @Json(name = "is_stop_video")
+    val isStopVideo: Boolean,
+    @Json(name = "enable")
+    val enable: Boolean,
+    @Json(name = "is_open")
+    val is_open: Boolean? = null,
+    @Json(name = "live_urls")
+    val liveUrls: List<String>?,
+    @Json(name = "_id")
+    val id: String,
+    @Json(name = "info")
+    val info: String,
+    @Json(name = "video_info")
+    val videoInfo: String,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "fight_no")
+    val fightNo: Int,
+    @Json(name = "group_no")
+    val groupNo: Int,
+    @Json(name = "column")
+    val column: Int,
+    @Json(name = "fix_column")
+    val fixColumn: Int,
+    @Json(name = "is_maintain")
+    val isMaintain: Boolean,
+    @Json(name = "maintain_desc")
+    val maintainDesc: String,
+    @Json(name = "__v")
+    val v: String?,
+)
+
+@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 = "user_name")
+    val userName: String,
+    @Json(name = "role")
+    val roles: String,
+    @Json(name = "enable")
+    val readOnly: Boolean,
+    @Json(name = "account_info")
+    var accountInfo: String?,
+    @Json(name = "account_name")
+    var accountName: String?,
+    @Json(name = "account_number")
+    var accountNumber: String?,
+    @Json(name = "balance")
+    val accountBalances: Double,
+    @Json(name = "currency_type")
+    val currencyType: Int,
+)
+
+@JsonClass(generateAdapter = true)
+data class NewPassword(
+    @Json(name = "new_password")
+    var newPassword: String,
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportOneResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: ReportOneData
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportDepositResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: ReportDepositData
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportWithdrawResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: ReportWithdrawData
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportDepositData(
+    @Json(name = "rows_per_page")
+    val rowsPerPage: Int,
+    @Json(name = "total_rows")
+    val totalRows: Int,
+    @Json(name = "page")
+    val page: Int,
+    @Json(name = "total_amount")
+    val totalAmount: String,
+    @Json(name = "total_pages")
+    val totalPages: Int,
+    @Json(name = "reports")
+    val reports: List<ReportDeposit>
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportDeposit(
+    @Json(name = "_id")
+    val _id: String,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "amount")
+    val amount: String,
+    @Json(name = "old_balance")
+    val oldBalance: String,
+    @Json(name = "new_balance")
+    val newBalance: String
+): BaseListItem(){
+    override fun getUnique(): String = _id
+}
+
+@JsonClass(generateAdapter = true)
+data class ReportWithdrawData(
+    @Json(name = "rows_per_page")
+    val rowsPerPage: Int,
+    @Json(name = "total_rows")
+    val totalRows: Int,
+    @Json(name = "page")
+    val page: Int,
+    @Json(name = "total_amount")
+    val totalAmount: String,
+    @Json(name = "total_pages")
+    val totalPages: Int,
+    @Json(name = "reports")
+    val reports: List<ReportWithdraw>
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportWithdraw(
+    @Json(name = "_id")
+    val _id: String,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "amount")
+    val amount: String,
+    @Json(name = "old_balance")
+    val oldBalance: String,
+    @Json(name = "new_balance")
+    val newBalance: String
+): BaseListItem(){
+    override fun getUnique(): String = _id
+}
+
+@JsonClass(generateAdapter = true)
+data class ReportBody(
+    @Json(name = "rows_per_page")
+    val rowsPerPage: Int,
+    @Json(name = "page")
+    val page: Int,
+    @Json(name = "start_date")
+    val startDate: String,
+    @Json(name = "end_date")
+    val endDate: String
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportOneData(
+    @Json(name = "rows_per_page")
+    val rowsPerPage: Int,
+    @Json(name = "total_rows")
+    val totalRows: Int,
+    @Json(name = "page")
+    val page: Int,
+    @Json(name = "total_pages")
+    val totalPages: Int,
+    @Json(name = "is_win")
+    val isWin: Boolean,
+    @Json(name = "turn_over")
+    val turnOver: String,
+    @Json(name = "amount_win_lose")
+    val amountWinLose: String,
+    @Json(name = "reports")
+    val reports: List<ReportOne>
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportOne(
+    @Json(name = "_id")
+    val _id: String,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "payout")
+    val payout: String,
+    @Json(name = "group")
+    val group: Int,
+    @Json(name = "fight_no")
+    val fightNo: Int,
+    @Json(name = "bet_name")
+    val betName: String,
+    @Json(name = "bet_color")
+    val betColor: String,
+    @Json(name = "is_win")
+    val is_win: Boolean? = null,
+    @Json(name = "result_name")
+    val resultName: String,
+    @Json(name = "result_color")
+    val resultColor: String,
+    @Json(name = "amount_win")
+    val amountWin: Int,
+    @Json(name = "amount")
+    val amount: Int,
+    @Json(name = "cast")
+    val cast: Int
+): BaseListItem(){
+    override fun getUnique(): String = _id
+}
+
+@JsonClass(generateAdapter = true)
+data class ReportTwoResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: ReportTwoData
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportTwoData(
+    @Json(name = "rows_per_page")
+    val rowsPerPage: Int,
+    @Json(name = "total_rows")
+    val totalRows: Int,
+    @Json(name = "page")
+    val page: Int,
+    @Json(name = "total_pages")
+    val totalPages: Int,
+    @Json(name = "results")
+    val results: List<ReportTwo>
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportTwo(
+    @Json(name = "_id")
+    val _id: String,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "name")
+    val name: String?,
+    @Json(name = "color")
+    val color: String?,
+    @Json(name = "group_no")
+    val group: Int,
+    @Json(name = "fight_no")
+    val fightNo: Int
+): BaseListItem(){
+    override fun getUnique(): String = _id
+}
+
+@JsonClass(generateAdapter = true)
+data class ReportThreeResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: LoginMessage,
+    @Json(name = "data")
+    val data: List<ReportThree>
+)
+
+@JsonClass(generateAdapter = true)
+data class ReportThree(
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "amount")
+    val amount: Int,
+    @Json(name = "type")
+    val type: String
+): BaseListItem(){
+    override fun getUnique(): String = date
+}

+ 415 - 0
app/src/main/java/com/sambath/sbc/remote/MainDataModel.kt

@@ -0,0 +1,415 @@
+package com.sambath.sbc.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 CfMainResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: MainMessage,
+    @Json(name = "data")
+    val data: CfMainData?
+)
+
+@JsonClass(generateAdapter = true)
+data class MainMessage(
+    @Json(name = "code")
+    val code: String,
+
+    @Json(name = "descriptions")
+    val description: String
+
+)
+
+@JsonClass(generateAdapter = true)
+data class CfMainData(
+    @Json(name = "userInfo")
+    val userInfo: UserInfo,
+    @Json(name = "chanel")
+    val channel: Channel,
+    @Json(name = "lastResult")
+    val lastResult: LastResult?
+)
+
+@JsonClass(generateAdapter = true)
+data class LastResult(
+    @Json(name = "_id")
+    val id: String,
+    @Json(name = "user_id")
+    val user_id: String,
+    @Json(name = "chanel_id")
+    val channelId: String,
+    @Json(name = "fight_no")
+    val fightNo: String,
+    @Json(name = "type_betting")
+    val typeBetting: String,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "no")
+    val no: String,
+    @Json(name = "color")
+    val color: String,
+    @Json(name = "cid")
+    val cid: String,
+    @Json(name = "rid")
+    val rid: String,
+    @Json(name = "group")
+    val group: String
+)
+@JsonClass(generateAdapter = true)
+data class MainData(
+    @Json(name = "userInfo")
+    val userInfo: UserInfo,
+    @Json(name = "chanel")
+    val channel: Channel,
+
+//below will clear soon
+    @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 UserInfo(
+    @Json(name = "account_info")
+    val accountInfo: String?,
+    @Json(name = "account_name")
+    val accountName: String?,
+    @Json(name = "account_number")
+    val accountNumber: Int?,
+    @Json(name = "balance")
+    val balance: Long,
+    @Json(name = "currency_type")
+    val currencyType: String,
+    @Json(name = "enable")
+    val enable: Boolean,
+    @Json(name = "role")
+    val role: String,
+    @Json(name = "user_name")
+    val userName: String
+)
+
+@JsonClass(generateAdapter = true)
+data class Channel(
+    @Json(name = "_id")
+    val id: String,
+    @Json(name = "tem_id")
+    val temId: String,
+    @Json(name = "name")
+    val name: String,
+    @Json(name = "status")
+    val status: String,
+    @Json(name = "info")
+    val info: String,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "type_of_play")
+    val typeOfPlay: String,
+    @Json(name = "fight_no")
+    val fightNo: Int,
+    @Json(name = "group")
+    val group: Int,
+    @Json(name = "amount_red")
+    val amountRed: Int,
+    @Json(name = "payout_red")
+    val payoutRed: Double,
+    @Json(name = "cast_red")
+    val castRed: Long,
+    @Json(name = "amount_equal")
+    val amountEqual: Int,
+    @Json(name = "payout_equal")
+    val payoutEqual: Int,
+    @Json(name = "cast_equal")
+    val castEqual: Int,
+    @Json(name = "amount_blue")
+    val amountBlue: Int,
+    @Json(name = "payout_blue")
+    val payoutBlue: Double,
+    @Json(name = "cast_blue")
+    val castBlue: Long,
+    @Json(name = "weigh_red_blue")
+    val weighRedBlue: Int,
+    @Json(name = "column")
+    val column: Int,
+    @Json(name = "fix_column")
+    val fixColumn: Int,
+    @Json(name = "target")
+    val target: Long,
+    @Json(name = "amount_min")
+    val amountMin: Int,
+    @Json(name = "amount_max")
+    val amountMax: Int,
+) {
+    override fun toString(): String {
+        return "{_id: ${this.id}, tem_id: ${this.temId}, name: ${this.name}, status: ${this.status}, info: ${this.info}, date: ${this.date}, type_of_play: ${this.typeOfPlay}, fight_no: ${this.fightNo}, " +
+                "group: ${this.group}, amount_red: ${this.amountRed}, payout_red: ${this.payoutRed}, cast_red: ${this.castRed}, amount_equal: ${this.amountEqual}, payout_equal: ${this.payoutEqual}, castEqual: ${this.castEqual}, amountBlue: ${this.amountBlue}, " +
+                "payout_blue: ${this.payoutBlue}, cast_blue: ${this.castBlue}, weigh_red_blue: ${this.weighRedBlue}, column: ${this.column}, fix_column: ${this.fixColumn}, target: ${this.target}, amount_min: ${this.amountMin}, amount_max: ${this.amountMax}}"
+    }
+}
+
+@JsonClass(generateAdapter = true)
+data class MyBetting(
+    @Json(name = "_id")
+    var id: String?,
+
+    @Json(name = "tem_id")
+    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
+)
+
+@JsonClass(generateAdapter = true)
+data class TodayReportResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: MainMessage,
+    @Json(name = "data")
+    val data: TodayReportData?
+)
+
+@JsonClass(generateAdapter = true)
+data class TodayReportData(
+    @Json(name = "todayReport")
+    val todayReportList: List<CfTodayReport>?
+)
+
+@JsonClass(generateAdapter = true)
+data class CfTodayReport(
+    @Json(name = "_id")
+    val id: String,
+    @Json(name = "fight_no")
+    val fightNo: Int?,
+    @Json(name = "type_betting")
+    val typeBetting: String?,
+    @Json(name = "amount")
+    val amount: Long?,
+    @Json(name = "payout")
+    val payout: Double?,
+    @Json(name = "cast")
+    val cast: String?,
+    @Json(name = "result")
+    val result: String?,
+    @Json(name = "win_lose")
+    val winLose: String?,
+    @Json(name = "amount_win")
+    val amountWin: String?,
+    @Json(name = "date")
+    val date: String?,
+    @Json(name = "updatedAt")
+    val updateAt: String?,
+): BaseListItem(){
+    override fun getUnique(): String = id
+}
+
+@JsonClass(generateAdapter = true)
+data class CurrentBetsResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: MainMessage,
+    @Json(name = "data")
+    val data: CurrentBetsData?
+)
+
+@JsonClass(generateAdapter = true)
+data class CurrentBetsData(
+    @Json(name = "currenBetting")
+    val currentBetsList: List<CfCurrentBets>?
+)
+
+@JsonClass(generateAdapter = true)
+data class CfCurrentBets(
+    @Json(name = "_id")
+    val id: String,
+    @Json(name = "user_id")
+    val userId: String?,
+    @Json(name = "fight_no")
+    val fightNo: Int?,
+    @Json(name = "group")
+    val group: Int?,
+    @Json(name = "type_betting")
+    val typeBetting: String,
+    @Json(name = "amount")
+    val amount: Long,
+    @Json(name = "payout")
+    val payout: Double,
+    @Json(name = "cast")
+    val cast: Long?,
+    @Json(name = "win_lose")
+    val winLose: Boolean?,
+    @Json(name = "amount_win")
+    val amountWin: Long?,
+    @Json(name = "date")
+    val date: String,
+    @Json(name = "updatedAt")
+    val updateAt: String?,
+): BaseListItem(){
+    override fun getUnique(): String = id
+}
+
+@JsonClass(generateAdapter = true)
+data class StatementResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: MainMessage,
+    @Json(name = "data")
+    val data: StatementData?
+)
+
+@JsonClass(generateAdapter = true)
+data class StatementData(
+    @Json(name = "statement")
+    val statementList: List<CfStatement>?
+)
+
+@JsonClass(generateAdapter = true)
+data class CfStatement(
+    @Json(name = "_id")
+    val id: String,
+    @Json(name = "date")
+    val date: String?,
+    @Json(name = "note")
+    val note: String?,
+    @Json(name = "note_khmer")
+    val noteKhmer: String?,
+    @Json(name = "amount")
+    val amount: Int?,
+    @Json(name = "amount_win")
+    val amountWin: Int?,
+    @Json(name = "trun_over")
+    val trunOver: Int?,
+): BaseListItem(){
+    override fun getUnique(): String = id
+}
+
+@JsonClass(generateAdapter = true)
+data class CreateBetResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: MainMessage,
+    @Json(name = "data")
+    val data: CreateBetData?
+)
+
+@JsonClass(generateAdapter = true)
+data class CreateBetData(
+    @Json(name = "account_balances")
+    val accountBalances: Double?,
+    @Json(name = "chanel")
+    val channel: Channel?,
+    @Json(name = "print")
+    val print: Print?
+)
+
+@JsonClass(generateAdapter = true)
+class CreateBetting(
+    @Json(name = "amount")
+    val amount: Int,
+    @Json(name = "chicken_id")
+    val chickenId: String
+)
+
+@JsonClass(generateAdapter = true)
+data class Print(
+    @Json(name = "fight_no")
+    var fightNo: String,
+    @Json(name = "date")
+    var date: String,
+    @Json(name = "user_name")
+    var userName: String,
+    @Json(name = "type_betting")
+    var typeBetting: String,
+    @Json(name = "amount")
+    var amount: String,
+    @Json(name = "payout_rate")
+    var payoutRate: String,
+    @Json(name = "payout")
+    var payout: String,
+)
+

+ 93 - 0
app/src/main/java/com/sambath/sbc/remote/PlayDataModel.kt

@@ -0,0 +1,93 @@
+package com.sambath.sbc.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/sambath/sbc/remote/ReportDataModel.kt

@@ -0,0 +1,153 @@
+package com.sambath.sbc.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
+
+}
+

+ 126 - 0
app/src/main/java/com/sambath/sbc/remote/ResultDataModel.kt

@@ -0,0 +1,126 @@
+package com.sambath.sbc.remote
+import com.google.gson.annotations.SerializedName
+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 CfResultResponse(
+    @Json(name = "code")
+    val resultCode: String,
+    @Json(name = "message")
+    val message: ResultMessage,
+    @Json(name = "data")
+    val data: CfResultData?
+)
+
+@JsonClass(generateAdapter = true)
+data class CfResultData(
+    @Json(name = "chanel")
+    val channel: Channel?,
+    @Json(name = "result")
+    val resultList: List<ResultCf>?
+)
+
+@JsonClass(generateAdapter = true)
+data class ResultCf(
+    @Json(name ="_id")
+    val id: String? = null,
+    @Json(name ="user_id")
+    val userId: String? = null,
+    @Json(name ="chanel_id")
+    val chanelId: String? = null,
+    @Json(name ="fight_no")
+    val fightNo: String? = null,
+    @Json(name ="type_betting")
+    val beetingType: String? = null,
+    @Json(name ="date")
+    val tWalaTotalAmount: String? = null,
+    @Json(name ="no")
+    val no: String? = null,
+    @Json(name ="color")
+    val color: String? = null,
+    @Json(name ="cid")
+    val colunmId: Int? = null,
+    @Json(name ="rid")
+    val rowId: Int? = null,
+    @Json(name ="group")
+    val group: String? = null,
+)
+
+@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
+)
+
+data class CfResult(
+    @SerializedName("_id")
+    var id: String? = null,
+    @SerializedName("user_id")
+    var userId: String? = null,
+    @SerializedName("chanel_id")
+    var chanelId: String? = null,
+    @SerializedName("fight_no")
+    var fightNo: String? = null,
+    @SerializedName("type_betting")
+    var beetingType: String? = null,
+    @SerializedName("date")
+    var tWalaTotalAmount: String? = null,
+    @SerializedName("no")
+    var no: String? = null,
+    @SerializedName("color")
+    var color: String? = null,
+    @SerializedName("cid")
+    var colunmId: Int? = null,
+    @SerializedName("rid")
+    var rowId: Int? = null,
+    @SerializedName("group")
+    var group: String? = null,
+){}
+

+ 15 - 0
app/src/main/java/com/sambath/sbc/remote/SocketMessageDataModel.kt

@@ -0,0 +1,15 @@
+package com.sambath.sbc.remote
+
+import org.json.JSONArray
+
+
+data class SocketMessageDataModel(
+    val type: String,
+    val countDown: Int?= null,
+    val resultArray: JSONArray? = null,
+    val totalValue: Int?= null
+
+){
+    fun isCountDowning() = countDown != null && resultArray == null
+
+}

+ 30 - 0
app/src/main/java/com/sambath/sbc/remote/UpdatePwdDataModel.kt

@@ -0,0 +1,30 @@
+package com.sambath.sbc.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,
+)
+

+ 66 - 0
app/src/main/java/com/sambath/sbc/remote/service/ApiService.kt

@@ -0,0 +1,66 @@
+package com.sambath.sbc.remote.service
+
+import com.sambath.sbc.remote.*
+import io.reactivex.Single
+import retrofit2.http.*
+
+interface ApiService {
+
+    @POST("/v1/api/user/login")
+    @Headers("No-Authentication: true")
+    fun login(@Body loginRequest: LoginRequest): Single<LoginResponse>
+
+//    @POST("/v1/api/user/register")
+//    fun createBetting(@Body register: Register): Single<RegisterResponse>
+
+    @POST("/v1/api/user/changepassword")
+    fun changePassword(@Body changePwd: ChangePwd): Single<ChangePwdResponse>
+
+//    @GET("/v1/api/user")
+//    fun getUserInfo(): Single<UserInfoResponse>
+//
+//    @PUT("/v1/api/user")
+//    fun updateUserInfo(@Body updateUser: UpdateUser): Single<UpdateResponse>
+
+    @GET("/v1/api/channel")
+    fun getChannel(): Single<ChannelResponse>
+
+    @GET("/v1/api/user")
+    fun getUser(): Single<UserResponse>
+
+    @GET("/v1/api/weight")
+    fun getWeight(): Single<WeightResponse>
+
+    @GET("/v1/api/type")
+    fun getBettingType(): Single<BettingTypeResponse>
+
+    @GET("/v1/api/result")
+    fun getResult(): Single<ResultsResponse>
+
+    @POST("/v1/api/betting")
+    fun createBetting(@Body createBetting: CreateBetting): Single<BettingResponse>
+
+    @GET("/v1/api/betting/current")
+    fun getCurrentBetting(): Single<CurrentResponse>
+
+    @GET("/v1/api/betting/today")
+    fun getTodayReport(): Single<TodayResponse>
+
+    @GET("/v1/api/button")
+    fun getButton(): Single<ButtonResponse>
+
+    @POST("/v1/api/report/deposit")
+    fun getReportDeposit(@Body reportBetting: ReportBody): Single<ReportDepositResponse>
+
+    @POST("/v1/api/report/withdraw")
+    fun getReportWithdraw(@Body reportBetting: ReportBody): Single<ReportWithdrawResponse>
+
+    @POST("/v1/api/report/betting")
+    fun getReportOne(@Body reportBetting: ReportBody): Single<ReportOneResponse>
+
+    @POST("/v1/api/result/filter")
+    fun getReportTwo(@Body reportBetting: ReportBody): Single<ReportTwoResponse>
+
+    @GET("/v1/api/report")
+    fun getReportThree(): Single<ReportThreeResponse>
+}

+ 19 - 0
app/src/main/java/com/sambath/sbc/remote/service/ConnectivityStates.java

@@ -0,0 +1,19 @@
+package com.sambath.sbc.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 ;
+
+}

+ 29 - 0
app/src/main/java/com/sambath/sbc/remote/service/EventListener.java

@@ -0,0 +1,29 @@
+package com.sambath.sbc.remote.service;
+
+public interface EventListener {
+
+    void onConnect();
+
+    void onConnectionError() ;
+
+    void onReconnect();
+
+    void onReconnectionTimeout();
+
+    void onDisconnect();
+
+    void onUpdateChannelInfo(String data);
+
+    void onDefinedResultAndChannel(String data);
+
+    void onUpdateUserInfo(String data);
+
+    void onUpdateBettingAmount(String data);
+
+    void onUpdatePayout(String data);
+
+    void onReverseRseult(String data);
+
+    void onResetAmount(String data);
+
+}

+ 141 - 0
app/src/main/java/com/sambath/sbc/remote/service/SocketService.java

@@ -0,0 +1,141 @@
+package com.sambath.sbc.remote.service;
+
+import static java.util.Collections.singletonList;
+import static java.util.Collections.singletonMap;
+
+import android.util.Log;
+
+import com.sambath.sbc.config.Config;
+import com.sambath.sbc.util.BaseObservable;
+
+import org.json.JSONObject;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import io.socket.client.IO;
+import io.socket.client.Socket;
+import io.socket.emitter.Emitter;
+
+public class SocketService extends BaseObservable<EventListener> {
+    private static final String TAG = "Socket";
+    private static final String SOCKET_1 = Config.SOCKET_1;
+    private static final String SOCKET_2 = Config.SOCKET_2;
+    private static final String SOCKET_3 = Config.SOCKET_3;
+    private static final String SOCKET_4 = Config.SOCKET_4;
+    private static final String EVENT_CONNECT = Socket.EVENT_CONNECT;
+    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_UPDATE_CHANNEL_INFO = "client-update-channel-info";
+    private static final String EVENT_DEFINED_RESULT_AND_CHANNEL = "client-defind-result-and-new-channel";
+    private static final String EVENT_UPDATE_USER_INFO = "client-update-user-info";
+    private static final String EVENT_UPDATE_BETTING_AMOUNT = "client-update-betting-amount";
+    private static final String EVENT_UPDATE_PAYOUT = "client-update-payout";
+    private static final String EVENT_REVERSE_RESULT = "client-reserves-result";
+    private static final String EVENT_RESET_AMOUNT = "client-reset-amount";
+    private Socket mSocket;
+
+    public void startListening(String token, int channelType) throws URISyntaxException {
+        IO.Options options = IO.Options.builder()
+                .setExtraHeaders(singletonMap("authorization", singletonList(token)))
+                .build();
+        Log.d("Socket", "startListening mSocket"+ channelType);
+        if (channelType == 2) {
+            mSocket = IO.socket(URI.create(SOCKET_2), options);
+        } else if (channelType == 3) {
+            mSocket = IO.socket(URI.create(SOCKET_3), options);
+        } else if(channelType == 4) {
+            mSocket = IO.socket(URI.create(SOCKET_4), options);
+        } else {
+            mSocket = IO.socket(URI.create(SOCKET_1), options);
+        }
+        mSocket.on(EVENT_CONNECT, connectListener);
+        mSocket.on(EVENT_UPDATE_CHANNEL_INFO, updateChannelInfo);
+        mSocket.on(EVENT_DEFINED_RESULT_AND_CHANNEL, definedResultAndChannel);
+        mSocket.on(EVENT_UPDATE_USER_INFO, updateUserInfo);
+        mSocket.on(EVENT_UPDATE_BETTING_AMOUNT, updateBettingAmount);
+        mSocket.on(EVENT_UPDATE_PAYOUT, updatePayout);
+        mSocket.on(EVENT_REVERSE_RESULT, reverseResult);
+        mSocket.on(EVENT_RESET_AMOUNT, resetAmount);
+        mSocket.on(EVENT_DISCONNECT, disconnectListener);
+        mSocket.on(EVENT_CONNECT_ERROR, connectionErrorListener);
+        mSocket.connect();
+    }
+
+    private Emitter.Listener updateChannelInfo = args -> {
+        Log.d("Socket", "updateChannelInfo s...fghfhgfhgfhfghgf");
+        final String rawMessage = args[0].toString();
+        for (EventListener listener : getListeners())
+            listener.onUpdateChannelInfo(rawMessage);
+    };
+    private Emitter.Listener definedResultAndChannel = args -> {
+        Log.d("Socket", "definedResultAndChannel s...fghfhgfhgfhfghgf");
+        final String rawMessage = args[0].toString();
+        for (EventListener listener : getListeners())
+            listener.onDefinedResultAndChannel(rawMessage);
+    };
+    private Emitter.Listener updateUserInfo = args -> {
+        Log.d("Socket", "updateUserInfo s...fghfhgfhgfhfghgf");
+        final String rawMessage = args[0].toString();
+        for (EventListener listener : getListeners())
+            listener.onUpdateUserInfo(rawMessage);
+    };
+    private Emitter.Listener updateBettingAmount = args -> {
+        Log.d("Socket", "updateBettingAmount s...fghfhgfhgfhfghgf");
+        final String rawMessage = args[0].toString();
+        for (EventListener listener : getListeners())
+            listener.onUpdateBettingAmount(rawMessage);
+    };
+    private Emitter.Listener updatePayout = args -> {
+        Log.d("Socket", "updatePayout s...fghfhgfhgfhfghgf");
+        final String rawMessage = args[0].toString();
+        for (EventListener listener : getListeners())
+            listener.onUpdatePayout(rawMessage);
+    };
+    private Emitter.Listener reverseResult = args -> {
+        Log.d("Socket", "reverseResult s...fghfhgfhgfhfghgf");
+        final String rawMessage = args[0].toString();
+        for (EventListener listener : getListeners())
+            listener.onReverseRseult(rawMessage);
+    };
+    private Emitter.Listener resetAmount = args -> {
+        Log.d("Socket", "resetAmount s...fghfhgfhgfhfghgf");
+        final String rawMessage = args[0].toString();
+        for (EventListener listener : getListeners())
+            listener.onResetAmount(rawMessage);
+    };
+    private Emitter.Listener connectListener = args -> {
+        Log.d("Socket", "onConnect s...fghfhgfhgfhfghgf");
+        for (EventListener listener : getListeners())
+            listener.onConnect();
+    };
+
+    public void stopListening() {
+        if (mSocket != null)
+            mSocket.disconnect();
+    }
+
+    public void switchChannel(String token, int channelType) throws URISyntaxException {
+        if (mSocket != null)
+            mSocket.disconnect();
+        startListening(token, channelType);
+    }
+
+    public void startEmitCfCreateBetting(JSONObject joinObject) {
+        mSocket.emit("player-betting", joinObject);
+    }
+
+    private Emitter.Listener connectionErrorListener = args -> {
+//        Log.d(TAG,"onConnectionError s..."+args[0].toString());
+        for (EventListener listener : getListeners())
+            listener.onConnectionError();
+    };
+
+    private Emitter.Listener disconnectListener = args -> {
+//        Log.d(TAG,"onDisconnect s..."+args[0].toString());
+        mSocket.off();
+        for (EventListener listener : getListeners()) {
+            listener.onDisconnect();
+        }
+    };
+}

+ 71 - 0
app/src/main/java/com/sambath/sbc/screen/login/LoginActivity.kt

@@ -0,0 +1,71 @@
+package com.sambath.sbc.screen.login
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.Observer
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.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)
+        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 //aaaaaa004  Bbbbbb001
+            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()
+
+    }
+}

+ 67 - 0
app/src/main/java/com/sambath/sbc/screen/login/LoginViewModel.kt

@@ -0,0 +1,67 @@
+package com.sambath.sbc.screen.login
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.remote.LoginRequest
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.ModelPreferencesManager
+import com.sambath.sbc.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(10, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    Log.d("login", it.toString())
+                    if (it.resultCode == "1") {
+                        _state.value = prev().copy(isProgress = false, isLoginSuccess = true)
+                        prefHelper.setUserToken(it.data?.token ?: "")
+                        prefHelper.setChannelType(1)
+                        ModelPreferencesManager.put(it.data?.user, Const.USER_KEY)
+                    } else {
+                        _state.value =
+                            prev().copy(isProgress = false, error = "[${it.message.description}]")
+                    }
+                }, {
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ " + 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!!
+
+
+}

+ 8 - 0
app/src/main/java/com/sambath/sbc/screen/login/LoginViewState.kt

@@ -0,0 +1,8 @@
+package com.sambath.sbc.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/sambath/sbc/screen/main/MainAdapter.kt

@@ -0,0 +1,21 @@
+package com.sambath.sbc.screen.main
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.sambath.sbc.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
+        )
+
+
+}

+ 22 - 0
app/src/main/java/com/sambath/sbc/screen/main/MainDataViewState.kt

@@ -0,0 +1,22 @@
+package com.sambath.sbc.screen.main
+
+import com.sambath.sbc.remote.*
+
+data class MainDataViewState(
+//    val isSuccess: Boolean = false,
+//    val channel: Channel? = null,
+//    val initial: Boolean = false,
+//    val isProgress: Boolean = false,
+//    val error: String? = null,
+//    val lastResult: LastResult? = null,
+
+    val isChPro: Boolean = false,
+    val errorCh: String? = null,
+    val channelInfo: ChannelData? = null,
+    val isChSuccess: Boolean = false,
+
+    val isUserPro: Boolean = false,
+    val errorUser: String? = null,
+    val userInfo: User? = null,
+    val isUserSuccess: Boolean = false,
+)

+ 170 - 0
app/src/main/java/com/sambath/sbc/screen/main/MainFragment.kt

@@ -0,0 +1,170 @@
+package com.sambath.sbc.screen.main
+
+import android.annotation.SuppressLint
+import android.media.MediaPlayer
+import android.os.Bundle
+import android.view.View
+import android.view.animation.AlphaAnimation
+import android.view.animation.Animation
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.viewpager2.widget.ViewPager2
+import com.google.android.material.tabs.TabLayout
+import com.google.android.material.tabs.TabLayoutMediator
+import com.sambath.sbc.R
+import com.sambath.sbc.adapter.MainPagerAdapter
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.base.BaseFragment
+import com.sambath.sbc.extension.btnClick
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.screen.main.cflive.Betting.CfBetFragment
+import com.sambath.sbc.screen.main.cflive.result.CfResultFragment
+import com.sambath.sbc.screen.report.StatementFragment
+import com.sambath.sbc.screen.setting.SettingFragment
+import com.sambath.sbc.view.SettingButtonView
+
+/**
+ * A simple [Fragment] subclass as the default destination in the navigation.
+ */
+class MainFragment : BaseFragment(R.layout.fragment_main) {
+    private val TAB_TITLES = arrayOf(
+        R.string.current_bets,
+        R.string.today_report,
+    )
+    private lateinit var mainViewModel: MainViewModel
+    private val shareViewModel = App.injectShareViewModel()
+    private val sharePref = App.injectPrefHelper()
+    private lateinit var user: User
+    private lateinit var btnPlay: SettingButtonView
+    private lateinit var btnResult: SettingButtonView
+    private lateinit var betTouch: MediaPlayer
+    lateinit var result: MediaPlayer
+    private var anim: AlphaAnimation? = null
+    override fun onCreate(savedInstanceState: Bundle?) {
+//        mainViewModel = MainViewModel(App.injectApiService(), App.injectPrefHelper())
+        super.onCreate(savedInstanceState)
+        //companyInfoId =arguments?.getInt(COM_INTO_ID_KEY) ?: 0
+        (requireActivity() as ShareActivity).apply {
+            user = userShare
+        }
+        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
+    }
+
+    @SuppressLint("CheckResult")
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+//        mainViewModel.state.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+//            getMainData(it)
+//        })
+//        mainViewModel.getMainData()
+//        (requireActivity() as ShareActivity).apply {
+//            userNameTextView.text = user.userName
+//        }
+        val mainPagerAdapter = MainPagerAdapter(requireActivity() as ShareActivity)
+        val viewPager: ViewPager2 = view.findViewById(R.id.view_pager)
+        viewPager.adapter = mainPagerAdapter
+        val tabs: TabLayout = view.findViewById(R.id.tabLayout)
+        TabLayoutMediator(
+            tabs, viewPager
+        ) { tab, position -> // Styling each tab here
+            tab.text = getString(TAB_TITLES[position])
+        }.attach()
+//        shareViewModel.getConnectivityStates.observe(viewLifecycleOwner, Observer {
+//            getSocketConectionStatus(it)
+//        })
+        btnPlay = view.findViewById(R.id.btn_play)
+        btnPlay.setOnClickListener {
+//            if (!sharePref.getIsMute()) betTouch.start()
+            it.btnClick().subscribe {
+//                btnPlay.isEnabled = false
+                (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, CfBetFragment().apply {
+                            arguments =
+                                Bundle().apply {
+                                    // putInt(Fragment7.COM_INFO_ID_KEY, companyInfoId)
+                                }
+                        })
+                        .addToBackStack(null)
+                        .commit()
+                }
+            }
+        }
+        btnResult = view.findViewById(R.id.btn_result)
+        btnResult.setOnClickListener {
+//            if (!sharePref.getIsMute()) betTouch.start()
+            it.btnClick().subscribe {
+//                btnResult.isEnabled = false
+                (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, CfResultFragment().apply {
+                            arguments =
+                                Bundle().apply {
+                                    // putInt(Fragment7.COM_INFO_ID_KEY, companyInfoId)
+                                }
+                        })
+                        .addToBackStack(null)
+                        .commit()
+                }
+            }
+        }
+        (requireActivity() as? ShareActivity)?.apply {
+            groupToolbarIcons.isVisible = true
+            layCfStatus.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()
+                }
+            }
+
+            reportImageView.setOnClickListener {
+//                if (!sharePref.getIsMute()) betTouch.start()
+                layCfStatus.isVisible = true
+                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()
+                }
+            }
+        }
+    }
+}

+ 10 - 0
app/src/main/java/com/sambath/sbc/screen/main/MainListItem.kt

@@ -0,0 +1,10 @@
+package com.sambath.sbc.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/sambath/sbc/screen/main/MainListViewHolder.kt

@@ -0,0 +1,75 @@
+package com.sambath.sbc.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.sambath.sbc.R
+import com.sambath.sbc.extension.btnClick
+import com.sambath.sbc.extension.setSafeOnClickListener
+import com.sambath.sbc.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)
+
+                    }
+                }
+
+
+            }
+
+
+        }
+
+    }
+
+
+
+}

+ 122 - 0
app/src/main/java/com/sambath/sbc/screen/main/MainViewModel.kt

@@ -0,0 +1,122 @@
+package com.sambath.sbc.screen.main
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.screen.main.cflive.result.CfResultViewState
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.ModelPreferencesManager
+import com.sambath.sbc.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class MainViewModel(val apiService: ApiService, val prefHelper: PrefHelper): BaseViewModel() {
+    private val _stateChannel = MutableLiveData(MainDataViewState())
+    val stateChannel: LiveData<MainDataViewState> = _stateChannel
+    fun getChannel(){
+        if (_stateChannel.value!!.isUserPro) return
+        _stateChannel.value = prevChannel().copy(isUserPro = true)
+        disposables.add(
+            apiService.getChannel()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        _stateChannel.value = prevChannel().copy(
+                            isUserPro = false,
+                            errorUser = null,
+                            channelInfo = it.data,
+                            isChSuccess = true
+                        )
+                    } else {
+                        _stateChannel.value =
+                            prevChannel().copy(isUserPro = false, errorUser = "[${it.message.description}]")
+                    }
+                }, {
+//                    Log.d("dataxzsd", it.getErrorCode())
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                    _stateChannel.value = prevChannel().copy(isUserPro = false, errorUser = message)
+                })
+        )
+    }
+    private fun prevChannel() = _stateChannel.value!!
+
+    private val _stateUser = MutableLiveData(MainDataViewState())
+    val stateUser: LiveData<MainDataViewState> = _stateUser
+    fun getUser(){
+        if (_stateUser.value!!.isUserPro) return
+        _stateUser.value = prevUser().copy(isUserPro = true)
+        disposables.add(
+            apiService.getUser()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        ModelPreferencesManager.put(it.data, Const.USER_KEY)
+                        _stateUser.value = prevUser().copy(
+                            isUserPro = false,
+                            errorUser = null,
+                            userInfo = it.data,
+                            isUserSuccess = true
+                        )
+                    } else {
+                        _stateUser.value =
+                            prevChannel().copy(isUserPro = false, errorUser = "[${it.message.description}]")
+                    }
+                }, {
+//                    Log.d("dataxzsd", it.getErrorCode())
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                    _stateUser.value = prevUser().copy(isUserPro = false, errorUser = message)
+                })
+        )
+    }
+    private fun prevUser() = _stateUser.value!!
+
+    private val _state = MutableLiveData<CfResultViewState>(CfResultViewState())
+    val state: LiveData<CfResultViewState> = _state
+    fun getCfResuleData(){
+        if (_state.value!!.isProgress) return
+        _state.value = prev().copy(isProgress = true)
+        disposables.add(
+            apiService.getResult()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+//                        Log.d("dataxzsd", it.data.toString())
+                        _state.value = prev().copy(
+                            isProgress = false,
+                            error = null,
+                            isSuccess = true,
+                            resultList = it.data?.results,
+                            resultSummary = it.data?.resultSummary
+                        )
+                    } else {
+                        _state.value =
+                            prev().copy(
+                                isProgress = false,
+                                isSuccess = false,
+                                error = "[${it.message.description}]"
+                            )
+                    }
+                }, {
+//                    Log.d("dataxzsd", it.getErrorCode())
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                    _state.value = prev().copy(
+                        isProgress = false,
+                        isSuccess = false,
+                        error = message
+                    )
+                })
+        )
+    }
+
+    private fun prev() = _state.value!!
+
+}

+ 444 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/Betting/CfBetFragment.kt

@@ -0,0 +1,444 @@
+package com.sambath.sbc.screen.main.cflive.Betting
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.appcompat.app.AlertDialog
+import androidx.core.view.isVisible
+import androidx.lifecycle.Observer
+import com.google.android.material.button.MaterialButton
+import com.google.gson.Gson
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.base.BaseFragment
+import com.sambath.sbc.extension.btnClick
+import com.sambath.sbc.remote.BtnData
+import com.sambath.sbc.remote.CreateBetting
+import com.sambath.sbc.remote.K
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.LogOutTimerUtil
+import com.sambath.sbc.util.ModelPreferencesManager
+import com.sambath.sbc.util.PrefHelper
+import kotlinx.android.synthetic.*
+import kotlinx.android.synthetic.main.app_bar.*
+import kotlinx.android.synthetic.main.fragment_cf_betting.*
+import org.json.JSONArray
+import org.json.JSONObject
+
+class CfBetFragment : BaseFragment(R.layout.fragment_cf_betting) {
+    private lateinit var btnClose: MaterialButton
+    private lateinit var cfBetViewModel: CfBetViewModel
+    private val shareViewModel = App.injectShareViewModel()
+    private val gson = Gson()
+    private var betMin: Int = 5000
+    private var betMax: Int = 500000
+    private var channelId: String = ""
+    private var betDate: String = ""
+    private var meronId: String = "615d4a899e9ab44fe23eb9db"
+    private var walaId: String = "615d4aa59e9ab44fe23eb9dd"
+    private var betAmount: Int = 0
+    private var fightNo: Int = 0
+    private var isStopBetting: String = "null"
+    lateinit var userShare: User
+    private lateinit var sharePref: PrefHelper
+    private var btnMaster: List<BtnData> = arrayListOf()
+    private val prefHelper = App.injectPrefHelper()
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        sharePref = App.injectPrefHelper()
+        cfBetViewModel = CfBetViewModel(App.injectApiService(), App.injectPrefHelper())
+        ModelPreferencesManager.get<User>(
+            Const.USER_KEY
+        )?.let {
+            userShare = it
+        }
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        (requireActivity() as? ShareActivity)?.apply {
+            groupToolbarIcons.isVisible = false
+            btnClose = view.findViewById<MaterialButton>(R.id.btn_close)
+            btnClose.setOnClickListener {
+//                if (!sharePref.getIsMute()) betTouch.start()
+                shareViewModel.setUpdateFlagMain(true)
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+            }
+        }
+        txtMax.text = currencyFormat(betMax)
+        txtMin.text = currencyFormat(betMin)
+        cfBetViewModel.getMaster()
+        cfBetViewModel.getBtnMaster()
+//        cfBetViewModel.getWeight()
+        cfBetViewModel.stateMaster.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+            if (it?.isSuccess == true) {
+                Log.d("stateMaster", it.toString())
+                if (it.bettingTypeData != null) {
+                    if (it.bettingTypeData.isNotEmpty()) {
+                        meronId = it.bettingTypeData[0]._id
+                        walaId = it.bettingTypeData[1]._id
+                    }
+                }
+            }
+        })
+        cfBetViewModel.stateBtn.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+            btnMaster(it)
+        })
+        cfBetViewModel.state.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+            updateInfo(it)
+        })
+        cfBetViewModel.stateWeight.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+            Log.d("stateUser", it.toString())
+            if (it?.isSuccess == true) {
+                if (it.weightData != null) {
+                    betMin = it.weightData.amountMin
+                    betMax = it.weightData.amountMax
+                    txtMax.text = currencyFormat(betMax)
+                    txtMin.text = currencyFormat(betMin)
+                    txtMeronAmount.text = it.weightData.meron?.amount
+                    txtMeronPayout.text = it.weightData.meron?.payout
+                    txtWalaAmount.text = it.weightData.wala?.amount
+                    txtWalaPayout.text = it.weightData.wala?.payout
+                }
+            }
+        })
+//      test user read only or not
+        if (userShare.readOnly) {
+            btnBetMeron.isEnabled = true
+            btnBetWala.isEnabled = true
+        } else {
+            btnBetMeron.isEnabled = false
+            btnBetWala.isEnabled = false
+        }
+//        Red side betting
+        btnBetMeron.setOnClickListener {
+            LogOutTimerUtil.resetLogoutTimer(null, null)
+            createBetting(K.Meron, meronId)
+        }
+//        Blue side betting
+        btnBetWala.setOnClickListener {
+            LogOutTimerUtil.resetLogoutTimer(null, null)
+            createBetting(K.Wala, walaId)
+        }
+        btnClear.setOnClickListener {
+            betAmount = 0
+            edtBettingAmount.setText("")
+        }
+        btnZero.setOnClickListener {
+            betAmount += btnMaster[0].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+        btnOne.setOnClickListener {
+            betAmount += btnMaster[1].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+        btnTwo.setOnClickListener {
+            betAmount += btnMaster[2].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+        btnThree.setOnClickListener {
+            betAmount += btnMaster[3].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+        btnFour.setOnClickListener {
+            betAmount += btnMaster[4].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+        btnFive.setOnClickListener {
+            betAmount += btnMaster[5].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+        btnSix.setOnClickListener {
+            betAmount += btnMaster[6].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+        btnSeven.setOnClickListener {
+            betAmount += btnMaster[7].amount
+            edtBettingAmount.setText(betAmount.toString())
+        }
+
+        txt_clear.setOnClickListener {
+            val string = edtBettingAmount.text.toString()
+            if (string.isNotEmpty()) {
+                edtBettingAmount.setText(string.substring(0, string.length - 1))
+            }
+        }
+        shareViewModel.getUpdatePayout.observe(viewLifecycleOwner, Observer {
+            Log.d("getUpdatePayout", "onUpdatePlayerBetting" + it)
+            if (!it.isNullOrEmpty()) {
+                if (isStopBetting == "true") {
+                    val obj = JSONObject(it)
+                    if (obj.getInt("currency_type") == userShare.currencyType) {
+                        txtMeronPayout.text = obj.getString("payout_wala")
+                        txtWalaPayout.text = obj.getString("payout_meron")
+                    }
+                }
+            }
+        })
+        shareViewModel.getResetAmount.observe(viewLifecycleOwner, Observer {
+            Log.d("getResetAmount", "onUpdatePlayerBetting" + it)
+            txtMeronAmount.text = "0"
+            txtWalaAmount.text = "0"
+        })
+        shareViewModel.getChannelInfo.observe(viewLifecycleOwner, Observer {
+            if (it != null) {
+                channelId = it.id
+                fightNo = it.fightNo
+                betDate = it.date
+                isStopBetting = if (it.is_open.toString().isEmpty()) {
+                    "null"
+                } else {
+                    it.is_open.toString()
+                }
+                layMeronPayout.visibility = View.VISIBLE
+                layWalaPayout.visibility = View.VISIBLE
+                if (userShare.readOnly) {
+                    when (isStopBetting) {
+                        "true" -> {
+                            btnBetMeron.isEnabled = true
+                            btnBetWala.isEnabled = true
+                        }
+                        "false" -> {
+                            btnBetMeron.isEnabled = false
+                            btnBetWala.isEnabled = false
+                        }
+                        else -> {
+                            btnBetMeron.isEnabled = false
+                            btnBetWala.isEnabled = false
+                            layMeronPayout.visibility = View.INVISIBLE
+                            layWalaPayout.visibility = View.INVISIBLE
+//                            txtMeronAmount.text = currencyFormat(it.amountRed)
+//                            txtWalaAmount.text = currencyFormat(it.amountBlue)
+//                            txtMeronPayout.text = it.payoutRed.toString()
+//                            txtWalaPayout.text = it.payoutBlue.toString()
+                        }
+                    }
+                } else {
+                    btnBetMeron.isEnabled = false
+                    btnBetWala.isEnabled = false
+                    if (isStopBetting == "null") {
+                        layMeronPayout.visibility = View.INVISIBLE
+                        layWalaPayout.visibility = View.INVISIBLE
+                    }
+                }
+            }
+        })
+        shareViewModel.getUpdatePayout.observe(viewLifecycleOwner, Observer {
+            Log.d("getUpdatePayout", "onUpdatePlayerBetting" + it)
+            if (!it.isNullOrEmpty()) {
+                val obj = JSONObject(it)
+                if (userShare.currencyType == obj.getInt("currency_type")) {
+                    txtMeronPayout.text = obj.getString("payout_meron")
+                    txtWalaPayout.text = obj.getString("payout_wala")
+                }
+            }
+        })
+        shareViewModel.onUpdateBettingAmount.observe(viewLifecycleOwner, Observer {
+            Log.d("onUpdateBettingAmount", "onUpdatePlayerBetting" + it)
+            if (!it.isNullOrEmpty()) {
+                val arr = JSONArray(it)
+                txtMeronAmount.text =
+                    arr.getJSONObject(userShare.currencyType - 1).getString("meron_amount")
+                txtWalaAmount.text =
+                    arr.getJSONObject(userShare.currencyType - 1).getString("wala_amount")
+            }
+        })
+        shareViewModel.onUpdateChanelDeveloper.observe(viewLifecycleOwner, Observer {
+            if (!it.isNullOrEmpty()) {
+//                Log.d("getUpdateData", "onUpdateChanelDeveloper" + it)
+                val obj = JSONObject(it)
+                betMin = obj.getInt("amount_min")
+                betMax = obj.getInt("amount_max")
+                txtMax.text = currencyFormat(betMax)
+                txtMin.text = currencyFormat(betMin)
+            }
+        })
+        shareViewModel.getUpdateData.observe(viewLifecycleOwner, Observer {
+            channelId = it.getString(K.ChannelId)
+            fightNo = it.getInt(K.Fight_No)
+            betDate = it.getString(K.date)
+//            Log.d("getMain", "datalive Channel ID" + channelId)
+            txtMeronAmount.text = currencyFormatKh(it.getDouble(K.CastRed))
+            txtWalaAmount.text = currencyFormatKh(it.getDouble(K.CastBlue))
+            txtMeronPayout.text = it.getString(K.PayoutRed)
+            txtWalaPayout.text = it.getString(K.PayoutBlue)
+            layMeronPayout.visibility = View.VISIBLE
+            layWalaPayout.visibility = View.VISIBLE
+            if (userShare.readOnly) {
+                when {
+                    it.getString(K.TypeOfPlay) == K.Open -> {
+                        btnBetMeron.isEnabled = true
+                        btnBetWala.isEnabled = true
+                    }
+                    it.getString(K.TypeOfPlay) == K.Close -> {
+                        btnBetMeron.isEnabled = false
+                        btnBetWala.isEnabled = false
+                    }
+                    else -> {
+                        btnBetMeron.isEnabled = false
+                        btnBetWala.isEnabled = false
+                        layMeronPayout.visibility = View.INVISIBLE
+                        layWalaPayout.visibility = View.INVISIBLE
+//                        txtMeronAmount.text = amountRed
+//                        txtWalaAmount.text = amountBlue
+//                        txtMeronPayout.text = payoutRed
+//                        txtWalaPayout.text = payoutBlue
+                    }
+                }
+            } else {
+                btnBetMeron.isEnabled = false
+                btnBetWala.isEnabled = false
+                if (it.getString(K.TypeOfPlay) == K.Live) {
+                    layMeronPayout.visibility = View.INVISIBLE
+                    layWalaPayout.visibility = View.INVISIBLE
+                }
+            }
+            betMin = it.getInt("amount_min")
+            betMax = it.getInt("amount_max")
+            txtMax.text = currencyFormat(betMax)
+            txtMin.text = currencyFormat(betMin)
+        })
+    }
+
+    private fun confirmBet(betType: String, moneyBet: Int, chickenId: String) {
+        val builder = context?.let { AlertDialog.Builder(it) }
+        //set title for alert dialog
+        builder?.setTitle("Confirm betting!")
+        //set message for alert dialog
+        builder?.setMessage("You are betting $moneyBet ${currencyType()} on $betType!")
+//        builder?.setIcon(android.R.drawable.ic_dialog_alert)
+
+        //performing positive action
+        builder?.setPositiveButton("Yes") { dialogInterface, which ->
+
+            cfBetViewModel.createBetting(CreateBetting(moneyBet, chickenId))
+            dialogInterface.dismiss()
+        }
+        //performing negative action
+        builder?.setNegativeButton("No") { dialogInterface, which ->
+            btnBetMeron.isEnabled = true
+            btnBetWala.isEnabled = true
+            dialogInterface.dismiss()
+        }
+        // Create the AlertDialog
+        val alertDialog: AlertDialog? = builder?.create()
+        // Set other dialog properties
+        alertDialog?.setCancelable(false)
+        alertDialog?.show()
+    }
+
+    private fun btnMaster(it: BtnMasterState) {
+        Log.d("CfCreateBetting", "api success : " + it.isSuccess)
+        if (it.isSuccess) {
+            Log.d("CfCreateBetting", "api success : " + it.btnData)
+            if (!it.btnData.isNullOrEmpty()) {
+                btnMaster = it.btnData
+                btnZero.text = it.btnData[0].label
+                btnOne.text = it.btnData[1].label
+                btnTwo.text = it.btnData[2].label
+                btnThree.text = it.btnData[3].label
+                btnFour.text = it.btnData[4].label
+                btnFive.text = it.btnData[5].label
+                btnSix.text = it.btnData[6].label
+                btnSeven.text = it.btnData[7].label
+            }
+        } else {
+            Log.d("CfCreateBetting", "api fail : ")
+        }
+    }
+
+    private fun updateInfo(it: CfBetViewState) {
+        if (it.isSuccess) {
+            Log.d("CfCreateBetting", "api success : " + it.data)
+            if (it.data != null) {
+                (requireActivity() as? ShareActivity)?.apply {
+                    tv_amount.text = it.data.balance
+                }
+                betAmount = 0
+//            if (it.channel != null) {
+//                fightNo = it.channel.fightNo
+//                betDate = it.channel.date
+//                val obj = JSONObject()
+//                obj.put(K.ChannelId, it.channel.id)
+//                obj.put(K.TemId, it.channel.temId)
+//                obj.put(K.AmountRed, it.channel.amountRed)
+//                obj.put(K.PayoutRed, it.channel.payoutRed)
+//                obj.put(K.PayoutBlue, it.channel.payoutBlue)
+//                obj.put(K.AmountBlue, it.channel.amountBlue)
+//                shareViewModel.emitCfCreateBetting(obj)
+//            }
+                if (prefHelper.getIsAutoPrint()) {
+                    printCfPrintable(
+                        userShare,
+                        it.data.fightNo.toString(),
+                        it.data.time,
+                        it.data.betting,
+                        it.data.amount,
+                        it.data.amount,
+                        it.data.amount,
+                        getLastFourChars(it.data._id, 4),
+                        sharePref.getChannelType()
+                    )
+                }
+                txtMsgAmount.text = ""
+                edtBettingAmount.setText("")
+                txtMsgSuccess.text = "Your betting is success!"
+                btnBetMeron.isEnabled = true
+                btnBetWala.isEnabled = true
+                it.isSuccess = false
+            }
+//            shareViewModel.setUpdateFlagMain(true)
+        } else {
+            if (it.error != null) {
+                txtMsgAmount.text = it.error
+                btnBetMeron.isEnabled = true
+                btnBetWala.isEnabled = true
+            }
+//            Log.d("CfCreateBetting", "api fail : " + it.accountBalance)
+        }
+    }
+
+    private fun createBetting(betType: String, chickenId: String) {
+        txtMsgSuccess.text = ""
+        txtMsgAmount.text = ""
+        val moneyBet = edtBettingAmount.text.toString()
+        if (moneyBet.isNotEmpty()) {
+            btnBetMeron.isEnabled = false
+            btnBetWala.isEnabled = false
+            confirmBet(betType, moneyBet.toInt(), chickenId)
+//            cfBetViewModel.createBetting(CreateBetting(moneyBet.toInt(), chickenId))
+        } else {
+            txtMsgAmount.text = "Please enter amount!"
+        }
+    }
+
+    companion object {
+        private const val ARG_SECTION_NUMBER = "section_number"
+
+        @JvmStatic
+        fun newInstance(sectionNumber: Int): CfBetFragment {
+            return CfBetFragment().apply {
+                arguments = Bundle().apply {
+                    putInt(ARG_SECTION_NUMBER, sectionNumber)
+                }
+            }
+        }
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        this.clearFindViewByIdCache()
+    }
+
+    private fun getLastFourChars(str: String, n: Int): String {
+        var lastChars = str
+        if (lastChars.length > n) {
+            lastChars = lastChars.substring(lastChars.length - n, lastChars.length)
+        }
+        return lastChars
+    }
+}

+ 173 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/Betting/CfBetViewModel.kt

@@ -0,0 +1,173 @@
+package com.sambath.sbc.screen.main.cflive.Betting
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.CreateBetting
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.ModelPreferencesManager
+import com.sambath.sbc.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class CfBetViewModel(val apiService: ApiService, val prefHelper: PrefHelper) : BaseViewModel() {
+    private val _state = MutableLiveData<CfBetViewState>(CfBetViewState())
+    val state: LiveData<CfBetViewState> = _state
+    fun createBetting(createBetting: CreateBetting) {
+        if (_state.value!!.isProgress) return
+        _state.value = prev().copy(isProgress = true)
+        disposables.add(
+            apiService.createBetting(createBetting)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        Log.d("CfCreateBetting", "api result : " + it.data)
+                        _state.value = prev().copy(
+                            isProgress = false,
+                            error = null,
+                            isSuccess = true,
+                            data = it.data
+                        )
+                    } else {
+                        Log.d("CfCreateBetting", "api result : " + it.resultCode)
+                        _state.value =
+                            prev().copy(
+                                isProgress = false,
+                                isSuccess = false,
+                                error = "[${it.message.description}]"
+                            )
+                    }
+                }, {
+                    Log.d("CfCreateBetting", it.getErrorCode())
+                    _state.value = prev().copy(
+                        isProgress = false,
+                        isSuccess = false,
+                        error = "ប្រតិបត្តិការមិនជោគជ័យទេ!"
+                    )
+                })
+        )
+    }
+
+    private fun prev() = _state.value!!
+
+    private val _stateMaster = MutableLiveData<BettingTypeMasterState>(BettingTypeMasterState())
+    val stateMaster: LiveData<BettingTypeMasterState> = _stateMaster
+    fun getMaster() {
+        if (_stateMaster.value!!.isProgress) return
+        _stateMaster.value = prevMaster().copy(isProgress = true)
+        disposables.add(
+            apiService.getBettingType()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+//                        Log.d("CfCreateBetting", "api result : " + it.data)
+                        _stateMaster.value = prevMaster().copy(
+                            isProgress = false,
+                            error = null,
+                            isSuccess = true,
+                            bettingTypeData = it.data
+                        )
+                    } else {
+//                        Log.d("CfCreateBetting", "api result : " + it.resultCode)
+                        _stateMaster.value =
+                            prevMaster().copy(
+                                isProgress = false,
+                                isSuccess = false,
+                                error = "[${it.message.description}]"
+                            )
+                    }
+                }, {
+//                    Log.d("CfCreateBetting", it.getErrorCode())
+                    _stateMaster.value = prevMaster().copy(
+                        isProgress = false,
+                        isSuccess = false,
+                        error = "ប្រតិបត្តិការមិនជោគជ័យទេ!"
+                    )
+                })
+        )
+    }
+
+    private fun prevMaster() = _stateMaster.value!!
+
+    private val _stateBtn = MutableLiveData<BtnMasterState>(BtnMasterState())
+    val stateBtn: LiveData<BtnMasterState> = _stateBtn
+    fun getBtnMaster() {
+        if (_stateBtn.value!!.isProgress) return
+        _stateBtn.value = prevBtn().copy(isProgress = true)
+        disposables.add(
+            apiService.getButton()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        Log.d("CfCreateBetting", "api result : " + it.data)
+                        _stateBtn.value = prevBtn().copy(
+                            isProgress = false,
+                            error = null,
+                            isSuccess = true,
+                            btnData = it.data
+                        )
+                    } else {
+                        Log.d("CfCreateBetting", "api result : " + it.resultCode)
+                        _stateBtn.value =
+                            prevBtn().copy(
+                                isProgress = false,
+                                isSuccess = false,
+                                error = "[${it.message.description}]"
+                            )
+                    }
+                }, {
+                    Log.d("CfCreateBetting", "error")
+                    _stateBtn.value = prevBtn().copy(
+                        isProgress = false,
+                        isSuccess = false,
+                        error = "ប្រតិបត្តិការមិនជោគជ័យទេ!"
+                    )
+                })
+        )
+    }
+
+    private fun prevBtn() = _stateBtn.value!!
+
+    private val _stateWeight = MutableLiveData(WeightViewState())
+    val stateWeight: LiveData<WeightViewState> = _stateWeight
+    fun getWeight() {
+        if (_stateWeight.value!!.isPro) return
+        _stateWeight.value = prevWeight().copy(isPro = true)
+        disposables.add(
+            apiService.getWeight()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        ModelPreferencesManager.put(it.data, Const.USER_KEY)
+                        _stateWeight.value = prevWeight().copy(
+                            isPro = false,
+                            error = null,
+                            weightData = it.data,
+                            isSuccess = true
+                        )
+                    } else {
+                        _stateWeight.value =
+                            prevWeight().copy(isPro = false, error = "[${it.message.description}]")
+                    }
+                }, {
+//                    Log.d("dataxzsd", it.getErrorCode())
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                    _stateWeight.value = prevWeight().copy(isPro = false, error = message)
+                })
+        )
+    }
+
+    private fun prevWeight() = _stateWeight.value!!
+}

+ 37 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/Betting/CfBetViewState.kt

@@ -0,0 +1,37 @@
+package com.sambath.sbc.screen.main.cflive.Betting
+
+import com.sambath.sbc.remote.BettingData
+import com.sambath.sbc.remote.BettingTypeData
+import com.sambath.sbc.remote.BtnData
+import com.sambath.sbc.remote.WeightData
+
+data class CfBetViewState(
+    val initial: Boolean = false,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var isSuccess: Boolean = false,
+    val data: BettingData? = null
+)
+
+data class BettingTypeMasterState(
+    val initial: Boolean = false,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var isSuccess: Boolean = false,
+    val bettingTypeData: List<BettingTypeData>? = null
+)
+
+data class BtnMasterState(
+    val initial: Boolean = false,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var isSuccess: Boolean = false,
+    val btnData: List<BtnData>? = null
+)
+
+data class WeightViewState(
+    val isPro: Boolean = false,
+    val error: String? = null,
+    val weightData: WeightData? = null,
+    val isSuccess: Boolean = false,
+)

+ 18 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsAdapter.kt

@@ -0,0 +1,18 @@
+package com.sambath.sbc.screen.main.cflive.currentbets
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.sambath.sbc.R
+
+class CurrentBetsAdapter  : BaseListAdapter() {
+    var printButtonListener: ((String, String, String, String, String, String, String) -> Unit) ?= null
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = CurrentBetsListViewHolder(
+        LayoutInflater.from(parent.context).inflate(
+            R.layout.current_bets_item,
+            parent,
+            false
+        ) , printButtonListener
+    )
+}

+ 113 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsFragment.kt

@@ -0,0 +1,113 @@
+package com.sambath.sbc.screen.main.cflive.currentbets
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.core.view.isVisible
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.base.BaseFragment
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.util.PrefHelper
+import kotlinx.android.synthetic.*
+import kotlinx.android.synthetic.main.fragment_current_bets.*
+
+class CurrentBetsFragment : BaseFragment(R.layout.fragment_current_bets) {
+    private val shareViewModel = App.injectShareViewModel()
+    private lateinit var adapter: CurrentBetsAdapter
+    private lateinit var user: User
+    private lateinit var sharePref: PrefHelper
+    private lateinit var currency: String
+    private lateinit var currentBetsViewModel: CurrentBetsViewModel
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        sharePref = App.injectPrefHelper()
+        (requireActivity() as ShareActivity).apply {
+            user = userShare
+        }
+        currentBetsViewModel = CurrentBetsViewModel(App.injectApiService(), App.injectPrefHelper())
+        when (user.currencyType) {
+            1 -> {//dollar
+                currency = "$"
+            }
+            2 -> {//riel
+                currency ="៛"
+            }
+            3 -> {//baht
+                currency = "฿"
+            }
+        }
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        currentBetsViewModel.getCurrentBetsData()
+        adapter = CurrentBetsAdapter()
+        val layoutBlueManager = LinearLayoutManager(requireActivity() as? ShareActivity)
+        rv_current_bet.layoutManager = layoutBlueManager
+        rv_current_bet.itemAnimator = DefaultItemAnimator()
+        rv_current_bet.adapter = adapter
+        adapter.printButtonListener = { fightNo, betDate, betType, amount, payout, payoutPrint, id ->
+            //val item = adapter.currentList[index] as ListItem
+            printCfPrintable(
+                user,
+                fightNo,
+                betDate,
+                betType,
+                amount,
+                payout,
+                payoutPrint,
+                id,
+                sharePref.getChannelType()
+            )
+        }
+        label_amount.text = "Amount ($currency)"
+        currentBetsViewModel.getCurrentBetsData()
+        currentBetsViewModel.state.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+//            Log.d("dataxzsd", "data live")
+            getCurrentBets(it)
+        })
+        shareViewModel.getUpdateFlagMain.observe(viewLifecycleOwner, Observer {
+            if (it) {
+//                Log.d("dataxzsdup", "update data live")
+                currentBetsViewModel.getCurrentBetsData()
+                shareViewModel.setUpdateFlagMain(false)
+            }
+        })
+        shareViewModel.getDefinedResultAndChannel.observe(viewLifecycleOwner, Observer {
+            currentBetsViewModel.getCurrentBetsData()
+        })
+    }
+
+    private fun getCurrentBets(it: CurrentBetsViewState) {
+        Log.d("callApi", "current report")
+        progressCurrentBets.isVisible = it.isProgress
+        if (it.currentBetsList != null) {
+            Log.d("callApi", "currentBetsList")
+            adapter.submitList(it.currentBetsList)
+        }
+        adapter.notifyDataSetChanged()
+    }
+
+    companion object {
+        private const val ARG_SECTION_NUMBER = "section_number"
+
+        @JvmStatic
+        fun newInstance(sectionNumber: Int): CurrentBetsFragment {
+            return CurrentBetsFragment().apply {
+                arguments = Bundle().apply {
+                    putInt(ARG_SECTION_NUMBER, sectionNumber)
+                }
+            }
+        }
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        this.clearFindViewByIdCache()
+    }
+}

+ 62 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsListViewHolder.kt

@@ -0,0 +1,62 @@
+package com.sambath.sbc.screen.main.cflive.currentbets
+
+import android.view.View
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.sambath.sbc.R
+import com.sambath.sbc.extension.btnClick
+import com.sambath.sbc.extension.setSafeOnClickListener
+import com.sambath.sbc.remote.CurrentBetData
+import com.sambath.sbc.remote.K
+
+class CurrentBetsListViewHolder(
+    itemView: View,
+    private val printButtonListener: ((String, String, String, String, String, String, String) -> Unit)? = null
+) : BaseListViewHolder(itemView) {
+    override fun bindView(item: BaseListItem) {
+        when (item) {
+            is CurrentBetData -> {
+                val txtFightBet: TextView = itemView.findViewById(R.id.txt_fight_no)
+                val txtType: TextView = itemView.findViewById(R.id.txt_type)
+                val txtAmount: TextView = itemView.findViewById(R.id.txt_amount)
+                val txtTime: TextView = itemView.findViewById(R.id.txt_time)
+                val txtPrint: TextView = itemView.findViewById(R.id.txt_print)
+                val fightNo = "#" + item.fightNo.toString()
+                txtFightBet.text = fightNo
+                var type = item.betting
+                when (type) {
+                    K.Meron -> {
+                        txtType.setTextColor(ContextCompat.getColor(itemView.context, R.color.meron))
+                    }
+                    K.Wala -> {
+                        txtType.setTextColor(ContextCompat.getColor(itemView.context, R.color.wala))
+                    }
+                    K.Tie -> {
+                        txtType.setTextColor(ContextCompat.getColor(itemView.context, R.color.draw))
+                    }
+                    K.Cancel -> {
+                        txtType.setTextColor(ContextCompat.getColor(itemView.context, R.color.cancel))
+                    }
+                }
+                txtType.text = type
+                txtAmount.text = item.amount
+                txtTime.text = item.time
+                txtPrint.setSafeOnClickListener {
+                    it.btnClick().subscribe {
+                        printButtonListener?.invoke(
+                            item.fightNo.toString(),
+                            item.time,
+                            type,
+                            item.amount.toString(),
+                            item.amount.toString(),
+                            item.amount,
+                            item._id
+                        )
+                    }
+                }
+            }
+        }
+    }
+}

+ 45 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsViewModel.kt

@@ -0,0 +1,45 @@
+package com.sambath.sbc.screen.main.cflive.currentbets
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class CurrentBetsViewModel (val apiService: ApiService, val prefHelper: PrefHelper): BaseViewModel() {
+    private val _state = MutableLiveData<CurrentBetsViewState>(CurrentBetsViewState())
+    val state: LiveData<CurrentBetsViewState> = _state
+    fun getCurrentBetsData(){
+        if (_state.value!!.isProgress) return
+        _state.value = prev().copy(isProgress = true)
+        disposables.add(
+            apiService.getCurrentBetting()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+//                        Log.d("dataxzsd", it.data.toString())
+                        _state.value = prev().copy(
+                            isProgress = false,
+                            error = null,
+                            currentBetsList = it.data
+                        )
+                    } else {
+                        _state.value =
+                            prev().copy(isProgress = false, error = "[${it.message.description}]")
+                    }
+                }, {
+//                    Log.d("dataxzsd", it.getErrorCode())
+                    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/sambath/sbc/screen/main/cflive/currentbets/CurrentBetsViewState.kt

@@ -0,0 +1,10 @@
+package com.sambath.sbc.screen.main.cflive.currentbets
+
+import com.sambath.sbc.remote.CurrentBetData
+
+data class CurrentBetsViewState(
+    val initial: Boolean = false,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var currentBetsList: List<CurrentBetData>? = null,
+)

+ 193 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/result/CfResultFragment.kt

@@ -0,0 +1,193 @@
+package com.sambath.sbc.screen.main.cflive.result
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.GridLayoutManager
+import com.gdtlib.lib.adapter.BaseListItem
+import com.google.android.material.button.MaterialButton
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.base.BaseFragment
+import com.sambath.sbc.extension.btnClick
+import com.sambath.sbc.remote.K
+import com.sambath.sbc.remote.ResultSummary
+import com.sambath.sbc.remote.Results
+import com.sambath.sbc.screen.result.Table1Adapter
+import com.sambath.sbc.screen.result.Table1ListItem
+import com.sambath.sbc.util.MiddleDividerItemDecoration
+import kotlinx.android.synthetic.main.fragment_cf_result.*
+import org.json.JSONObject
+
+class CfResultFragment : BaseFragment(R.layout.fragment_cf_result) {
+    private lateinit var adapterTable1: Table1Adapter
+    private lateinit var itemDecoration: MiddleDividerItemDecoration
+    private lateinit var itemsTable1: MutableList<Table1ListItem>
+    private lateinit var btnClose: MaterialButton
+    private val gson = Gson()
+    private val shareViewModel = App.injectShareViewModel()
+    private lateinit var cfResultViewModel: CfResultViewModel
+    private var cirRed: Int = 0
+    private var cirBlue: Int = 0
+    private var cirYellow: Int = 0
+    private var cirGreen: Int = 0
+    private var startColumn: Int = 0
+    private var newStartColumn: Int = 0
+    private var column: Int = 20
+    private var fixColumn: Int = 20
+    override fun onCreate(savedInstanceState: Bundle?) {
+        cfResultViewModel = CfResultViewModel(App.injectApiService(), App.injectPrefHelper())
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        setDataTabOne()
+        cfResultViewModel.getCfResuleData()
+        cfResultViewModel.state.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+            Log.d("dataxzsd", "data live" + it.toString())
+            addResultList(it)
+        })
+        (requireActivity() as? ShareActivity)?.apply {
+            groupToolbarIcons.isVisible = false
+            btnClose = view.findViewById<MaterialButton>(R.id.btn_close)
+            btnClose.setOnClickListener {
+//                if (!sharePref.getIsMute()) betTouch.start()
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+            }
+        }
+        shareViewModel.getDefinedResultAndChannel.observe(viewLifecycleOwner, Observer {
+            if (!it.isNullOrEmpty()) {
+                if (newStartColumn > startColumn) {
+                    itemsTable1?.clear()
+                    for (n in 0..119) {
+                        itemsTable1?.add(Table1ListItem(n, "cir-white"))
+                    }
+                    startColumn = newStartColumn
+                }
+                val obj = JSONObject(it)
+                val resultArr = obj.getJSONArray("objCoResult")
+                val sumObj = obj.getJSONObject("objSummaryCoResult")
+                val sumType = object : TypeToken<ResultSummary>() {}.type
+                val summary =
+                    gson.fromJson<ResultSummary>(sumObj.toString(), sumType)
+                txt_blue.text = summary.wala.toString()
+                txt_cancel.text = summary.cancel.toString()
+                txt_green.text = summary.tie.toString()
+                txt_red.text = summary.meron.toString()
+                if (resultArr.length() > 0) {
+                    val resultType = object : TypeToken<List<Results>>() {}.type
+                    val cfResultList =
+                        gson.fromJson<List<Results>>(resultArr.toString(), resultType)
+                    shareViewModel.setResult(cfResultList[0].name)
+                    for (i in 0 until (cfResultList.size)) {
+                        val rowNum = cfResultList[i].rid as Int
+                        val colNum = cfResultList[i].cid as Int
+                        val index = if (rowNum == 1) {
+                            (19 * rowNum.minus(1)).plus(colNum.minus(startColumn.plus(1)))
+                        } else {
+                            (20 * rowNum.minus(1)).plus(colNum.minus(startColumn.plus(1)))
+                        }
+                        if (index in 0..120) {
+                            itemsTable1[index].color = cfResultList[i].color.toString()
+                            itemsTable1[index].fightNo = cfResultList[i].fightNo.toString()
+                        }
+                    }
+                    adapterTable1.submitList(itemsTable1 as List<BaseListItem>?)
+                    adapterTable1.notifyDataSetChanged()
+                }
+            }
+        })
+        shareViewModel.getChannelInfo.observe(viewLifecycleOwner, Observer {
+            if (it != null) {
+                column = it.column
+                fixColumn = it.fixColumn
+                startColumn = column.minus(fixColumn)
+            }
+        })
+    }
+
+    private fun updateColNumber(obj: JSONObject) {
+        column = if (obj.has(K.Column)) {
+            obj.getInt(K.Column)
+        } else {
+            column
+        }
+        fixColumn = if (obj.has(K.Fix_Column)) {
+            obj.getInt(K.Fix_Column)
+        } else {
+            fixColumn
+        }
+        startColumn = column.minus(fixColumn)
+    }
+
+    private fun addResultList(it: CfResultViewState) {
+        if (it.isSuccess) {
+            startColumn = column.minus(fixColumn)
+            if (startColumn > newStartColumn) {
+                itemsTable1.clear()
+                for (n in 0..119) {
+                    itemsTable1.add(Table1ListItem(n, "cir-white", ""))
+                }
+                newStartColumn = startColumn
+            }
+            if (!it.resultList.isNullOrEmpty()) {
+                shareViewModel.setResult(it.resultList!![0].name)
+                for (i in 0 until (it.resultList!!.size)) {
+                    val rowNum = it.resultList!![i].rid as Int
+                    val colNum = it.resultList!![i].cid as Int
+                    if (colNum > startColumn) {
+                        val index = if (rowNum == 1) {
+                            (19 * rowNum.minus(1)).plus(colNum.minus(startColumn.plus(1)))
+                        } else {
+                            (20 * rowNum.minus(1)).plus(colNum.minus(startColumn.plus(1)))
+                        }
+                        if (index in 0..120) {
+                            itemsTable1[index].color = it.resultList!![i].color
+                            itemsTable1[index].fightNo = it.resultList!![i].fightNo.toString()
+                        }
+                    }
+                }
+                adapterTable1.submitList(itemsTable1 as List<BaseListItem>?)
+                adapterTable1.notifyDataSetChanged()
+                txt_blue.text = it.resultSummary?.wala.toString()
+                txt_cancel.text = it.resultSummary?.cancel.toString()
+                txt_green.text = it.resultSummary?.tie.toString()
+                txt_red.text = it.resultSummary?.meron.toString()
+            }
+        }
+    }
+
+    private fun setDataTabOne() {
+        itemDecoration =
+            MiddleDividerItemDecoration(requireContext(), MiddleDividerItemDecoration.ALL)
+        itemDecoration.setDividerColor(
+            ContextCompat.getColor(
+                requireContext(),
+                R.color.color_gray_800
+            )
+        )
+        adapterTable1 = Table1Adapter()
+        itemsTable1 = mutableListOf()
+        for (n in 0..119) {
+            itemsTable1.add(Table1ListItem(n, "cir-white"))
+        }
+        rv_point.addItemDecoration(itemDecoration)
+        rv_point.setHasFixedSize(true)
+        rv_point.layoutManager = GridLayoutManager(requireContext(), 20)
+        rv_point.adapter = adapterTable1
+        adapterTable1.submitList(itemsTable1 as List<BaseListItem>?)
+        txt_blue.text = cirBlue.toString()
+        txt_cancel.text = cirYellow.toString()
+        txt_green.text = cirGreen.toString()
+        txt_red.text = cirRed.toString()
+    }
+}

+ 55 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/result/CfResultViewModel.kt

@@ -0,0 +1,55 @@
+package com.sambath.sbc.screen.main.cflive.result
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class CfResultViewModel (val apiService: ApiService, val prefHelper: PrefHelper): BaseViewModel() {
+    private val _state = MutableLiveData<CfResultViewState>(CfResultViewState())
+    val state: LiveData<CfResultViewState> = _state
+    fun getCfResuleData(){
+        if (_state.value!!.isProgress) return
+        _state.value = prev().copy(isProgress = true)
+        disposables.add(
+            apiService.getResult()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+//                        Log.d("dataxzsd", it.data.toString())
+                        _state.value = prev().copy(
+                            isProgress = false,
+                            error = null,
+                            isSuccess = true,
+                            resultList = it.data?.results,
+                            resultSummary = it.data?.resultSummary
+                        )
+                    } else {
+                        _state.value =
+                            prev().copy(
+                                isProgress = false,
+                                isSuccess = false,
+                                error = "[${it.message.description}]"
+                            )
+                    }
+                }, {
+//                    Log.d("dataxzsd", it.getErrorCode())
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                    _state.value = prev().copy(
+                        isProgress = false,
+                        isSuccess = false,
+                        error = message
+                    )
+                })
+        )
+    }
+
+    private fun prev() = _state.value!!
+}

+ 13 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/result/CfResultViewState.kt

@@ -0,0 +1,13 @@
+package com.sambath.sbc.screen.main.cflive.result
+
+import com.sambath.sbc.remote.ResultSummary
+import com.sambath.sbc.remote.Results
+
+data class CfResultViewState(
+    val initial: Boolean = false,
+    val isSuccess: Boolean = false,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var resultList: List<Results>? = null,
+    var resultSummary: ResultSummary? = null,
+)

+ 301 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/StatementDialogFragment.kt

@@ -0,0 +1,301 @@
+package com.cocking.fight.screen.dialogfragment
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import androidx.core.view.isVisible
+import androidx.fragment.app.DialogFragment
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.cocking.fight.screen.report.ReportAdapter
+import com.cocking.fight.screen.report.Type
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.remote.ReportBody
+import com.sambath.sbc.remote.ReportOne
+import com.sambath.sbc.remote.ReportTwo
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.ModelPreferencesManager
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.schedulers.Schedulers
+import kotlinx.android.synthetic.main.app_bar_dialog.*
+import kotlinx.android.synthetic.main.fragment_dialog_report.*
+import java.text.DecimalFormat
+import java.util.concurrent.TimeUnit
+
+class StatementDialogFragment : DialogFragment() {
+    private lateinit var adapterTb1: ReportAdapter
+    private lateinit var adapterTb2: ReportAdapter
+    private lateinit var adapterTb3: ReportAdapter
+    private lateinit var rvTab1: RecyclerView
+    private lateinit var rvTab2: RecyclerView
+    private lateinit var rvTab3: RecyclerView
+    private lateinit var user: User
+    private lateinit var layoutManager1: LinearLayoutManager
+    private lateinit var layoutManager2: LinearLayoutManager
+    private var pageOne: Int = 1
+    private var totalPageOne: Int = 1
+    private var totalRecordOne: Int = 0
+    private var isLoadingOne: Boolean = false
+    private var pageTwo: Int = 1
+    private var totalPageTwo: Int = 1
+    private var totalRecordTwo: Int = 0
+    private var isLoadingTwo: Boolean = false
+    private var listOne: List<ReportOne> = arrayListOf()
+    private var listTwo: List<ReportTwo> = arrayListOf()
+    private val apiService = App.injectApiService()
+    private lateinit var statementDialogViewModel: StatementDialogViewModel
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        user = ModelPreferencesManager.get<User>(Const.USER_KEY)!!
+        statementDialogViewModel =
+            StatementDialogViewModel(App.injectApiService(), App.injectPrefHelper())
+        return inflater.inflate(R.layout.fragment_dialog_report, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        txtUserId.text = user.userName
+        txtSubRed.text = currencyFormat(user.accountBalances)
+        img_back.setOnClickListener {
+            dismiss()
+        }
+        rvTab1 = view.findViewById(R.id.rv_tb1)
+        rvTab2 = view.findViewById(R.id.rv_tb2)
+        rvTab3 = view.findViewById(R.id.rv_tb3)
+        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
+        }
+        img_back.setOnClickListener {
+            dialog?.dismiss()
+        }
+        init()
+//        getDataOne()
+//        getDataTwo()
+        exOne(ReportBody(20, 1, "2021-12-17", "2021-12-31"))
+        exTwo(ReportBody(20, 1, "2021-12-17", "2021-12-31"))
+//        statementDialogViewModel.getReportTwo(1)
+        statementDialogViewModel.getReportThree()
+//        statementDialogViewModel.stateOne.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+//            getReportOne(it)
+//        })
+//        statementDialogViewModel.stateTwo.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+//            getReportTwo(it)
+//        })
+        statementDialogViewModel.stateThree.observe(
+            viewLifecycleOwner,
+            androidx.lifecycle.Observer {
+                getReportThree(it)
+            })
+        rvTab1.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+//                val visibleItemCount: Int = layoutManager1.childCount
+//                val pastVisibleItem: Int = layoutManager1.findFirstCompletelyVisibleItemPosition()
+                val total: Int = adapterTb1.itemCount
+                if (!isLoadingOne) {
+                    if (total < totalRecordOne) {
+//                        getDataOne()
+                        Log.d("getReport", "itemCount1 :: " + total)
+                        exOne(ReportBody(20, 1, "2021-12-17", "2021-12-31"))
+                    }
+                }
+                super.onScrolled(recyclerView, dx, dy)
+            }
+        })
+        rvTab2.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+                val visibleItemCount: Int = layoutManager2.childCount
+                val pastVisibleItem: Int = layoutManager2.findFirstCompletelyVisibleItemPosition()
+                val total: Int = adapterTb2.itemCount
+                if (!isLoadingTwo) {
+                    Log.d("getReport", "total :: plus " + total+" :: "+totalRecordTwo)
+                    if (total < totalRecordTwo) {
+//                        getDataTwo()
+                        Log.d("getReport", "itemCount2 :: " + total)
+                        exTwo(ReportBody(20, 1, "2021-12-17", "2021-12-31"))
+                    }
+                }
+                super.onScrolled(recyclerView, dx, dy)
+            }
+        })
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setStyle(DialogFragment.STYLE_NORMAL, R.style.AppTheme);
+    }
+
+//    private fun getDataOne() {
+//        statementDialogViewModel.getReportOne(pageOne)
+//        pageOne++
+//    }
+
+//    private fun getDataTwo() {
+//        isLoadingTwo = true
+//        statementDialogViewModel.getReportTwo(pageTwo)
+//        pageTwo++
+//    }
+
+    override fun onStart() {
+        super.onStart()
+        dialog?.window?.setLayout(
+            WindowManager.LayoutParams.MATCH_PARENT,
+            WindowManager.LayoutParams.MATCH_PARENT
+        )
+    }
+
+    companion object {
+        const val TAG = "PurchaseConfirmationDialog"
+    }
+
+//    private fun getReportOne(data: StatementDialogViewState) {
+//        progress.isVisible = false
+//        if (data.reportOneList != null) {
+//            totalPageOne = data.totalPageOne
+//            Log.d("getReport", "1 :: " + data.reportOneList!!.size)
+//            adapterTb1.submitList(data.reportOneList)
+//        }
+//    }
+
+//    private fun getReportTwo(data: StatementDialogViewState) {
+//        if (data.reportTwoList.isNullOrEmpty()) {
+//            Log.d("getReport", "2 :: " + data.reportTwoList!!.size)
+//            totalPageTwo = data.totalPageTwo
+//            val li: List<ReportTwo> = data.reportTwoList!!
+//            listTwo = concatenate(listTwo, li)
+//            adapterTb2.submitList(listTwo)
+//            isLoadingTwo = false
+//        }
+//    }
+
+    private fun getReportThree(data: StatementDialogViewState) {
+        if (data.reportThreeList != null) {
+            Log.d("getReport", "3 :: " + data.reportThreeList!!.size)
+            adapterTb3.submitList(data.reportThreeList)
+        }
+    }
+
+    private fun exOne(reportBetting: ReportBody) {
+        isLoadingOne = true
+        pageOne++
+        val disposables = CompositeDisposable()
+        disposables.add(
+            apiService.getReportOne(reportBetting)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        progress.isVisible = false
+                        totalPageOne = it.data.totalPages
+                        totalRecordOne = it.data.totalRows
+                        val li: List<ReportOne> = it.data.reports
+                        listOne = concatenate(listOne, li)
+                        Log.d("getReport", "listOne :: " + listOne.size)
+                        adapterTb1.submitList(listOne)
+                        isLoadingOne = false
+                    } else {
+                        isLoadingOne = false
+                        val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.message.description
+                    }
+                }, {
+                    isLoadingOne = false
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                })
+        )
+    }
+
+    private fun exTwo(reportBetting: ReportBody) {
+        isLoadingTwo = true
+        pageTwo++
+        Log.d("getReport", "page2 :: " + reportBetting.page)
+        val disposables = CompositeDisposable()
+        disposables.add(
+            apiService.getReportTwo(reportBetting)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        totalPageTwo = it.data.totalPages
+                        totalRecordTwo = it.data.totalRows
+                        val li: List<ReportTwo> = it.data.results
+                        listTwo = concatenate(listTwo, li)
+                        Log.d("getReport", "listTwo :: " + listTwo.size)
+                        adapterTb2.submitList(listTwo)
+                        isLoadingTwo = false
+                    } else {
+                        val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.message.description
+                    }
+                }, {
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                })
+        )
+    }
+
+    fun init() {
+//        progress.isVisible = state.isProgress
+//        if (!state.winList.isNullOrEmpty()) {
+        adapterTb1 = ReportAdapter(Type.WIN)
+//            adapterTb1.submitList(state.winList)
+        rvTab1.setHasFixedSize(true)
+        layoutManager1 = LinearLayoutManager(context)
+        rvTab1.layoutManager = layoutManager1
+        rvTab1.adapter = adapterTb1
+//        }
+//        if (!state.winLostList.isNullOrEmpty()) {
+        adapterTb2 = ReportAdapter(Type.WIN_LOST)
+//            adapterTb2.submitList(state.winLostList)
+        rvTab2.setHasFixedSize(true)
+        layoutManager2 = LinearLayoutManager(context)
+        rvTab2.layoutManager = layoutManager2
+        rvTab2.adapter = adapterTb2
+//        }
+//        if (!state.statementList.isNullOrEmpty()) {
+        adapterTb3 = ReportAdapter(Type.STATEMENT)
+//            adapterTb3.submitList(state.statementList)
+        rvTab3.setHasFixedSize(true)
+        rvTab3.layoutManager = LinearLayoutManager(context)
+        rvTab3.adapter = adapterTb3
+//        }
+    }
+
+    fun currencyFormat(amount: Double): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+    fun <T> concatenate(vararg lists: List<T>): List<T> {
+        return listOf(*lists).flatten()
+    }
+}

+ 43 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/StatementDialogViewModel.kt

@@ -0,0 +1,43 @@
+package com.cocking.fight.screen.dialogfragment
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class StatementDialogViewModel (val apiService: ApiService, val prefHelper: PrefHelper) : BaseViewModel(){
+    private val _stateThree = MutableLiveData<StatementDialogViewState>(StatementDialogViewState())
+    val stateThree: LiveData<StatementDialogViewState> = _stateThree
+
+    fun getReportThree() {
+        if (_stateThree.value!!.isProgressThree) return
+        _stateThree.value = prevThree().copy(isProgressThree = true)
+        disposables.add(
+            apiService.getReportThree()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+                        _stateThree.value = prevThree().copy(
+                            isProgressThree = false,
+                            errorThree = null,
+                            reportThreeList = it.data
+                        )
+                    } else {
+                        _stateThree.value = prevThree().copy(isProgressThree = false, errorThree = "[${it.message.description}]")
+                    }
+                }, {
+                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
+                    _stateThree.value = prevThree().copy(isProgressThree = false, errorThree = message)
+                })
+        )
+    }
+
+    private fun prevThree() = _stateThree.value!!
+}

+ 10 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/StatementDialogViewState.kt

@@ -0,0 +1,10 @@
+package com.cocking.fight.screen.dialogfragment
+
+import com.sambath.sbc.remote.ReportThree
+
+
+data class StatementDialogViewState (
+    val isProgressThree: Boolean = false,
+    val errorThree: String? = null,
+    var reportThreeList: List<ReportThree>? = null,
+)

+ 66 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/report/ReportAdapter.kt

@@ -0,0 +1,66 @@
+package com.cocking.fight.screen.report
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.sambath.sbc.R
+import com.sambath.sbc.remote.ReportOne
+
+class ReportAdapter(private val type: Type): BaseListAdapter() {
+    var printButtonListener: ((ReportOne) -> Unit) ?= null
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+        when (type) {
+            Type.DEPOSIT -> {
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_money_transaction,
+                        parent,
+                        false
+                    )
+                )
+            }
+            Type.WITHDRAW -> {
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_money_transaction,
+                        parent,
+                        false
+                    )
+                )
+            }
+            Type.WIN -> {
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_table_statement,
+                        parent,
+                        false
+                    ), printButtonListener
+                )
+            }
+            Type.WIN_LOST -> {
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_table_report,
+                        parent,
+                        false
+                    ), printButtonListener
+                )
+            }
+            Type.STATEMENT -> {//Statement
+                return ReportListViewHolder(
+                    LayoutInflater.from(parent.context).inflate(
+                        R.layout.item_report,
+                        parent,
+                        false
+                    )
+                )
+            }
+
+        }
+    }
+}
+enum class Type{
+    DEPOSIT, WITHDRAW, WIN, WIN_LOST, STATEMENT
+}

+ 189 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/report/ReportListViewHolder.kt

@@ -0,0 +1,189 @@
+package com.cocking.fight.screen.report
+
+import android.annotation.SuppressLint
+import android.graphics.Color
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.sambath.sbc.R
+import com.sambath.sbc.extension.setSafeOnClickListener
+import com.sambath.sbc.remote.*
+import java.text.DecimalFormat
+
+
+class ReportListViewHolder(
+    itemView: View,
+    private val printButtonListener: ((ReportOne) -> Unit)? = null
+) : BaseListViewHolder(itemView) {
+    @SuppressLint("SetTextI18n")
+    override fun bindView(item: BaseListItem) {
+        when (item) {
+            is ReportDeposit -> {
+                val tvDate = itemView.findViewById<TextView>(R.id.tv_date)
+                val tvOldBalance = itemView.findViewById<TextView>(R.id.tv_result_amount)
+                val tvNewBalance = itemView.findViewById<TextView>(R.id.tv_old_balance)
+                val tvAmount = itemView.findViewById<TextView>(R.id.tv_amount)
+                tvDate.text = item.date
+                tvAmount.text = item.amount
+                tvOldBalance.text = item.oldBalance
+                tvNewBalance.text = item.newBalance
+            }
+            is ReportWithdraw -> {
+                val tvDate = itemView.findViewById<TextView>(R.id.tv_date)
+                val tvOldBalance = itemView.findViewById<TextView>(R.id.tv_result_amount)
+                val tvNewBalance = itemView.findViewById<TextView>(R.id.tv_old_balance)
+                val tvAmount = itemView.findViewById<TextView>(R.id.tv_amount)
+                tvDate.text = item.date
+                tvAmount.text = item.amount
+                tvOldBalance.text = item.oldBalance
+                tvNewBalance.text = item.newBalance
+            }
+            is ReportOne -> {
+                val tvFightNo = itemView.findViewById<TextView>(R.id.tv_fight_no)
+                val tvResultAmount = itemView.findViewById<TextView>(R.id.tv_result_amount)
+                val tvWinResult = itemView.findViewById<TextView>(R.id.tv_old_balance)
+                val tvResultName = itemView.findViewById<TextView>(R.id.tv_result_name)
+                val tvBettingDate = itemView.findViewById<TextView>(R.id.tv_amount)
+                val betType = item.betName
+                val betCast = "${getCurrency(item.amount)}x${item.payout}"
+                tvFightNo.text = "#${item.fightNo.toString()}"
+                tvWinResult.text = betType
+//                val date = item.date.split(" ")
+                tvBettingDate.text = item.date
+                when (betType) {
+                    K.Meron -> {
+                        tvWinResult.setTextColor(Color.RED)
+                    }
+                    K.Wala -> {
+                        tvWinResult.setTextColor(Color.BLUE)
+                    }
+                    K.Tie -> {
+                        tvWinResult.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.draw
+                            )
+                        )
+                    }
+                    K.Cancel -> {
+                        tvWinResult.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.cancel
+                            )
+                        )
+                    }
+                }
+                tvResultName.text = item.resultName
+                when (item.resultName) {
+                    K.Meron -> {
+                        tvResultName.setTextColor(Color.RED)
+                    }
+                    K.Wala -> {
+                        tvResultName.setTextColor(Color.BLUE)
+                    }
+                    K.Tie -> {
+                        tvResultName.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.draw
+                            )
+                        )
+                    }
+                    K.Cancel -> {
+                        tvResultName.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.cancel
+                            )
+                        )
+                    }
+                }
+                val winLose = getCurrency(item.amountWin)
+                tvResultAmount.text = "$betCast=$winLose"
+                if (item.is_win == true) {
+                    tvResultAmount.setTextColor(Color.BLACK)
+                } else {
+                    tvResultAmount.setTextColor(Color.RED)
+                }
+                tvFightNo.setSafeOnClickListener {
+//                    Toast.makeText(co)
+                    printButtonListener?.invoke(item)
+                }
+            }
+            is ReportTwo -> {
+                val tvFightNo = itemView.findViewById<TextView>(R.id.tv_fight_no)
+                val tvResultName = itemView.findViewById<TextView>(R.id.tv_result_name)
+                val tvGroupNo = itemView.findViewById<TextView>(R.id.tv_group_no)
+                val tvBettingDate = itemView.findViewById<TextView>(R.id.tv_amount)
+                val betType = item.name
+                tvFightNo.text = "#${item.fightNo}"
+                tvResultName.text = item.name
+                tvGroupNo.text = item.group.toString()
+//                val date = item.date.split(" ")
+                tvBettingDate.text = item.date
+                when (betType) {
+                    K.Meron -> {
+                        tvResultName.setTextColor(Color.RED)
+                    }
+                    K.Wala -> {
+                        tvResultName.setTextColor(Color.BLUE)
+                    }
+                    K.Tie -> {
+                        tvResultName.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.draw
+                            )
+                        )
+                    }
+                    K.Cancel -> {
+                        tvResultName.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.cancel
+                            )
+                        )
+                    }
+                }
+            }
+            is ReportThree -> {//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.type
+                tvC3.text = item.date
+                when (item.type) {
+                    "BETTED" -> {
+                        imgC1.setImageResource(R.drawable.bet)
+                        if (item.amount < 0) {//lost
+                            tvC4.text = currencyFormat(item.amount.toInt())
+                            tvC4.setTextColor(Color.RED)
+                        } else {//win
+                            tvC4.text = currencyFormat(item.amount.toInt())
+                            tvC4.setTextColor(Color.BLUE)
+                        }
+                    }
+                    "WITHDREW" -> {
+                        imgC1.setImageResource(R.drawable.withdraw)
+                    }
+                    "DEPOSITED" -> {
+                        imgC1.setImageResource(R.drawable.deposit)
+                    }
+                }
+            }
+        }
+    }
+
+    fun currencyFormat(amount: Int): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+
+}

+ 15 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/statement/report/ReportViewState.kt

@@ -0,0 +1,15 @@
+package com.cocking.fight.screen.report
+
+import com.sambath.sbc.remote.Statement
+import com.sambath.sbc.remote.Win
+import com.sambath.sbc.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
+
+)

+ 16 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportAdapter.kt

@@ -0,0 +1,16 @@
+package com.sambath.sbc.screen.main.cflive.todayreport
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.sambath.sbc.R
+
+class TodayReportAdapter : BaseListAdapter() {
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = TodayReportListViewHolder(
+        LayoutInflater.from(parent.context).inflate(
+            R.layout.today_report_item,
+            parent,
+            false
+        ))
+}

+ 67 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportFragment.kt

@@ -0,0 +1,67 @@
+package com.sambath.sbc.screen.main.cflive.todayreport
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.core.view.isVisible
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.base.BaseFragment
+import kotlinx.android.synthetic.main.fragment_today_report.*
+
+class TodayReportFragment : BaseFragment(R.layout.fragment_today_report) {
+    private val shareViewModel = App.injectShareViewModel()
+    private lateinit var adapter: TodayReportAdapter
+    private lateinit var todayReportViewModel: TodayReportViewModel
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        todayReportViewModel = TodayReportViewModel(App.injectApiService(), App.injectPrefHelper())
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        adapter = TodayReportAdapter()
+        val layoutBlueManager = LinearLayoutManager(requireActivity() as? ShareActivity)
+        rv_today_report.layoutManager = layoutBlueManager
+        rv_today_report.itemAnimator = DefaultItemAnimator()
+        rv_today_report.adapter = adapter
+        todayReportViewModel.getTodayReportData()
+        todayReportViewModel.state.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
+//            Log.d("dataxzsd", "data live")
+            getTodayReport(it)
+        })
+        shareViewModel.getUpdateFlagMain.observe(viewLifecycleOwner, Observer {
+            if (it){
+//                Log.d("dataxzsdup", "update data live")
+                todayReportViewModel.getTodayReportData()
+                shareViewModel.setUpdateFlagMain(false)
+            }
+        })
+        shareViewModel.getViewResult.observe(viewLifecycleOwner, Observer {
+             todayReportViewModel.getTodayReportData()
+        })
+    }
+    private fun getTodayReport(state: TodayReportViewState){
+        Log.d("callApi", "today report")
+        progressTodayReport.isVisible = state.isProgress
+        if (!state.todayReportList.isNullOrEmpty()){
+            adapter.submitList(state.todayReportList)
+        }
+        adapter.notifyDataSetChanged()
+    }
+    companion object {
+        private const val ARG_SECTION_NUMBER = "section_number"
+        @JvmStatic
+        fun newInstance(sectionNumber: Int): TodayReportFragment {
+            return TodayReportFragment().apply {
+                arguments = Bundle().apply {
+                    putInt(ARG_SECTION_NUMBER, sectionNumber)
+                }
+            }
+        }
+    }
+}

+ 141 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportListViewHolder.kt

@@ -0,0 +1,141 @@
+package com.sambath.sbc.screen.main.cflive.todayreport
+
+import android.graphics.Color
+import android.view.View
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.sambath.sbc.R
+import com.sambath.sbc.remote.*
+
+class TodayReportListViewHolder(
+    itemView: View
+) : BaseListViewHolder(itemView) {
+    override fun bindView(item: BaseListItem) {
+        when (item) {
+            is TodayData -> {
+                val txtFightNo: TextView = itemView.findViewById(R.id.txt_fight_bet)
+                val txtType: TextView = itemView.findViewById(R.id.txt_type)
+                val txtResult: TextView = itemView.findViewById(R.id.txt_result)
+                val txtTime: TextView = itemView.findViewById(R.id.txt_time)
+                val fightNo = "#" + item.fightNo.toString()
+                txtFightNo.text = fightNo
+                var type = item.betting
+                when (type) {
+                    K.Meron -> {
+                        txtType.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.meron
+                            )
+                        )
+                    }
+                    K.Wala -> {
+                        txtType.setTextColor(ContextCompat.getColor(itemView.context, R.color.wala))
+                    }
+                    K.Tie -> {
+                        txtType.setTextColor(ContextCompat.getColor(itemView.context, R.color.draw))
+                    }
+                    K.Cancel -> {
+                        txtType.setTextColor(
+                            ContextCompat.getColor(
+                                itemView.context,
+                                R.color.cancel
+                            )
+                        )
+                    }
+                }
+                when (item.isWin) {
+                    true -> {
+                        val result = "" + item.amount
+                        txtResult.text = result
+                        when (type) {
+                            K.Meron -> {
+                                txtResult.setTextColor(
+                                    ContextCompat.getColor(
+                                        itemView.context,
+                                        R.color.meron
+                                    )
+                                )
+                            }
+                            K.Wala -> {
+                                txtResult.setTextColor(
+                                    ContextCompat.getColor(
+                                        itemView.context,
+                                        R.color.wala
+                                    )
+                                )
+                            }
+                            K.Tie -> {
+                                txtResult.setTextColor(
+                                    ContextCompat.getColor(
+                                        itemView.context,
+                                        R.color.draw
+                                    )
+                                )
+                            }
+                            K.Cancel -> {
+                                txtResult.setTextColor(
+                                    ContextCompat.getColor(
+                                        itemView.context,
+                                        R.color.cancel
+                                    )
+                                )
+                            }
+                        }
+                        txtFightNo.setTextColor(Color.WHITE)
+                        txtTime.setTextColor(Color.WHITE)
+                    }
+                    false -> {
+                        val result = "lose: (" + item.amount + ")"
+                        txtResult.text = result
+                        txtResult.setTextColor(Color.RED)
+                        txtFightNo.setTextColor(Color.RED)
+                        txtTime.setTextColor(Color.RED)
+                    }
+                    else -> {
+                        txtFightNo.setTextColor(Color.WHITE)
+                        txtTime.setTextColor(Color.WHITE)
+//                        if (item.typeBetting == "red") {
+//                            txtResult.setTextColor(ContextCompat.getColor(itemView.context, R.color.meron))
+//                        } else {
+//                            txtResult.setTextColor(ContextCompat.getColor(itemView.context, R.color.wala))
+//                        }
+                        var resultTxt = ""
+                        when (item.resultName) {
+                            K.Cancel -> {
+                                resultTxt = "cancel ( " + item.amount + " )"
+                                txtResult.setTextColor(
+                                    ContextCompat.getColor(
+                                        itemView.context,
+                                        R.color.cancel
+                                    )
+                                )
+                            }
+                            K.Tie -> {
+                                resultTxt = "Tie ( " + item.amount + " )"
+                                txtResult.setTextColor(
+                                    ContextCompat.getColor(
+                                        itemView.context,
+                                        R.color.draw
+                                    )
+                                )
+                            }
+                            else -> {
+                                resultTxt = "" + item.amount
+                                txtResult.setTextColor(
+                                    ContextCompat.getColor(
+                                        itemView.context,
+                                        R.color.color_white
+                                    )
+                                )
+                            }
+                        }
+                        txtResult.text = resultTxt
+                    }
+                }
+            }
+        }
+    }
+}

+ 45 - 0
app/src/main/java/com/sambath/sbc/screen/main/cflive/todayreport/TodayReportViewModel.kt

@@ -0,0 +1,45 @@
+package com.sambath.sbc.screen.main.cflive.todayreport
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import java.util.concurrent.TimeUnit
+
+class TodayReportViewModel (val apiService: ApiService, val prefHelper: PrefHelper): BaseViewModel() {
+    private val _state = MutableLiveData<TodayReportViewState>(TodayReportViewState())
+    val state: LiveData<TodayReportViewState> = _state
+    fun getTodayReportData(){
+        if (_state.value!!.isProgress) return
+        _state.value = prev().copy(isProgress = true)
+        disposables.add(
+            apiService.getTodayReport()
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    if (it.resultCode == "1") {
+//                        Log.d("dataxzsd", "getTodayReportData:: "+it.data.toString())
+                        _state.value = prev().copy(
+                            isProgress = false,
+                            error = null,
+                            todayReportList = it.data
+                        )
+                    } else {
+                        _state.value =
+                            prev().copy(isProgress = false, error = "[${it.message.description}]")
+                    }
+                }, {
+//                    Log.d("dataxzsd", "getTodayReportData:: "+ it.getErrorCode())
+                    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/sambath/sbc/screen/main/cflive/todayreport/TodayReportViewState.kt

@@ -0,0 +1,10 @@
+package com.sambath.sbc.screen.main.cflive.todayreport
+
+import com.sambath.sbc.remote.*
+
+data class TodayReportViewState(
+    val initial: Boolean = false,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var todayReportList: List<TodayData>? = null,
+)

+ 16 - 0
app/src/main/java/com/sambath/sbc/screen/report/StatementAdapter.kt

@@ -0,0 +1,16 @@
+package com.sambath.sbc.screen.report
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.sambath.sbc.R
+
+class StatementAdapter: BaseListAdapter() {
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = StatementListViewHolder(
+        LayoutInflater.from(parent.context).inflate(
+        R.layout.statement_item,
+        parent,
+        false
+    ))
+}

+ 410 - 0
app/src/main/java/com/sambath/sbc/screen/report/StatementFragment.kt

@@ -0,0 +1,410 @@
+package com.sambath.sbc.screen.report
+
+import android.graphics.Color
+import android.os.Bundle
+import android.util.Log
+import androidx.fragment.app.Fragment
+import android.view.View
+import androidx.appcompat.widget.LinearLayoutCompat
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.cocking.fight.screen.dialogfragment.StatementDialogViewModel
+import com.cocking.fight.screen.dialogfragment.StatementDialogViewState
+import com.cocking.fight.screen.report.ReportAdapter
+import com.cocking.fight.screen.report.Type
+import com.google.android.material.button.MaterialButton
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.app.getErrorCode
+import com.sambath.sbc.base.BaseFragment
+import com.sambath.sbc.extension.btnClick
+import com.sambath.sbc.remote.*
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.util.ModelPreferencesManager
+import com.sambath.sbc.util.PrefHelper
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.schedulers.Schedulers
+import kotlinx.android.synthetic.main.app_bar.*
+import kotlinx.android.synthetic.main.fragment_statement.*
+import java.text.DecimalFormat
+import java.util.concurrent.TimeUnit
+
+/**
+ * A simple [Fragment] subclass as the second destination in the navigation.
+ */
+class StatementFragment : BaseFragment(R.layout.fragment_statement) {
+    private lateinit var adapterDep: ReportAdapter
+    private lateinit var adapterWith: ReportAdapter
+    private lateinit var adapterTb1: ReportAdapter
+    private lateinit var adapterTb2: ReportAdapter
+    private lateinit var adapterTb3: ReportAdapter
+    private lateinit var rvTabDeposit: RecyclerView
+    private lateinit var rvTabWithdraw: RecyclerView
+    private lateinit var rvTab1: RecyclerView
+    private lateinit var rvTab2: RecyclerView
+    private lateinit var rvTab3: RecyclerView
+    private lateinit var user: User
+    private lateinit var layoutManagerDep: LinearLayoutManager
+    private lateinit var layoutManagerWit: LinearLayoutManager
+    private lateinit var layoutManager1: LinearLayoutManager
+    private lateinit var layoutManager2: LinearLayoutManager
+    private lateinit var linTabDeposit: LinearLayoutCompat
+    private lateinit var linTabWithdraw: LinearLayoutCompat
+    private lateinit var linTab1: LinearLayoutCompat
+    private lateinit var linTab2: LinearLayoutCompat
+    private lateinit var linTab3: LinearLayoutCompat
+    private var pageDeposit: Int = 1
+    private var totalPageDeposit: Int = 1
+    private var totalRecordDeposit: Int = 0
+    private var isLoadingDeposit: Boolean = false
+    private var pageWithdraw: Int = 1
+    private var totalPageWithdraw: Int = 1
+    private var totalRecordWithdraw: Int = 0
+    private var isLoadingWithdraw: Boolean = false
+    private var pageOne: Int = 1
+    private var totalPageOne: Int = 1
+    private var totalRecordOne: Int = 0
+    private var isLoadingOne: Boolean = false
+    private var pageTwo: Int = 1
+    private var totalPageTwo: Int = 1
+    private var totalRecordTwo: Int = 0
+    private val rowPerPage : Int = 50
+    private var isLoadingTwo: Boolean = false
+    private var listDeposit: List<ReportDeposit> = arrayListOf()
+    private var listWithdraw: List<ReportWithdraw> = arrayListOf()
+    private var listOne: List<ReportOne> = arrayListOf()
+    private var listTwo: List<ReportTwo> = arrayListOf()
+    private val apiService = App.injectApiService()
+    private lateinit var currency: String
+    private lateinit var sharePref: PrefHelper
+    private lateinit var btnClose: MaterialButton
+    private lateinit var statementDialogViewModel: StatementDialogViewModel
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        sharePref = App.injectPrefHelper()
+        user = ModelPreferencesManager.get<User>(Const.USER_KEY)!!
+        statementDialogViewModel =
+            StatementDialogViewModel(App.injectApiService(), App.injectPrefHelper())
+        (requireActivity() as ShareActivity).apply {
+            user = userShare
+        }
+        when (user.currencyType) {
+            1 -> {//dollar
+                currency = "$"
+            }
+            2 -> {//riel
+                currency ="៛"
+            }
+            3 -> {//baht
+                currency = "฿"
+            }
+        }
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        (requireActivity() as? ShareActivity)?.apply {
+            groupToolbarIcons.isVisible = false
+            layCfStatus.isVisible = false
+            btnClose = view.findViewById<MaterialButton>(R.id.btn_close)
+            btnClose.setOnClickListener {
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+            }
+        }
+        tvDepAmount.text = "Amount ($currency)"
+        tvWithAmount.text = "Amount ($currency)"
+        tvReportAmount.text = "Amount ($currency)"
+        tvStatementAmount.text = "Amount ($currency)"
+        linTabDeposit = view.findViewById(R.id.lin_tab_deposit)
+        linTabWithdraw = view.findViewById(R.id.lin_tab_withdraw)
+        linTab1 = view.findViewById(R.id.lin_tab_1)
+        linTab2 = view.findViewById(R.id.lin_tab_2)
+        linTab3 = view.findViewById(R.id.lin_tab_3)
+        rvTabDeposit = view.findViewById(R.id.rv_tb_deposit)
+        rvTabWithdraw = view.findViewById(R.id.rv_tb_withdraw)
+        rvTab1 = view.findViewById(R.id.rv_tb1)
+        rvTab2 = view.findViewById(R.id.rv_tb2)
+        rvTab3 = view.findViewById(R.id.rv_tb3)
+        linMainTabDeposit.setOnClickListener {
+            bg_select_deposit.visibility = View.VISIBLE
+            bg_select_withdraw.visibility = View.INVISIBLE
+            bg_select_tab1.visibility = View.INVISIBLE
+            bg_select_tab2.visibility = View.INVISIBLE
+            bg_select_tab3.visibility = View.INVISIBLE
+
+            linTabDeposit.visibility = View.VISIBLE
+            linTabWithdraw.visibility = View.GONE
+            linTab1.visibility = View.GONE
+            linTab2.visibility = View.GONE
+            linTab3.visibility = View.GONE
+        }
+        linMainTabWithdraw.setOnClickListener {
+            bg_select_deposit.visibility = View.INVISIBLE
+            bg_select_withdraw.visibility = View.VISIBLE
+            bg_select_tab1.visibility = View.INVISIBLE
+            bg_select_tab2.visibility = View.INVISIBLE
+            bg_select_tab3.visibility = View.INVISIBLE
+
+            linTabDeposit.visibility = View.GONE
+            linTabWithdraw.visibility = View.VISIBLE
+            linTab1.visibility = View.GONE
+            linTab2.visibility = View.GONE
+            linTab3.visibility = View.GONE
+        }
+        linTabMainStatement.setOnClickListener {
+            bg_select_deposit.visibility = View.INVISIBLE
+            bg_select_withdraw.visibility = View.INVISIBLE
+            bg_select_tab1.visibility = View.VISIBLE
+            bg_select_tab2.visibility = View.INVISIBLE
+            bg_select_tab3.visibility = View.INVISIBLE
+
+            linTabDeposit.visibility = View.GONE
+            linTabWithdraw.visibility = View.GONE
+            linTab1.visibility = View.VISIBLE
+            linTab2.visibility = View.GONE
+            linTab3.visibility = View.GONE
+        }
+        linTabResult.setOnClickListener {
+            bg_select_deposit.visibility = View.INVISIBLE
+            bg_select_withdraw.visibility = View.INVISIBLE
+            bg_select_tab1.visibility = View.INVISIBLE
+            bg_select_tab2.visibility = View.VISIBLE
+            bg_select_tab3.visibility = View.INVISIBLE
+
+            linTabDeposit.visibility = View.GONE
+            linTabWithdraw.visibility = View.GONE
+            linTab1.visibility = View.GONE
+            linTab2.visibility = View.VISIBLE
+            linTab3.visibility = View.GONE
+        }
+//        linTabReport.setOnClickListener {
+//            bg_select_deposit.visibility = View.INVISIBLE
+//            bg_select_withdraw.visibility = View.INVISIBLE
+//            bg_select_tab1.visibility = View.INVISIBLE
+//            bg_select_tab2.visibility = View.INVISIBLE
+//            bg_select_tab3.visibility = View.VISIBLE
+//
+//            linTabDeposit.visibility = View.GONE
+//            linTabWithdraw.visibility = View.GONE
+//            linTab1.visibility = View.GONE
+//            linTab2.visibility = View.GONE
+//            linTab3.visibility = View.VISIBLE
+//        }
+        init()
+        exDeposit(ReportBody(rowPerPage, pageDeposit, "", ""))
+        exWithdraw(ReportBody(rowPerPage, pageWithdraw, "", ""))
+        exOne(ReportBody(rowPerPage, pageOne, "", ""))
+        exTwo(ReportBody(rowPerPage, pageTwo, "", ""))
+//        statementDialogViewModel.getReportThree()
+//        statementDialogViewModel.stateThree.observe(
+//            viewLifecycleOwner,
+//            androidx.lifecycle.Observer {
+//                getReportThree(it)
+//            })
+        rvTab1.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+                val total: Int = adapterTb1.itemCount
+                if (!isLoadingOne) {
+                    if (total < totalRecordOne) {
+//                        Log.d("getReport", "itemCount1 :: " + total)
+                        exOne(ReportBody(rowPerPage, pageOne, "", ""))
+                    }
+                }
+                super.onScrolled(recyclerView, dx, dy)
+            }
+        })
+        rvTab2.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+                val visibleItemCount: Int = layoutManager2.childCount
+                val pastVisibleItem: Int = layoutManager2.findFirstCompletelyVisibleItemPosition()
+                val total: Int = adapterTb2.itemCount
+                if (!isLoadingTwo) {
+//                    Log.d("getReport", "total :: plus " + total + " :: " + totalRecordTwo)
+                    if (total < totalRecordTwo) {
+//                        Log.d("getReport", "itemCount2 :: " + total)
+                        exTwo(ReportBody(rowPerPage, pageTwo, "", ""))
+                    }
+                }
+                super.onScrolled(recyclerView, dx, dy)
+            }
+        })
+
+    }
+
+    private fun getReportThree(data: StatementDialogViewState) {
+        if (data.reportThreeList != null) {
+            progress.isVisible = false
+//            Log.d("getReport", "3 :: " + data.reportThreeList!!.size)
+            adapterTb3.submitList(data.reportThreeList)
+        }
+    }
+
+    private fun exOne(reportBetting: ReportBody) {
+//        Log.d("getReport", "load listOne")
+        isLoadingOne = true
+        pageOne++
+        val disposables = CompositeDisposable()
+        disposables.add(
+            apiService.getReportOne(reportBetting)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    progress.isVisible = false
+                    if (it.resultCode == "1") {
+                        totalPageOne = it.data.totalPages
+                        totalRecordOne = it.data.totalRows
+                        val li: List<ReportOne> = it.data.reports
+                        listOne = concatenate(listOne, li)
+//                        Log.d("getReport", "listOne :: " + listOne.size)
+                        adapterTb1.submitList(listOne)
+                        isLoadingOne = false
+                    } else {
+                        isLoadingOne = false
+                        val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.message.description
+                    }
+                }, {
+                    progress.isVisible = false
+                    isLoadingOne = false
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                })
+        )
+    }
+
+    private fun exTwo(reportResult: ReportBody) {
+//        Log.d("getReport", "load listTwo")
+        isLoadingTwo = true
+        pageTwo++
+        val disposables = CompositeDisposable()
+        disposables.add(
+            apiService.getReportTwo(reportResult)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    progress.isVisible = false
+                    if (it.resultCode == "1") {
+                        totalPageTwo = it.data.totalPages
+                        totalRecordTwo = it.data.totalRows
+                        val li: List<ReportTwo> = it.data.results
+                        listTwo = concatenate(listTwo, li)
+//                        Log.d("getReport", "listTwo :: " + listTwo.size)
+                        adapterTb2.submitList(listTwo)
+                        isLoadingTwo = false
+                    } else {
+                        val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.message.description
+                    }
+                }, {
+                    progress.isVisible = false
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                })
+        )
+    }
+
+    private fun exDeposit(reportResult: ReportBody) {
+        isLoadingDeposit = true
+        pageDeposit++
+        val disposables = CompositeDisposable()
+        disposables.add(
+            apiService.getReportDeposit(reportResult)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    progress.isVisible = false
+                    if (it.resultCode == "1") {
+                        tvDepTurnOver.text = it.data.totalAmount
+                        totalPageDeposit = it.data.totalPages
+                        totalRecordDeposit = it.data.totalRows
+                        val li: List<ReportDeposit> = it.data.reports
+                        listDeposit = concatenate(listDeposit, li)
+                        adapterDep.submitList(listDeposit)
+                        isLoadingDeposit = false
+                    } else {
+                        val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.message.description
+                    }
+                }, {
+                    progress.isVisible = false
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                })
+        )
+    }
+
+    private fun exWithdraw(reportResult: ReportBody) {
+        isLoadingWithdraw = true
+        pageWithdraw++
+        val disposables = CompositeDisposable()
+        disposables.add(
+            apiService.getReportWithdraw(reportResult)
+                .timeout(60, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    progress.isVisible = false
+                    if (it.resultCode == "1") {
+                        tvWithTurnOver.text = it.data.totalAmount
+                        totalPageWithdraw = it.data.totalPages
+                        totalRecordWithdraw = it.data.totalRows
+                        val li: List<ReportWithdraw> = it.data.reports
+                        listWithdraw = concatenate(listWithdraw, li)
+                        adapterWith.submitList(listWithdraw)
+                        isLoadingWithdraw = false
+                    } else {
+                        val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.message.description
+                    }
+                }, {
+                    progress.isVisible = false
+                    val message: String = "ប្រតិបត្តិការមិនជោគជ័យ\n" + it.getErrorCode()
+                })
+        )
+    }
+
+    fun init() {
+        adapterDep = ReportAdapter(Type.DEPOSIT)
+        rvTabDeposit.setHasFixedSize(true)
+        layoutManagerDep = LinearLayoutManager(context)
+        rvTabDeposit.layoutManager = layoutManagerDep
+        rvTabDeposit.adapter = adapterDep
+
+        adapterWith = ReportAdapter(Type.DEPOSIT)
+        rvTabWithdraw.setHasFixedSize(true)
+        layoutManagerWit = LinearLayoutManager(context)
+        rvTabWithdraw.layoutManager = layoutManagerWit
+        rvTabWithdraw.adapter = adapterWith
+
+        adapterTb1 = ReportAdapter(Type.WIN)
+        rvTab1.setHasFixedSize(true)
+        layoutManager1 = LinearLayoutManager(context)
+        rvTab1.layoutManager = layoutManager1
+        rvTab1.adapter = adapterTb1
+        adapterTb1.printButtonListener = { reportOne: ReportOne ->
+            printSBCPrintable(reportOne, user.currencyType, sharePref.getChannelType())
+        }
+
+        adapterTb2 = ReportAdapter(Type.WIN_LOST)
+        rvTab2.setHasFixedSize(true)
+        layoutManager2 = LinearLayoutManager(context)
+        rvTab2.layoutManager = layoutManager2
+        rvTab2.adapter = adapterTb2
+
+        adapterTb3 = ReportAdapter(Type.STATEMENT)
+        rvTab3.setHasFixedSize(true)
+        rvTab3.layoutManager = LinearLayoutManager(context)
+        rvTab3.adapter = adapterTb3
+    }
+
+    fun currencyFormat(amount: Double): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+
+    private fun <T> concatenate(vararg lists: List<T>): List<T> {
+        return listOf(*lists).flatten()
+    }
+}

+ 67 - 0
app/src/main/java/com/sambath/sbc/screen/report/StatementListViewHolder.kt

@@ -0,0 +1,67 @@
+package com.sambath.sbc.screen.report
+
+import android.graphics.Color
+import android.view.View
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import com.gdtlib.lib.adapter.BaseListItem
+import com.gdtlib.lib.viewholder.BaseListViewHolder
+import com.sambath.sbc.R
+import com.sambath.sbc.remote.CfStatement
+import java.text.DecimalFormat
+
+class StatementListViewHolder(
+    itemView: View
+) : BaseListViewHolder(itemView) {
+    fun currencyFormat(amount: Int): String? {
+        val formatter = DecimalFormat("#,###")
+        return formatter.format(amount)
+    }
+    override fun bindView(item: BaseListItem) {
+        when (item) {
+            is CfStatement -> {
+//                val txtNO: TextView = itemView.findViewById(R.id.txt_no)
+                val txtDate: TextView = itemView.findViewById(R.id.txt_date)
+                val txtRemark: TextView = itemView.findViewById(R.id.txt_remark)
+                val txtTrunOver: TextView = itemView.findViewById(R.id.txt_trun_over)
+                val txtAmount: TextView = itemView.findViewById(R.id.txt_amount)
+                val txtAmountWin: TextView = itemView.findViewById(R.id.txt_amount_win)
+
+//                txtNO.text = adapterPosition.plus(1).toString() Deposite  Withdraw
+                txtDate.text = item.date
+                txtRemark.text = item.note.toString()
+                when (item.note) {
+                    "Deposite" -> {
+                        txtRemark.setTextColor(ContextCompat.getColor(itemView.context, R.color.color_blue_800))
+                    }
+                    "Withdraw" -> {
+                        txtRemark.setTextColor(ContextCompat.getColor(itemView.context, R.color.color_red_800))
+                    }
+                    else -> {
+                        txtRemark.setTextColor(Color.WHITE)
+                    }
+                }
+                txtTrunOver.text = item.trunOver?.let { currencyFormat(it) }
+                if(item.trunOver!! > 0){
+                    txtTrunOver.setTextColor(ContextCompat.getColor(itemView.context, R.color.wala))
+                }else{
+                    txtTrunOver.setTextColor(Color.WHITE)
+                }
+                txtAmount.text = item.amount?.let { currencyFormat(it) }
+                txtAmount.setTextColor(ContextCompat.getColor(itemView.context, R.color.blue_green))
+                txtAmountWin.text = item.amountWin?.let { currencyFormat(it) }
+                when {
+                    item.amountWin!! >0 -> {
+                        txtAmountWin.setTextColor(ContextCompat.getColor(itemView.context, R.color.light_yellow))
+                    }
+                    item.amountWin < 0 -> {
+                        txtAmountWin.setTextColor(ContextCompat.getColor(itemView.context, R.color.meron))
+                    }
+                    else -> {
+                        txtAmountWin.setTextColor(Color.WHITE)
+                    }
+                }
+            }
+        }
+    }
+}

+ 41 - 0
app/src/main/java/com/sambath/sbc/screen/report/StatementViewModel.kt

@@ -0,0 +1,41 @@
+package com.sambath.sbc.screen.report
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.sambath.sbc.base.BaseViewModel
+import com.sambath.sbc.remote.service.ApiService
+import com.sambath.sbc.util.PrefHelper
+
+class StatementViewModel (val apiService: ApiService, val prefHelper: PrefHelper): BaseViewModel() {
+    private val _state = MutableLiveData<StatementViewState>(StatementViewState())
+    val state: LiveData<StatementViewState> = _state
+    fun getStatementData(){
+//        if (_state.value!!.isProgress) return
+//        _state.value = prev().copy(isProgress = true)
+//        disposables.add(
+//            apiService.getStatementData()
+//                .timeout(60, TimeUnit.SECONDS)
+//                .subscribeOn(Schedulers.io())
+//                .observeOn(AndroidSchedulers.mainThread())
+//                .subscribe({
+//                    if (it.resultCode == "1") {
+////                        Log.d("dataxzsd", it.data.toString())
+//                        _state.value = prev().copy(
+//                            isProgress = false,
+//                            error = null,
+//                            statementList = it.data?.statementList
+//                        )
+//                    } else {
+//                        _state.value =
+//                            prev().copy(isProgress = false, error = "[${it.message.description}]")
+//                    }
+//                }, {
+////                    Log.d("dataxzsd", it.getErrorCode())
+//                    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/sambath/sbc/screen/report/StatementViewState.kt

@@ -0,0 +1,10 @@
+package com.sambath.sbc.screen.report
+
+import com.sambath.sbc.remote.CfStatement
+
+data class StatementViewState(
+    val initial: Boolean = true,
+    val isProgress: Boolean = false,
+    val error: String? = null,
+    var statementList: List<CfStatement>? = null,
+)

+ 10 - 0
app/src/main/java/com/sambath/sbc/screen/result/ResultViewState.kt

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

+ 17 - 0
app/src/main/java/com/sambath/sbc/screen/result/Table1Adapter.kt

@@ -0,0 +1,17 @@
+package com.sambath.sbc.screen.result
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.sambath.sbc.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/sambath/sbc/screen/result/Table1ListItem.kt

@@ -0,0 +1,11 @@
+package com.sambath.sbc.screen.result
+
+import com.gdtlib.lib.adapter.BaseListItem
+
+data class Table1ListItem(
+    val Id: Int,
+    var color: String = "cir-white",
+    var fightNo: String = ""
+) : BaseListItem() {
+    override fun getUnique(): String = Id.toString()//"${Id}${color}"
+}

+ 38 - 0
app/src/main/java/com/sambath/sbc/screen/result/Table1ListViewHolder.kt

@@ -0,0 +1,38 @@
+package com.sambath.sbc.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.sambath.sbc.R
+
+class Table1ListViewHolder(
+    itemView: View
+) : BaseListViewHolder(itemView) {
+    private val ivCircle = itemView.findViewById<ImageView>(R.id.img_color)
+    private val txtFightNo = itemView.findViewById<TextView>(R.id.txtFightNo)
+    override fun bindView(item: BaseListItem) {
+        when (item) {
+            is Table1ListItem -> {
+                with(item) {
+                    txtFightNo.text = fightNo
+                    when (color) {
+                        "cir-blue" -> {//1 is blue small
+                            ivCircle.setImageResource(R.drawable.bg_circle_blue)
+                        }
+                        "cir-red" -> {//2 is red big
+                            ivCircle.setImageResource(R.drawable.bg_circle_red)
+                        }
+                        "cir-green" -> {//3 is green big
+                            ivCircle.setImageResource(R.drawable.bg_circle_green)
+                        }
+                        "cir-cancel" -> {//4 is yellow big
+                            ivCircle.setImageResource(R.drawable.bg_circle_yellow)
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 20 - 0
app/src/main/java/com/sambath/sbc/screen/result/Table2Adapter.kt

@@ -0,0 +1,20 @@
+package com.sambath.sbc.screen.result
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gdtlib.lib.adapter.BaseListAdapter
+import com.sambath.sbc.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/sambath/sbc/screen/result/Table2ListItem.kt

@@ -0,0 +1,11 @@
+package com.sambath.sbc.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/sambath/sbc/screen/result/Table2ListViewHolder.kt

@@ -0,0 +1,47 @@
+package com.sambath.sbc.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.sambath.sbc.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()
+                    }
+                }
+            }
+
+        }
+
+    }
+}

+ 167 - 0
app/src/main/java/com/sambath/sbc/screen/setting/SettingFragment.kt

@@ -0,0 +1,167 @@
+package com.sambath.sbc.screen.setting
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.textfield.TextInputLayout
+import com.mazenrashed.printooth.Printooth
+import com.mazenrashed.printooth.ui.ScanningActivity
+import com.sambath.sbc.R
+import com.sambath.sbc.app.App
+import com.sambath.sbc.app.ShareActivity
+import com.sambath.sbc.base.BaseFragment
+import com.sambath.sbc.extension.btnClick
+import com.sambath.sbc.remote.ChangePwd
+import com.sambath.sbc.remote.User
+import com.sambath.sbc.screen.login.LoginActivity
+import com.sambath.sbc.util.Const
+import com.sambath.sbc.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: MaterialButton
+    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)
+        user = ModelPreferencesManager.get<User>(Const.USER_KEY)!!
+        (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
+            layCfStatus.isVisible = false
+            btnClose = view.findViewById<MaterialButton>(R.id.btn_close)
+            btnClose.setOnClickListener {
+//                if (!sharePref.getIsMute()) betTouch.start()
+                it.btnClick().subscribe {
+                    onBackPressed()
+                }
+            }
+        }
+        val tilCurrentPwd = view.findViewById<TextInputLayout>(R.id.til_new_pwd)
+        val tilNewPwd = 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 = ""
+                tilCurrentPwd.error = null
+                tilCurrentPwd.isErrorEnabled = false
+                tilNewPwd.error = null
+                tilNewPwd.isErrorEnabled = false
+                val currentPwd = et_current_pwd.text
+                val newPwd = et_new_pwd.text
+                if (currentPwd.isNullOrEmpty()) {
+                    tilCurrentPwd.error = getString(R.string.err_not_empty)
+                    tilCurrentPwd.requestFocus()
+                    tv_error.text = getString(R.string.err_not_empty)
+                    return@subscribe
+                }
+                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 (currentPwd.toString() == newPwd.toString()) {
+                    tilCurrentPwd.error = getString(R.string.err_wrong_pwd)
+                    tilNewPwd.error = getString(R.string.err_wrong_pwd)
+                    tv_error.text = getString(R.string.err_wrong_pwd)
+                    return@subscribe
+                }
+                settingViewModel.updatePassword(
+                    ChangePwd(currentPwd.toString().trim(), newPwd.toString().trim())
+                )
+            }
+        }
+
+        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
+    }
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor