浏览代码

init architecture

aaron 6 年之前
父节点
当前提交
e7346a03bd

+ 3 - 1
app/src/main/AndroidManifest.xml

@@ -4,7 +4,9 @@
 
 
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <application
     <application
-        android:allowBackup="true"
+        android:name=".MorakMorakApp"
+        android:allowBackup="false"
+        android:fullBackupContent="false"
         android:icon="@mipmap/ic_launcher"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
         android:label="@string/app_name"
         android:roundIcon="@mipmap/ic_launcher_round"
         android:roundIcon="@mipmap/ic_launcher_round"

+ 15 - 1
app/src/main/java/com/hanwha/morakmorak/MorakMorakApp.kt

@@ -1,7 +1,21 @@
 package com.hanwha.morakmorak
 package com.hanwha.morakmorak
 
 
+import android.app.Application
+import com.hanwha.morakmorak.di.networkModule
+import com.ntels.product.chatbot.util.AppLogger
+import org.koin.android.ext.android.startKoin
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
  */
  */
-class MorakMorakApp {
+class MorakMorakApp : Application() {
+
+    override fun onCreate() {
+        super.onCreate()
+
+        AppLogger.init()
+        startKoin(this, listOf(
+                networkModule
+        ))
+    }
 }
 }

+ 57 - 1
app/src/main/java/com/hanwha/morakmorak/di/NetworkModule.kt

@@ -1,5 +1,61 @@
 package com.hanwha.morakmorak.di
 package com.hanwha.morakmorak.di
 
 
+import com.google.gson.GsonBuilder
+import com.hanwha.morakmorak.BuildConfig
+import okhttp3.Cache
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.koin.android.ext.koin.androidApplication
+import org.koin.dsl.module.module
+import retrofit2.Retrofit
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
+import retrofit2.converter.gson.GsonConverterFactory
+import java.util.concurrent.TimeUnit
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
- */
+ */
+
+private const val CONNECT_TIMEOUT = 15L
+private const val WRITE_TIMEOUT = 15L
+private const val READ_TIMEOUT = 15L
+
+val networkModule = module {
+    single { Cache(androidApplication().cacheDir, 10L * 1024 * 1024) }
+
+    single { GsonBuilder().create() }
+
+    single {
+        OkHttpClient.Builder().apply {
+            cache(get())
+            connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
+            writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
+            readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
+            retryOnConnectionFailure(true)
+//            addInterceptor(get())
+            addInterceptor(HttpLoggingInterceptor().apply {
+                if (BuildConfig.DEBUG) {
+                    level = HttpLoggingInterceptor.Level.BODY
+                }
+            })
+        }.build()
+    }
+
+    single {
+        Retrofit.Builder()
+                .baseUrl(BuildConfig.BASE_URL)
+                .addConverterFactory(GsonConverterFactory.create(get()))
+                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+                .client(get())
+                .build()
+    }
+
+//    single {
+//        Interceptor { chain ->
+//            chain.proceed(chain.request().newBuilder().apply {
+//                header("Accept", "application/vnd.github.mercy-preview+json")
+//            }.build())
+//        }
+//    }
+}

+ 9 - 1
app/src/main/java/com/hanwha/morakmorak/extensions/BindingAdapterExtensions.kt

@@ -1,5 +1,13 @@
 package com.hanwha.morakmorak.extensions
 package com.hanwha.morakmorak.extensions
 
 
+import android.databinding.BindingAdapter
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
- */
+ */
+
+@BindingAdapter("refreshing")
+fun SwipeRefreshLayout.refreshing(visible: Boolean) {
+    isRefreshing = visible
+}

+ 31 - 1
app/src/main/java/com/hanwha/morakmorak/extensions/RxExtensions.kt

@@ -1,5 +1,35 @@
 package com.hanwha.morakmorak.extensions
 package com.hanwha.morakmorak.extensions
 
 
+import android.databinding.ObservableField
+import io.reactivex.Observable
+import io.reactivex.Single
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import timber.log.Timber
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
- */
+ */
+
+fun <T> Single<T>.with(): Single<T> = subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
+
+fun <T> ObservableField<T>.asObservable() : Observable<T> {
+    return Observable.create { emitter ->
+
+        emitter.onNext(get()!!)
+
+        val callback = object : android.databinding.Observable.OnPropertyChangedCallback() {
+            override fun onPropertyChanged(observable: android.databinding.Observable, i: Int) {
+                if (observable === this) {
+                    Timber.d(get().toString())
+                    emitter.onNext(get()!!)
+                }
+            }
+        }
+
+        addOnPropertyChangedCallback(callback)
+        emitter.setCancellable { removeOnPropertyChangedCallback(callback) }
+    }
+}
+
+object RxUtils

+ 19 - 1
app/src/main/java/com/hanwha/morakmorak/ui/BindingActivity.kt

@@ -1,7 +1,25 @@
 package com.hanwha.morakmorak.ui
 package com.hanwha.morakmorak.ui
 
 
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.os.Bundle
+import androidx.annotation.LayoutRes
+import androidx.appcompat.app.AppCompatActivity
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
  */
  */
-class BindingActivity {
+abstract class BindingActivity<T : ViewDataBinding> : AppCompatActivity() {
+
+    @LayoutRes
+    abstract fun getLayoutResId(): Int
+
+    protected lateinit var binding: T
+        private set
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        binding = DataBindingUtil.setContentView(this, getLayoutResId())
+    }
 }
 }

+ 20 - 1
app/src/main/java/com/hanwha/morakmorak/ui/BindingFragment.kt

@@ -1,7 +1,26 @@
 package com.hanwha.morakmorak.ui
 package com.hanwha.morakmorak.ui
 
 
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
  */
  */
-class BindingFragment {
+abstract class BindingFragment<T : ViewDataBinding> : Fragment() {
+
+    @LayoutRes
+    abstract fun getLayoutResId(): Int
+
+    protected lateinit var binding: T
+        private set
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        return DataBindingUtil.inflate<T>(inflater, getLayoutResId(), container, false).apply { binding = this }.root
+    }
 }
 }

+ 7 - 1
app/src/main/java/com/hanwha/morakmorak/ui/BindingViewHolder.kt

@@ -1,7 +1,13 @@
 package com.hanwha.morakmorak.ui
 package com.hanwha.morakmorak.ui
 
 
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
  */
  */
-class BindingViewHolder {
+abstract class BindingViewHolder<out T : ViewDataBinding>(view: View) : RecyclerView.ViewHolder(view) {
+    val binding: T = DataBindingUtil.bind(view)!!
 }
 }

+ 32 - 32
app/src/main/java/com/hanwha/morakmorak/util/CommonUtils.kt

@@ -1,4 +1,4 @@
-package com.ntels.product.chatbot.util
+package com.hanwha.morakmorak.util
 
 
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
 import android.annotation.TargetApi
 import android.annotation.TargetApi
@@ -7,7 +7,7 @@ import android.os.Build
 import android.provider.Settings.Secure
 import android.provider.Settings.Secure
 import android.telephony.TelephonyManager
 import android.telephony.TelephonyManager
 import android.text.format.DateFormat
 import android.text.format.DateFormat
-import com.ntels.product.chatbot.data.DataManager
+//import com.ntels.product.chatbot.data.DataManager
 import timber.log.Timber
 import timber.log.Timber
 import java.io.BufferedReader
 import java.io.BufferedReader
 import java.io.IOException
 import java.io.IOException
@@ -69,11 +69,11 @@ class CommonUtils {
 
 
         @JvmStatic fun readTermsFromAssets(context: Context): String? {
         @JvmStatic fun readTermsFromAssets(context: Context): String? {
             var tempStr = ""
             var tempStr = ""
-            var inputStreamReader: InputStreamReader? = InputStreamReader(context.assets.open("terms.txt"))
-            var reader: BufferedReader? = BufferedReader(inputStreamReader)
+            val inputStreamReader: InputStreamReader? = InputStreamReader(context.assets.open("terms.txt"))
+            val reader: BufferedReader? = BufferedReader(inputStreamReader)
 
 
             try {
             try {
-                var line: String? = null
+                var line: String?
                 while (!reader!!.readLine().also { line = it }.isNullOrEmpty()) tempStr += "$line\n"
                 while (!reader!!.readLine().also { line = it }.isNullOrEmpty()) tempStr += "$line\n"
                 reader.close()
                 reader.close()
                 inputStreamReader?.close()
                 inputStreamReader?.close()
@@ -96,7 +96,7 @@ class CommonUtils {
 
 
             return when {
             return when {
                 id.isNullOrEmpty() -> 1
                 id.isNullOrEmpty() -> 1
-                id!!.length < 6 -> 2
+                id.length < 6 -> 2
                 id.contains(" ") -> 3
                 id.contains(" ") -> 3
                 (!matcher.matches() || englishMatcher.matches() || numberMatcher.matches()) -> 4
                 (!matcher.matches() || englishMatcher.matches() || numberMatcher.matches()) -> 4
                 (!checkContinueChar(id)) -> 6
                 (!checkContinueChar(id)) -> 6
@@ -204,32 +204,32 @@ class CommonUtils {
          */
          */
         @JvmStatic fun delSpecialChar(str: String) = str.replace("[^\uAC00-\uD7A3xfe0-9a-zA-Z\\s]".toRegex(), "")
         @JvmStatic fun delSpecialChar(str: String) = str.replace("[^\uAC00-\uD7A3xfe0-9a-zA-Z\\s]".toRegex(), "")
 
 
-        @JvmStatic fun getDeviceUUID(context: Context, dataManager: DataManager): String {
-            val id = dataManager.deviceId
-
-            var uuid: UUID? = null
-            if (id.isNotEmpty()) {
-                uuid = UUID.fromString(id)
-            } else {
-                val androidId = Secure.getString(context.contentResolver, Secure.ANDROID_ID)
-                try {
-                    uuid = if ("9774d56d682e549c" != androidId) {
-                        UUID.nameUUIDFromBytes(androidId.toByteArray(Charset.forName("utf-8")))
-                    } else {
-                        val deviceId = (context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).deviceId
-                        if (deviceId != null) UUID.nameUUIDFromBytes(deviceId.toByteArray(Charset.forName("utf-8"))) else UUID.randomUUID()
-                    }
-                } catch (e: UnsupportedEncodingException) {
-                    throw RuntimeException(e)
-                } catch (e: SecurityException) {
-                    throw RuntimeException(e)
-                }
-
-                dataManager.deviceId = uuid.toString()
-            }
-
-            return uuid.toString()
-        }
+//        @JvmStatic fun getDeviceUUID(context: Context, dataManager: DataManager): String {
+//            val id = dataManager.deviceId
+//
+//            var uuid: UUID? = null
+//            if (id.isNotEmpty()) {
+//                uuid = UUID.fromString(id)
+//            } else {
+//                val androidId = Secure.getString(context.contentResolver, Secure.ANDROID_ID)
+//                try {
+//                    uuid = if ("9774d56d682e549c" != androidId) {
+//                        UUID.nameUUIDFromBytes(androidId.toByteArray(Charset.forName("utf-8")))
+//                    } else {
+//                        val deviceId = (context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).deviceId
+//                        if (deviceId != null) UUID.nameUUIDFromBytes(deviceId.toByteArray(Charset.forName("utf-8"))) else UUID.randomUUID()
+//                    }
+//                } catch (e: UnsupportedEncodingException) {
+//                    throw RuntimeException(e)
+//                } catch (e: SecurityException) {
+//                    throw RuntimeException(e)
+//                }
+//
+//                dataManager.deviceId = uuid.toString()
+//            }
+//
+//            return uuid.toString()
+//        }
 
 
 //        @JvmStatic fun unixTimeToDate(unixTime: Long): String {
 //        @JvmStatic fun unixTimeToDate(unixTime: Long): String {
 //            val date = Date(unixTime * 1000L)
 //            val date = Date(unixTime * 1000L)

+ 7 - 1
app/src/main/java/com/hanwha/morakmorak/util/Executors.kt

@@ -1,5 +1,11 @@
 package com.hanwha.morakmorak.util
 package com.hanwha.morakmorak.util
 
 
+import java.util.concurrent.Executors
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
- */
+ */
+
+private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
+
+fun ioThread(f : () -> Unit) = IO_EXECUTOR.execute(f)

+ 10 - 10
app/src/main/java/com/hanwha/morakmorak/util/NetworkUtils.kt

@@ -1,4 +1,4 @@
-package com.ntels.product.chatbot.util
+package com.hanwha.morakmorak.util
 
 
 import android.content.Context
 import android.content.Context
 import android.net.ConnectivityManager
 import android.net.ConnectivityManager
@@ -12,16 +12,16 @@ import android.net.Uri
 class NetworkUtils {
 class NetworkUtils {
 
 
     companion object {
     companion object {
-        @JvmStatic
-        fun isNetworkConnected(context: Context): Boolean {
-            val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE)
-            return if (connectivityManager is ConnectivityManager) {
-                val networkInfo: NetworkInfo? = connectivityManager.activeNetworkInfo
-                networkInfo?.isConnected ?: false
-            } else false
-        }
+//        @JvmStatic
+//        fun isNetworkConnected(context: Context): Boolean {
+//            val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE)
+//            return if (connectivityManager is ConnectivityManager) {
+//                val networkInfo: NetworkInfo? = connectivityManager.activeNetworkInfo
+//                networkInfo?.isConnected ?: false
+//            } else false
+//        }
 
 
-        @JvmStatic fun parseUrlParameter(url: String) = HashMap<String, String>().apply {
+        @JvmStatic fun parseUrlParameter(url: String) = HashMap<String, String?>().apply {
                 Uri.parse(url).queryParameterNames.forEach { put(it, Uri.parse(url).getQueryParameter(it)) }
                 Uri.parse(url).queryParameterNames.forEach { put(it, Uri.parse(url).getQueryParameter(it)) }
         }
         }
     }
     }

+ 11 - 0
app/src/main/java/com/hanwha/morakmorak/util/NotNullMutableLiveData.kt

@@ -1,7 +1,18 @@
 package com.hanwha.morakmorak.util
 package com.hanwha.morakmorak.util
 
 
+import androidx.lifecycle.MutableLiveData
+
 /**
 /**
  * Created by aaron on 08/07/2019
  * Created by aaron on 08/07/2019
  */
  */
 class NotNullMutableLiveData {
 class NotNullMutableLiveData {
+
+    class NotNullMutableLiveData<T : Any>(defaultValue: T) : MutableLiveData<T>() {
+
+        init {
+            value = defaultValue
+        }
+
+        override fun getValue()  = super.getValue()!!
+    }
 }
 }

+ 2 - 2
app/src/main/java/com/hanwha/morakmorak/util/ViewUtils.kt

@@ -1,8 +1,8 @@
-package com.ntels.product.chatbot.util
+package com.hanwha.morakmorak.util
 
 
 import android.content.res.Resources
 import android.content.res.Resources
-import android.support.design.widget.TabLayout
 import android.view.ViewGroup
 import android.view.ViewGroup
+import com.google.android.material.tabs.TabLayout
 
 
 /**
 /**
  * Created by aaron on 2018-05-30
  * Created by aaron on 2018-05-30

+ 111 - 0
versions.gradle

@@ -0,0 +1,111 @@
+ext.deps = [:]
+def deps = [:]
+def versions = [:]
+
+versions.room = "2.1.0-alpha03"
+versions.lifecycle = "2.0.0"
+versions.support = "1.0.0"
+versions.junit = "4.12"
+versions.espresso = "3.1.0-alpha4"
+versions.retrofit = "2.3.0"
+versions.okhttp_logging_interceptor = "3.9.0"
+versions.mockito = "2.7.19"
+versions.mockito_all = "1.10.19"
+versions.mockito_android = "2.22.0"
+versions.constraint_layout = "2.0.0-alpha2"
+versions.android_gradle_plugin = '3.3.0'
+versions.rxjava2 = "2.1.3"
+versions.rx_android = "2.0.1"
+versions.axt_runner = "1.1.0-alpha4"
+versions.axt_rules = "1.1.0-alpha4"
+versions.hamcrest = "2.1"
+versions.kotlin = "1.3.0"
+versions.koin = "1.0.2"
+versions.paging = "2.1.0-rc01"
+versions.timber = "4.7.0"
+
+def support = [:]
+support.annotations = "androidx.annotation:annotation:$versions.support"
+support.app_compat = "androidx.appcompat:appcompat:$versions.support"
+support.recyclerview = "androidx.recyclerview:recyclerview:$versions.support"
+support.design = "com.google.android.material:material:$versions.support"
+support.v4 = "androidx.legacy:legacy-support-v4:$versions.support"
+support.core_utils = "androidx.legacy:legacy-support-core-utils:$versions.support"
+
+def room = [:]
+room.runtime = "androidx.room:room-runtime:$versions.room"
+room.compiler = "androidx.room:room-compiler:$versions.room"
+room.rxjava2 = "androidx.room:room-rxjava2:$versions.room"
+room.testing = "androidx.room:room-testing:$versions.room"
+
+def lifecycle = [:]
+lifecycle.runtime = "androidx.lifecycle:lifecycle-runtime:$versions.lifecycle"
+lifecycle.extensions = "androidx.lifecycle:lifecycle-extensions:$versions.lifecycle"
+lifecycle.java8 = "androidx.lifecycle:lifecycle-common-java8:$versions.lifecycle"
+lifecycle.compiler = "androidx.lifecycle:lifecycle-compiler:$versions.lifecycle"
+
+def retrofit = [:]
+retrofit.runtime = "com.squareup.retrofit2:retrofit:$versions.retrofit"
+retrofit.rx_adapter = "com.squareup.retrofit2:adapter-rxjava2:$versions.retrofit"
+retrofit.gson = "com.squareup.retrofit2:converter-gson:$versions.retrofit"
+
+def espresso = [:]
+espresso.core = "androidx.test.espresso:espresso-core:$versions.espresso"
+espresso.contrib = "androidx.test.espresso:espresso-contrib:$versions.espresso"
+espresso.intents = "androidx.test.espresso:espresso-intents:$versions.espresso"
+
+def axt = [:]
+axt.runner = "androidx.test:runner:$versions.axt_runner"
+axt.rules = "androidx.test:rules:$versions.axt_rules"
+
+def mockito = [:]
+mockito.core = "org.mockito:mockito-core:$versions.mockito"
+mockito.all = "org.mockito:mockito-all:$versions.mockito_all"
+mockito.android = "org.mockito:mockito-android:$versions.mockito_android"
+
+def kotlin = [:]
+kotlin.stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin"
+kotlin.test = "org.jetbrains.kotlin:kotlin-test-junit:$versions.kotlin"
+kotlin.plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
+kotlin.allopen = "org.jetbrains.kotlin:kotlin-allopen:$versions.kotlin"
+
+def koin = [:]
+koin.core = "org.koin:koin-core:$versions.koin"
+koin.android = "org.koin:koin-android:$versions.koin"
+koin.architecture = "org.koin:koin-androidx-viewmodel:$versions.koin"
+koin.test = "org.koin:koin-test:$versions.koin"
+
+def build_versions = [:]
+build_versions.min_sdk = 21
+build_versions.target_sdk = 28
+build_versions.build_tools = "28.0.3"
+
+deps.kotlin = kotlin
+deps.koin = koin
+deps.support = support
+deps.retrofit = retrofit
+deps.lifecycle = lifecycle
+deps.rxjava2 = "io.reactivex.rxjava2:rxjava:$versions.rxjava2"
+deps.rx_android = "io.reactivex.rxjava2:rxandroid:$versions.rx_android"
+deps.room = room
+deps.mockito = mockito
+deps.axt = axt
+deps.espresso = espresso
+deps.android_gradle_plugin = "com.android.tools.build:gradle:$versions.android_gradle_plugin"
+deps.okhttp_logging_interceptor = "com.squareup.okhttp3:logging-interceptor:${versions.okhttp_logging_interceptor}"
+deps.paging_ktx = "androidx.paging:paging-runtime-ktx:$versions.paging"
+deps.constraint_layout = "androidx.constraintlayout:constraintlayout:$versions.constraint_layout"
+deps.junit = "junit:junit:$versions.junit"
+deps.hamcrest = "org.hamcrest:hamcrest:$versions.hamcrest"
+deps.timber = "com.jakewharton.timber:timber:$versions.timber"
+
+ext.build_versions = build_versions
+ext.deps = deps
+
+static def addRepos(RepositoryHandler handler) {
+    handler.google()
+    handler.jcenter()
+    handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
+}
+
+ext.addRepos = this.&addRepos