Skip to content

Instantly share code, notes, and snippets.

@Lukmannudin
Last active July 25, 2020 14:04
Show Gist options
  • Select an option

  • Save Lukmannudin/4bd698d722c4de61cb6bc72fafca0b57 to your computer and use it in GitHub Desktop.

Select an option

Save Lukmannudin/4bd698d722c4de61cb6bc72fafca0b57 to your computer and use it in GitHub Desktop.
Source Code Aplikasi Sleepy Platform Android Sesudah Reengineering
package id.diamondsleep.data.remoteapi
import id.diamondsleep.data.mapper.BaseRemote
import id.diamondsleep.data.source.dataarticle.articleremote.ArticleRemote
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Path
interface ArticleApi {
@GET("articles/{page}")
suspend fun getArticles(@Path("page") page: Int): Response<BaseRemote<List<ArticleRemote>>>
}
package id.diamondsleep.data.source.dataarticle.articlelocal
import androidx.room.*
@Dao
interface ArticleDao {
@Query("SELECT * FROM articles")
suspend fun getArticles(): List<ArticleLocal>
@Query("SELECT * FROM articles WHERE idArticle =:idArticle")
suspend fun getArticle(idArticle: Int): ArticleLocal
@Query("DELETE FROM articles")
suspend fun clearArticles()
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertArticle(article: List<ArticleLocal>)
@Delete
fun delete(article: ArticleLocal)
}
package id.diamondsleep.data.source
import id.diamondsleep.model.Article
import id.diamondsleep.model.Result
interface ArticleDataSource {
suspend fun getArticle(idArticle: Int): Result<Article>
suspend fun getArticles(page: Int): Result<List<Article>>
suspend fun saveArticles(articles: List<Article>)
}
package id.diamondsleep.data.source.dataarticle.articlelocal
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "articles")
data class ArticleLocal(
@PrimaryKey
val idArticle: Int,
val title: String,
val imageUrl: String,
val content: String,
val source: String,
val date: String,
val author: String
)
package id.diamondsleep.data.source.dataarticle.articlelocal
import id.diamondsleep.data.mapper.articlemapper.ArticleMapper
import id.diamondsleep.data.source.ArticleDataSource
import id.diamondsleep.model.Article
import id.diamondsleep.model.Result
class ArticleLocalDataSource(
private val articleDao: ArticleDao
) : ArticleDataSource {
override suspend fun getArticle(idArticle: Int): Result<Article> {
return try {
Result.Success(ArticleMapper.articleLocalToArticle(articleDao.getArticle(idArticle)))
} catch (e: Exception) {
e.printStackTrace()
Result.Error(Exception(e.localizedMessage))
}
}
override suspend fun getArticles(page: Int): Result<List<Article>> {
return try {
Result.Success(ArticleMapper.articlesLocalToArticles(articleDao.getArticles()))
} catch (e: Exception) {
e.printStackTrace()
Result.Error(Exception(e.localizedMessage))
}
}
override suspend fun saveArticles(articles: List<Article>) {
articleDao.clearArticles()
articleDao.insertArticle(ArticleMapper.articlesToLocals(articles))
}
}
package id.diamondsleep.data.mapper.articlemapper
import id.diamondsleep.data.mapper.Mapper
import id.diamondsleep.data.source.dataarticle.articlelocal.ArticleLocal
import id.diamondsleep.model.Article
class ArticleLocalToArticle : Mapper<ArticleLocal, Article> {
override fun map(input: ArticleLocal): Article {
return Article(
input.idArticle,
input.title,
input.imageUrl,
input.content,
input.source,
input.date,
input.author
)
}
}
package id.diamondsleep.data.mapper.articlemapper
import id.diamondsleep.data.source.dataarticle.articlelocal.ArticleLocal
import id.diamondsleep.data.source.dataarticle.articleremote.ArticleRemote
import id.diamondsleep.model.Article
object ArticleMapper {
fun articlesRemoteToArticles(articlesRemote: List<ArticleRemote>): List<Article> {
return ArticlesRemoteToArticles(ArticleRemoteToArticle()).map(articlesRemote)
}
fun articleLocalToArticle(articleLocal: ArticleLocal): Article {
return ArticleLocalToArticle().map(articleLocal)
}
fun articlesLocalToArticles(articlesLocal: List<ArticleLocal>): List<Article> {
return ArticlesLocalToArticles(ArticleLocalToArticle()).map(articlesLocal)
}
fun articlesToLocals(articles: List<Article>): List<ArticleLocal> {
return ArticlesToLocal(ArticleToLocal()).map(articles)
}
}
package id.diamondsleep.data.source.dataarticle
import id.diamondsleep.data.source.ArticleDataSource
import id.diamondsleep.model.Article
import id.diamondsleep.model.Result
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.withContext
import timber.log.Timber
class ArticleRepository(
private val articleRemoteDataSource: ArticleDataSource,
private val articleLocalDataSource: ArticleDataSource,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : ArticleRepositoryContract {
override suspend fun getArticle(idArticle: Int): Flow<Result<Article>> = flow {
when (val resultLocal = articleLocalDataSource.getArticle(idArticle)) {
is Result.Success -> {
emit(Result.Success(resultLocal.data))
}
is Result.Error -> {
emit(Result.Error(resultLocal.exception))
}
}
}
override suspend fun getArticles(page: Int): Flow<Result<List<Article>>> = flow {
when (val resultLocal = articleLocalDataSource.getArticles(page)) {
is Result.Success -> {
emit(Result.Success(resultLocal.data))
}
is Result.Error -> {
emit(Result.Error(resultLocal.exception))
}
}
when (val resultRemote = articleRemoteDataSource.getArticles(page)) {
is Result.Success -> {
saveArticles(resultRemote.data)
emit(Result.Success(resultRemote.data))
}
is Result.Error -> {
emit(Result.Error(resultRemote.exception))
}
}
}
override suspend fun saveArticles(articles: List<Article>) {
withContext(ioDispatcher) {
articleLocalDataSource.saveArticles(articles)
articleRemoteDataSource.saveArticles(articles)
}
}
}
package id.diamondsleep.data.source.dataarticle
import id.diamondsleep.model.Article
import id.diamondsleep.model.Result
import kotlinx.coroutines.flow.Flow
interface ArticleRepositoryContract {
suspend fun getArticle(idArticle: Int): Flow<Result<Article>>
suspend fun getArticles(page: Int): Flow<Result<List<Article>>>
suspend fun saveArticles(articles: List<Article>)
}
package id.diamondsleep.ui.home.tips
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.core.text.HtmlCompat
import com.bumptech.glide.Glide
import id.diamondsleep.R
import id.diamondsleep.model.Tip
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.utilities.helper.StringToDateConverter
import kotlinx.android.synthetic.main.activity_content_article.*
class DetailTipsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_content_article)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = resources.getString(R.string.tips)
val dataIntentTips = intent.getParcelableExtra<Tip>(ConstantValue.DATA_CONTENT)
setView(dataIntentTips)
}
private fun setView(tips: Tip) {
detail_content_title.text = tips.title
detail_content_author.text = tips.author
detail_content_date.text = StringToDateConverter.changeFormatDate(tips.date)
detail_content_text.text = HtmlCompat.fromHtml(tips.content, HtmlCompat.FROM_HTML_MODE_COMPACT)
Glide.with(this).load(tips.imageUrl).into(detail_content_thumbnail)
detail_content_source.text = tips.source
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
if (item?.itemId == android.R.id.home) {
super.onBackPressed()
}
return super.onOptionsItemSelected(item)
}
}
package id.diamondsleep.utilities.backgroundservice
import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.wifi.WifiManager
import android.os.IBinder
import id.diamondsleep.utilities.ConstantValue
import java.lang.reflect.InvocationTargetException
import java.util.*
class InternetService : Service() {
private val twoHours = 60 * 120
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent!!.getBooleanExtra(ConstantValue.DEACTIVE_SERVICE, false)) {
stopSelf()
}
var increment = 0
Timer().scheduleAtFixedRate(object : TimerTask() {
override fun run() {
increment++
if (increment == twoHours) {
increment = 0
setMobileDataEnabled(this@InternetService, false)
setWifiEnabled(this@InternetService, false)
}
}
}, 0, 1000)
return START_NOT_STICKY
}
@Throws(ClassNotFoundException::class, NoSuchFieldException::class, IllegalAccessException::class, NoSuchMethodException::class, InvocationTargetException::class)
fun setMobileDataEnabled(context: Context, enabled: Boolean) {
val conman = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val conmanClass = Class.forName(conman.javaClass.name)
val connectivityManagerField = conmanClass.getDeclaredField("mService")
connectivityManagerField.isAccessible = true
val connectivityManager: Any = connectivityManagerField.get(conman)
val connectivityManagerClass = Class.forName(connectivityManager.javaClass.name)
val setMobileDataEnabledMethod = connectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", java.lang.Boolean.TYPE)
setMobileDataEnabledMethod.isAccessible = true
setMobileDataEnabledMethod.invoke(connectivityManager, enabled)
}
fun setWifiEnabled(context: Context, status: Boolean) {
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
wifiManager.isWifiEnabled = status
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
package id.diamondsleep.utilities.backgroundservice
import android.app.Service
import android.content.Context
import android.content.Intent
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.IBinder
import id.diamondsleep.R
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.utilities.SleepyNotification
import java.util.*
import kotlin.math.roundToInt
class LightService : Service() {
private lateinit var sensorManager: SensorManager
private lateinit var lightSensor: Sensor
private var lightValue = 0
private var lightIntensityValueSum = 0
private val lightIntensityTolerance = 80
private var timeLimit = 60 * 5
private var incrementMillisecond = 0
override fun onCreate() {
super.onCreate()
sensorManager = applicationContext.getSystemService(Context.SENSOR_SERVICE) as SensorManager
lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent!!.getBooleanExtra(ConstantValue.DEACTIVE_SERVICE, false)) {
stopSelf()
}
sensorManager.registerListener(lightSensorListener, lightSensor, SensorManager.SENSOR_DELAY_NORMAL)
Timer().scheduleAtFixedRate(object : TimerTask() {
override fun run() {
++incrementMillisecond
lightIntensityValueSum += lightValue
showNotificationIfLightIntencityDisturbing()
}
}, 0, 1000)
return START_NOT_STICKY
}
private fun showNotificationIfLightIntencityDisturbing() {
if (incrementMillisecond == timeLimit) {
incrementMillisecond = 0
val meanLightValue = lightIntensityValueSum / timeLimit
if (meanLightValue > lightIntensityTolerance) {
showLightIntencityNotification()
}
}
}
private fun showLightIntencityNotification() {
val notification = SleepyNotification(this@LightService)
notification.apply {
title = "Light Intensity $lightValue lux"
message = getString(R.string.message_for_turnoff_light_disturbing)
showNotification()
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onDestroy() {
super.onDestroy()
sensorManager.unregisterListener(lightSensorListener)
}
private val lightSensorListener = object : SensorEventListener {
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
}
override fun onSensorChanged(event: SensorEvent?) {
lightValue = event!!.values[0].roundToInt()
if (isFirstValueChanged) {
showLightIntencityNotification()
isFirstValueChanged = false
}
}
}
companion object {
var isFirstValueChanged = true
}
}
package id.diamondsleep.ui.login
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.common.api.ApiException
import id.diamondsleep.MainActivity
import id.diamondsleep.R
import id.diamondsleep.getUserViewModelFactory
import id.diamondsleep.utilities.Preferences
import kotlinx.android.synthetic.main.layout_login.*
class LoginActivity : AppCompatActivity() {
private val viewModel: LoginViewModel by viewModels {
getUserViewModelFactory()
}
private lateinit var googleSignClient: GoogleSignInClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.layout_login)
btn_sign_in_google.setOnClickListener {
viewModel.showLoading(true)
signIn()
}
}
public override fun onStart() {
super.onStart()
setObserverToViewModel()
}
private fun setObserverToViewModel() {
viewModel.apply {
gso.observe(this@LoginActivity, Observer {
googleSignClient = GoogleSignIn.getClient(this@LoginActivity, it)
})
loading.observe(this@LoginActivity, Observer {
setLoadingView(it)
})
}
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
val account = task.getResult(ApiException::class.java)
viewModel.login(account!!)
saveLogin()
moveToMainActivity()
finish()
} catch (e: Exception) {
Toast.makeText(this, getString(R.string.check_internet_connection), Toast.LENGTH_SHORT).show()
e.printStackTrace()
}
}
viewModel.showLoading(false)
}
private fun signIn() {
val signInIntent = googleSignClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
private fun saveLogin() {
Preferences(this).setLogin(true)
}
private fun moveToMainActivity() {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
private fun setLoadingView(statusLoading: Boolean) {
if (statusLoading) {
please_wait.visibility = View.VISIBLE
login_loading.visibility = View.VISIBLE
} else {
please_wait.visibility = View.GONE
login_loading.visibility = View.GONE
}
}
companion object {
private const val RC_SIGN_IN = 7
}
}
package id.diamondsleep.ui.login
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import id.diamondsleep.data.source.datauser.UserDataContract
import id.diamondsleep.model.User
import kotlinx.coroutines.launch
class LoginViewModel internal constructor(val userRepository: UserDataContract) : ViewModel() {
private val _gso = MutableLiveData<GoogleSignInOptions>()
val gso: LiveData<GoogleSignInOptions> = _gso
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading
init {
_loading.value = false
_gso.value = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build()
}
fun login(googleSignInAccount: GoogleSignInAccount) {
_loading.value = true
viewModelScope.launch {
userRepository.getUser(googleSignInAccount.email!!, googleSignInAccount.displayName!!)
userRepository.saveUser(User(googleSignInAccount.email!!, googleSignInAccount.displayName!!))
}
_loading.value = false
}
fun showLoading(statusLoading: Boolean) {
_loading.value = statusLoading
}
//for testing purpose
fun loginTest(email: String, displayName: String) {
_loading.value = true
viewModelScope.launch {
userRepository.saveUser(User(email, displayName))
}
_loading.value = false
}
}
package id.diamondsleep
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.navigation.NavigationView
import com.spotify.sdk.android.authentication.AuthenticationClient
import com.spotify.sdk.android.authentication.AuthenticationRequest
import com.spotify.sdk.android.authentication.AuthenticationResponse
import id.diamondsleep.ui.login.LoginActivity
import id.diamondsleep.utilities.ConstantValue.REQUEST_CONNECT_SPOTIFY
import id.diamondsleep.utilities.Preferences
import kotlinx.android.synthetic.main.app_bar_main.*
import timber.log.Timber
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var navView: NavigationView
lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
loginCheckIn()
navView = findViewById(R.id.nav_view)
drawerLayout = findViewById(R.id.drawer_layout)
setNavigationController()
spotifyAuthorization()
}
private fun spotifyAuthorization() {
if (Preferences(this).getTokenSpotify() == "") {
val builder = AuthenticationRequest.Builder(BuildConfig.SPOTIFY_CLIENT_ID, AuthenticationResponse.Type.TOKEN, BuildConfig.SPOTIFY_REDIRECT_URI)
builder.setScopes(arrayOf("streaming"))
sendToActivityResultForConnectSpotify(builder)
}
}
private fun sendToActivityResultForConnectSpotify(builder: AuthenticationRequest.Builder) {
val request = builder.build()
AuthenticationClient.openLoginActivity(this, REQUEST_CONNECT_SPOTIFY, request)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
private fun setNavigationController() {
val navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_relaxation, R.id.nav_environment_conditions,
R.id.nav_hitung_kualitastidur, R.id.nav_datatidur, R.id.nav_setting,
R.id.nav_about_app, R.id.nav_logout
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
private fun loginCheckIn() {
if (!Preferences(this).isLogin()) {
moveToLoginActivity()
}
}
private fun moveToLoginActivity() {
startActivity(Intent(this, LoginActivity::class.java))
finish()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CONNECT_SPOTIFY) {
onConnectingSpotify(resultCode, data)
}
}
private fun onConnectingSpotify(resultCode: Int, data: Intent?) {
val response = AuthenticationClient.getResponse(resultCode, data)
when (response.type) {
AuthenticationResponse.Type.TOKEN -> {
Preferences(this).saveTokenSpotify(response.accessToken)
}
AuthenticationResponse.Type.ERROR -> {
Timber.d("erroreuy: "+response.error)
Toast.makeText(this, response.error, Toast.LENGTH_SHORT).show()
}
else -> {
}
}
}
}
package id.diamondsleep.ui.home.tips
import id.diamondsleep.model.CategoryTips
import id.diamondsleep.model.Tip
object MapToCategoryTips {
fun convert(tips: List<Tip>): List<CategoryTips> {
val categoryTips = mutableListOf<CategoryTips>()
val tipsByCategory = tips.groupBy { it.category }
for (value in tipsByCategory.values) {
val categoryName = value[0].category.replace("_", " ")
categoryTips.add(CategoryTips(categoryName, value))
}
return categoryTips
}
}
package id.diamondsleep.utilities.backgroundservice
import android.app.Service
import android.content.Intent
import android.os.IBinder
import id.diamondsleep.R
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.utilities.NoiseDetection
import id.diamondsleep.utilities.SleepyNotification
import java.util.*
import kotlin.math.roundToInt
class NoiseService : Service() {
private var noiseDetection: NoiseDetection? = null
private var soundLevelValueSum = 0
private val soundLevelTolerance = 80
private val fiveMinutes = 60 * 5
private var incrementMillisecond = 0
override fun onCreate() {
super.onCreate()
noiseDetection = NoiseDetection()
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent!!.getBooleanExtra(ConstantValue.DEACTIVE_SERVICE, false)) {
stopSelf()
}
noiseDetection = NoiseDetection()
noiseDetection!!.start()
Timer().scheduleAtFixedRate(object : TimerTask() {
override fun run() {
++incrementMillisecond
if (incrementMillisecond == 10 && isFirstValueChanged) {
showSoundLevelDisturbingNotification()
isFirstValueChanged = false
}
if (!noiseDetection!!.amplitude.isNaN()){
soundLevelValueSum += noiseDetection!!.amplitude.roundToInt()
}
showNotificationIfSoundDistrubing()
}
}, 0, 1000)
return START_NOT_STICKY
}
private fun showNotificationIfSoundDistrubing() {
if (incrementMillisecond == fiveMinutes) {
incrementMillisecond = 0
val meanSoundValue = soundLevelValueSum / fiveMinutes
if (meanSoundValue > soundLevelTolerance) {
showSoundLevelDisturbingNotification()
}
}
}
private fun showSoundLevelDisturbingNotification() {
val notification = SleepyNotification(this@NoiseService)
notification.apply {
// title = "Noise Level ${noiseDetection!!.amplitude.roundToInt()} dB"
title = "Noise Level 33 dB"
message = getString(R.string.message_for_turnoff_sound_disturbing)
showNotification()
}
}
override fun onDestroy() {
super.onDestroy()
noiseDetection!!.stop()
}
companion object {
var isFirstValueChanged = true
}
}
package id.diamondsleep.ui.sleepqualitycalculator
import android.os.Bundle
import android.view.View
interface QuestionsView {
fun setContentView(view: View)
fun moveToNext(view: View)
fun moveToBack(view: View)
fun answeredQuestions(view: View): Bundle
}
package id.diamondsleep.data.remoteapi
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import id.diamondsleep.BuildConfig
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitFactory {
private val mLoggingInterceptor = HttpLoggingInterceptor()
private val client: OkHttpClient =
OkHttpClient.Builder().addInterceptor(mLoggingInterceptor).build()
init {
mLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
}
private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
val USER_API: UserApi = retrofit.create(UserApi::class.java)
val TIPS_API: TipsApi = retrofit.create(TipsApi::class.java)
val ARTICLE_API: ArticleApi = retrofit.create(ArticleApi::class.java)
val SLEEP_QUALITY_CALCULATOR_API: SleepQualityCalculatorApi = retrofit.create(SleepQualityCalculatorApi::class.java)
val SLEEP_HISTORY: SleepHistoryApi = retrofit.create(SleepHistoryApi::class.java)
}
package id.diamondsleep.ui.sleepqualitycalculator
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import id.diamondsleep.R
import id.diamondsleep.getSleepQualityViewModelFactory
import id.diamondsleep.utilities.psqiutil.PSQIQualityCalculator
import id.diamondsleep.model.PSQISleepQuality
import id.diamondsleep.ui.home.tips.tipsmore.AllTipsActivity
import id.diamondsleep.utilities.DateUtilities
import id.diamondsleep.utilities.CategoryTipsValue
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.model.psqiquestions.PSQIQualityQuestions
import kotlinx.android.synthetic.main.layout_psqi_result.view.*
class SleepQualityCalculationScoreFragment : Fragment() {
private val viewModel: SleepQualityCalculatorViewModel by viewModels {
getSleepQualityViewModelFactory()
}
private var sleepSubjectiveScore = 0
private var sleepLatencyScore = 0
private var sleepDurationScore = 0
private var sleepEfficiencyScore = 0
private var sleepDisturbingScore = 0
private var medicamentUsingScore = 0
private var daytimeDysfunctionScore = 0
private var psqiScore = 0
private lateinit var psqiSLeepQuality: PSQIQualityQuestions
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.layout_psqi_result, container, false)
psqiSLeepQuality = getAnsweredQuestionsBefore()
setupScore()
setupScoreView(view)
saveScoreToServer()
view.sleep_quality_scoring_button.setOnClickListener {
val intent = Intent(requireActivity(), AllTipsActivity::class.java)
intent.putExtra(AllTipsActivity.CATEGORY_KEY, CategoryTipsValue.getCategoryIndex(""))
startActivity(intent)
}
return view
}
private fun setupScore() {
val psqiCalculator = PSQIQualityCalculator(psqiSLeepQuality)
psqiCalculator.apply {
sleepSubjectiveScore = sleepSubjectiveScore()
sleepLatencyScore = sleepLatencyScore()
sleepDurationScore = sleepDurationScore()
sleepEfficiencyScore = sleepEfficiencyScore()
sleepDisturbingScore = sleepDisturbingScore()
medicamentUsingScore = medicamentUsingScore()
daytimeDysfunctionScore = daytimeDysfunctionScore()
psqiScore = psqiSleepQualityScore()
}
}
private fun saveScoreToServer() {
val psqiSleepQuality = PSQISleepQuality(
0,
"",
sleepSubjectiveScore,
sleepDurationScore,
sleepLatencyScore,
sleepEfficiencyScore,
sleepDisturbingScore,
medicamentUsingScore,
daytimeDysfunctionScore,
DateUtilities.getCurrentDate()
)
viewModel.saveSleepQuality(psqiSleepQuality)
}
private fun setupScoreView(view: View) {
view.apply {
sleepquality_count_subjective_score.text = sleepSubjectiveScore.toString()
sleepquality_count_latency_score.text = sleepLatencyScore.toString()
sleepquality_count_duration_score.text = sleepDurationScore.toString()
sleepquality_count_efficiency_score.text = sleepEfficiencyScore.toString()
sleepquality_count_disturb_score.text = sleepDisturbingScore.toString()
sleepquality_count_medicament_score.text = medicamentUsingScore.toString()
sleepquality_count_dysfunction_score.text = daytimeDysfunctionScore.toString()
sleep_quality_score.text = psqiScore.toString()
sleep_quality_result.text = resultSleepQuality(psqiScore)
}
}
private fun resultSleepQuality(sleepQualityScore: Int): String {
return if (sleepQualityScore <= 5) {
requireContext().getString(R.string.the_conclusion_is_good_sleep_quality)
} else {
requireContext().getString(R.string.the_conclusion_is_poor_sleep_quality)
}
}
private fun getAnsweredQuestionsBefore(): PSQIQualityQuestions {
return arguments?.getParcelable(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY)!!
}
}
package id.diamondsleep.ui.sleepqualitycalculator
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import id.diamondsleep.R
import id.diamondsleep.model.PSQISleepQuality
import id.diamondsleep.utilities.DateConverter
import kotlinx.android.synthetic.main.card_sleepqualitycount.view.*
class SleepQualityCalculatorAdapter : RecyclerView.Adapter<SleepQualityCalculatorAdapter.ViewHolder>() {
private val psqiSleepQualities = mutableListOf<PSQISleepQuality>()
fun updateSleepQualityCountAdapter(sleepQualities: List<PSQISleepQuality>) {
this.psqiSleepQualities.clear()
this.psqiSleepQualities.addAll(sleepQualities)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.card_sleepqualitycount, parent, false)
)
}
override fun getItemCount(): Int {
return psqiSleepQualities.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItem(psqiSleepQualities[position])
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val date = itemView.sleepqualitycount_date
private val score = itemView.sleepqualitycount_score
private val iconIndicator = itemView.sleepqualitycount_icon_indicator
private val sleepQualityResult = itemView.sleepqualitycount_sleepquality_result
fun bindItem(psqiSleepQuality: PSQISleepQuality) {
val psqiScore = psqiSleepScore(psqiSleepQuality)
date.text = DateConverter.convertDateToStringWithoutTime(psqiSleepQuality.date)
score.text = psqiScore.toString()
if (psqiScore > 5) {
Glide.with(itemView.context).load(R.mipmap.ic_smile_black).into(iconIndicator)
sleepQualityResult.text = itemView.context.getString(R.string.good)
} else {
Glide.with(itemView.context).load(R.mipmap.ic_sad_black).into(iconIndicator)
sleepQualityResult.text = itemView.context.getString(R.string.not_good)
}
}
fun psqiSleepScore(psqiSleepQuality: PSQISleepQuality): Int {
psqiSleepQuality.apply {
return sleepSubjective + sleepLatency + sleepDuration + sleepHabitsEfficiency + sleepDisturbance + medicamentUse + daytimeDysfunction
}
}
}
}
package id.diamondsleep.ui.sleepqualitycalculator
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.navigation.findNavController
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import id.diamondsleep.MainActivity
import id.diamondsleep.R
import id.diamondsleep.getSleepQualityViewModelFactory
import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.layout_sleep_quality_count.*
import kotlinx.android.synthetic.main.layout_sleep_quality_count.view.*
class SleepQualityCalculatorFragment : Fragment() {
private val sleepQualityViewModel: SleepQualityCalculatorViewModel by viewModels {
getSleepQualityViewModelFactory()
}
private lateinit var adapter: SleepQualityCalculatorAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.layout_sleep_quality_count, container, false)
(requireActivity() as MainActivity).toolbar_point.text = getText(R.string.nav_item_sleepqualitycount)
adapter = SleepQualityCalculatorAdapter()
setSleepQualityHistoryRecyclerView(view)
view.sleepqualitycount_btn_startcounting.setOnClickListener {
it.findNavController().navigate(R.id.action_nav_hitung_kualitastidur_to_sleepQualityCountQuestionZero)
}
return view
}
override fun onStart() {
super.onStart()
setObserverToViewModel()
}
private fun setObserverToViewModel() {
sleepQualityViewModel.apply {
psqiSleepQualities.observe(viewLifecycleOwner, Observer {
if (it.isNotEmpty()) {
adapter.updateSleepQualityCountAdapter(it)
} else {
sleepqualitycount_nohistory.visibility = View.VISIBLE
}
})
loading.observe(viewLifecycleOwner, Observer {
loadingState(it)
})
}
}
private fun setSleepQualityHistoryRecyclerView(view: View) {
view.recyclerview_sleepquality_history.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = this@SleepQualityCalculatorFragment.adapter
itemAnimator = DefaultItemAnimator()
}
}
private fun loadingState(statusLoading: Boolean) {
if (statusLoading) {
sleepqualitycount_proggressbar.visibility = View.VISIBLE
} else {
sleepqualitycount_proggressbar.visibility = View.GONE
}
}
}
package id.diamondsleep.ui.sleepqualitycalculator.questions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController
import id.diamondsleep.R
import id.diamondsleep.ui.sleepqualitycalculator.QuestionsView
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.model.psqiquestions.DailyLife
import id.diamondsleep.model.psqiquestions.PSQIQualityQuestions
import kotlinx.android.synthetic.main.layout_sleepquality_questions.view.*
import kotlinx.android.synthetic.main.sleepquality_question_four.view.*
class SleepQualityCountQuestionFourFragment : Fragment(), QuestionsView {
private lateinit var psqiSLeepQuality: PSQIQualityQuestions
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.layout_sleepquality_questions, container, false)
setContentView(view)
setAnswerQuestions(view)
psqiSLeepQuality = getAnsweredQuestionsBefore()
view.sleepqualitycount_question_next_btn.setOnClickListener {
moveToNext(view)
}
return view
}
override fun answeredQuestions(view: View): Bundle {
val dailyLife = DailyLife()
dailyLife.apply {
sleepQualityToLifeAnswer = view.sleepqualitycount_question_about_sleepquality_tolife_answer.selectedItemPosition
affectSleepQualityAnswer = view.sleepqualitycount_question_about_sleepquality_towork_answer.selectedItemPosition
}
psqiSLeepQuality.dailyLife = dailyLife
return bundleOf(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY to psqiSLeepQuality)
}
private fun setAnswerQuestions(view: View) {
ArrayAdapter.createFromResource(
requireContext(),
R.array.sleep_quality_common_answer,
android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
view.sleepqualitycount_question_about_sleepquality_tolife_answer.adapter = adapter
view.sleepqualitycount_question_about_sleepquality_towork_answer.adapter = adapter
}
}
private fun getAnsweredQuestionsBefore(): PSQIQualityQuestions {
return arguments?.getParcelable(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY)!!
}
override fun setContentView(view: View) {
view.sleepqualitycount_question_questiontext.visibility = View.GONE
view.sleepqualitycount_question_viewstub.apply {
this.layoutResource = R.layout.sleepquality_question_four
this.inflate()
}
view.sleepqualitycount_question_proggresspageindicator.progress = 100
view.sleepqualitycount_question_current_page.text = 5.toString()
view.sleepqualitycount_question_questiontext.text = requireContext().getText(R.string.sleep_quality_count_question_about_sleep_disorders)
view.sleepqualitycount_question_explanation.text = requireContext().getText(R.string.sleep_quality_count_question_sleep_disoders_explanation)
}
override fun moveToNext(view: View) {
view.findNavController().navigate(R.id.action_sleepQualityCountQuestionFourFragment_to_sleepQualityCountScoreSleepQualityFragment,
answeredQuestions(view))
}
override fun moveToBack(view: View) {
}
}
package id.diamondsleep.ui.sleepqualitycalculator.questions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RadioButton
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController
import id.diamondsleep.R
import id.diamondsleep.ui.sleepqualitycalculator.QuestionsView
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.model.psqiquestions.PSQIQualityQuestions
import kotlinx.android.synthetic.main.layout_sleepquality_questions.view.*
import kotlinx.android.synthetic.main.sleepquality_question_one.view.*
class SleepQualityCountQuestionOneFragment : Fragment(), QuestionsView {
private lateinit var psqiSLeepQuality: PSQIQualityQuestions
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.layout_sleepquality_questions, container, false)
setContentView(view)
psqiSLeepQuality = getAnsweredQuestionsBefore()
view.sleepqualitycount_question_next_btn.setOnClickListener {
moveToNext(view)
}
return view
}
private fun getAnsweredQuestionsBefore(): PSQIQualityQuestions {
return arguments?.getParcelable(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY)!!
}
override fun moveToNext(view: View) {
view.findNavController().navigate(R.id.action_sleepQualityCountQuestionOneFragment_to_sleepQualityCountQuestionTwoFragment,
answeredQuestions(view))
}
override fun moveToBack(view: View) {
}
private fun selectedAnswer(view: View): Int {
view.radioGroupLastSleepQuality.apply {
val selectedAnswerId = this.checkedRadioButtonId
val selectedButton = this.findViewById<RadioButton>(selectedAnswerId)
return indexOfChild(selectedButton)
}
}
override fun answeredQuestions(view: View): Bundle {
psqiSLeepQuality.lastSleepQualityAnswer = selectedAnswer(view)
return bundleOf(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY to psqiSLeepQuality)
}
override fun setContentView(view: View) {
view.sleepqualitycount_question_viewstub.apply {
this.layoutResource = R.layout.sleepquality_question_one
this.inflate()
}
view.sleepqualitycount_question_proggresspageindicator.progress = 40
view.sleepqualitycount_question_current_page.text = 2.toString()
view.sleepqualitycount_question_explanation.text = requireContext().getText(R.string.sleep_quality_count_question_how_good_quality_of_sleep_explanation)
view.sleepqualitycount_question_questiontext.text = requireContext().getText(R.string.sleep_quality_count_question_how_good_quality_of_sleep)
}
}
package id.diamondsleep.ui.sleepqualitycalculator.questions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController
import id.diamondsleep.R
import id.diamondsleep.ui.sleepqualitycalculator.QuestionsView
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.model.psqiquestions.PSQIQualityQuestions
import kotlinx.android.synthetic.main.layout_sleepquality_questions.view.*
import kotlinx.android.synthetic.main.sleepquality_question_three.view.*
class SleepQualityCountQuestionThreeFragment : Fragment(), QuestionsView {
private lateinit var psqiSLeepQuality: PSQIQualityQuestions
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.layout_sleepquality_questions, container, false)
setContentView(view)
setAnswerQuestions(view)
psqiSLeepQuality = getAnsweredQuestionsBefore()
view.sleepqualitycount_question_next_btn.setOnClickListener {
moveToNext(view)
}
return view
}
private fun getAnsweredQuestionsBefore(): PSQIQualityQuestions {
return arguments?.getParcelable(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY)!!
}
override fun setContentView(view: View) {
view.sleepqualitycount_question_viewstub.apply {
this.layoutResource = R.layout.sleepquality_question_three
this.inflate()
}
view.sleepqualitycount_question_proggresspageindicator.progress = 80
view.sleepqualitycount_question_current_page.text = 4.toString()
view.sleepqualitycount_question_questiontext.text = requireContext().getText(R.string.question_used_medicine)
view.sleepqualitycount_question_explanation.text = requireContext().getText(R.string.sleep_quality_count_question_sleep_disoders_explanation)
}
override fun moveToNext(view: View) {
view.findNavController().navigate(R.id.action_sleepQualityCountQuestionThreeFragment_to_sleepQualityCountQuestionFourFragment,
answeredQuestions(view))
}
override fun moveToBack(view: View) {
}
override fun answeredQuestions(view: View): Bundle {
psqiSLeepQuality.usingMedicament = view.sleepqualitycount_question_medicament_answer.selectedItemPosition
return bundleOf(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY to psqiSLeepQuality)
}
private fun setAnswerQuestions(view: View) {
ArrayAdapter.createFromResource(
requireContext(),
R.array.medicament_use_answer,
android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
view.sleepqualitycount_question_medicament_answer.adapter = adapter
}
}
}
package id.diamondsleep.ui.sleepqualitycalculator.questions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController
import id.diamondsleep.R
import id.diamondsleep.ui.sleepqualitycalculator.QuestionsView
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.model.psqiquestions.PSQIQualityQuestions
import id.diamondsleep.model.psqiquestions.SleepDisorders
import kotlinx.android.synthetic.main.layout_sleepquality_questions.view.*
import kotlinx.android.synthetic.main.sleepquality_question_two.view.*
/**
* A simple [Fragment] subclass.
*/
class SleepQualityCountQuestionTwoFragment : Fragment(), QuestionsView {
private lateinit var psqiSLeepQuality: PSQIQualityQuestions
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.layout_sleepquality_questions, container, false)
setContentView(view)
setAnswerQuestions(view)
psqiSLeepQuality = getAnsweredQuestionsBefore()
view.sleepqualitycount_question_next_btn.setOnClickListener {
moveToNext(view)
}
return view
}
override fun moveToNext(view: View) {
view.findNavController().navigate(R.id.action_sleepQualityCountQuestionTwoFragment_to_sleepQualityCountQuestionThreeFragment,
answeredQuestions(view))
}
override fun moveToBack(view: View) {
}
private fun getAnsweredQuestionsBefore(): PSQIQualityQuestions {
return arguments?.getParcelable(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY)!!
}
override fun answeredQuestions(view: View): Bundle {
val sleepDisorders = SleepDisorders()
// create sleep disorders
sleepDisorders.apply {
cantSleepIn30MinutesAnswer = view.sleepqualitycount_question_cant_sleep_30minutes_answer.selectedItemPosition
wakeupMidnightAnswer = view.sleepqualitycount_question_wakeup_midnight_answer.selectedItemPosition
wakeupForBathroomAnswer = view.sleepqualitycount_question_wakeup_bathroom_answer.selectedItemPosition
cantBreatheBetterAnswer = view.sleepqualitycount_question_cant_breathe_better_answer.selectedItemPosition
coughSnoreAnsweer = view.sleepqualitycount_question_cough_snore_answer.selectedItemPosition
}
// sleep disoders to psqiSleepQuality
psqiSLeepQuality.sleepDisorders = sleepDisorders
return bundleOf(ConstantValue.DATA_QUESTIONS_SLEEP_QUALITY to psqiSLeepQuality)
}
override fun setContentView(view: View) {
view.sleepqualitycount_question_viewstub.apply {
this.layoutResource = R.layout.sleepquality_question_two
this.inflate()
}
view.sleepqualitycount_question_proggresspageindicator.progress = 60
view.sleepqualitycount_question_current_page.text = 3.toString()
view.sleepqualitycount_question_questiontext.text = requireContext().getText(R.string.sleep_quality_count_question_about_sleep_disorders)
view.sleepqualitycount_question_explanation.text = requireContext().getText(R.string.sleep_quality_count_question_sleep_disoders_explanation)
}
private fun setAnswerQuestions(view: View) {
ArrayAdapter.createFromResource(
requireContext(),
R.array.time_disorders_sleep_answer,
android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
view.sleepqualitycount_question_cant_sleep_30minutes_answer.adapter = adapter
view.sleepqualitycount_question_cant_breathe_better_answer.adapter = adapter
view.sleepqualitycount_question_cough_snore_answer.adapter = adapter
view.sleepqualitycount_question_wakeup_bathroom_answer.adapter = adapter
view.sleepqualitycount_question_wakeup_midnight_answer.adapter = adapter
}
}
}
package id.diamondsleep.data
import androidx.room.Database
import androidx.room.RoomDatabase
import id.diamondsleep.data.source.dataarticle.articlelocal.ArticleDao
import id.diamondsleep.data.source.dataarticle.articlelocal.ArticleLocal
import id.diamondsleep.data.source.datapsqisleepquality.psqisleepqualitylocal.PSQISleepQualityDao
import id.diamondsleep.data.source.datapsqisleepquality.psqisleepqualitylocal.PSQISleepQualityLocal
import id.diamondsleep.data.source.datasleephistory.sleephistorylocal.SleepHistoryDao
import id.diamondsleep.data.source.datasleephistory.sleephistorylocal.SleepHistoryLocal
import id.diamondsleep.data.source.datatips.tipslocal.TipsDao
import id.diamondsleep.data.source.datatips.tipslocal.TipLocal
import id.diamondsleep.data.source.datauser.local.UserDao
import id.diamondsleep.data.source.datauser.local.UserLocal
@Database(
entities = [UserLocal::class, TipLocal::class, ArticleLocal::class, PSQISleepQualityLocal::class, SleepHistoryLocal::class],
version = 2,
exportSchema = true
)
abstract class SleepyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun tipsDao(): TipsDao
abstract fun articelDao(): ArticleDao
abstract fun psqiSleepQualityDao(): PSQISleepQualityDao
abstract fun sleepHistoryDao(): SleepHistoryDao
}
package id.diamondsleep.ui.home.tips
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import id.diamondsleep.R
import id.diamondsleep.model.Tip
import id.diamondsleep.utilities.OnCardClickListener
import id.diamondsleep.utilities.helper.StringToDateConverter
import kotlinx.android.synthetic.main.card_tips.view.*
class TipsCardAdapter(
private var categoryTips: MutableList<Tip> = mutableListOf(),
private val cardClickListener: OnCardClickListener<Tip>
) : RecyclerView.Adapter<TipsCardAdapter.ViewHolder>() {
fun update(tips: List<Tip>) {
categoryTips.clear()
categoryTips.addAll(tips)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.card_tips, parent, false))
}
override fun getItemCount(): Int = categoryTips.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItem(categoryTips[position], cardClickListener)
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val thumbnailImage = itemView.tips_child_thumbnail
private val title = itemView.tips_child_title
private val author = itemView.tips_child_author
private val date = itemView.tips_child_date
fun bindItem(tip: Tip, listener: OnCardClickListener<Tip>) {
Glide.with(itemView).load(tip.imageUrl).apply(RequestOptions.bitmapTransform(RoundedCorners(24))).into(thumbnailImage)
title.text = tip.title
author.text = tip.author
date.text = StringToDateConverter.changeFormatDate(tip.date)
itemView.setOnClickListener {
listener.onClicked(tip)
}
}
}
}
package id.diamondsleep.ui.home.tips
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.viewpager.widget.PagerAdapter
import com.bumptech.glide.Glide
import com.google.gson.Gson
import id.diamondsleep.R
import id.diamondsleep.model.Tip
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.utilities.OnCardClickListener
class TipsCarouselAdapter(
private val context: Context,
private val onCardClickListener: OnCardClickListener<Tip>
) : PagerAdapter() {
private val mTips: MutableList<Tip> = mutableListOf()
fun update(tips: List<Tip>) {
mTips.clear()
mTips.addAll(tips)
notifyDataSetChanged()
}
private val inflater: LayoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
override fun getCount(): Int {
return mTips.size
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val itemView = inflater.inflate(R.layout.adapter_tips_main_view_pager, container, false)
val tipsTitle: TextView = itemView.findViewById(R.id.tips_top_title)
val tipsCategory: TextView = itemView.findViewById(R.id.tips_top_kategori)
val tipsThumbnail: ImageView = itemView.findViewById(R.id.tips_top_pic)
val tipsMore: TextView = itemView.findViewById(R.id.tips_top_more)
Glide.with(context).load(mTips[position].imageUrl).into(tipsThumbnail)
tipsCategory.text = mTips[position].category.replace("_"," ")
tipsTitle.text = mTips[position].title
tipsMore.setOnClickListener {
onCardClickListener.onClicked(mTips[position])
}
container.addView(itemView)
return itemView
}
override fun isViewFromObject(view: View, `object`: Any): Boolean {
return view === `object`
}
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
val view = `object` as View
container.removeView(view)
}
}
package id.diamondsleep.ui.home.tips
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import id.diamondsleep.R
import id.diamondsleep.model.CategoryTips
import id.diamondsleep.model.Tip
import id.diamondsleep.ui.home.tips.tipsmore.AllTipsActivity
import id.diamondsleep.utilities.CategoryTipsValue
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.utilities.OnCardClickListener
import kotlinx.android.synthetic.main.category_tips.view.*
class TipsCategoryAdapter(private val cardClickListener: OnCardClickListener<Tip>)
: RecyclerView.Adapter<TipsCategoryAdapter.ViewHolder>() {
private val categoryTips = mutableListOf<CategoryTips>()
private val viewPool = RecyclerView.RecycledViewPool()
private lateinit var context: Context
fun update(categoryTips: List<CategoryTips>) {
this.categoryTips.clear()
this.categoryTips.addAll(categoryTips)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
context = parent.context
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.category_tips, parent, false))
}
override fun getItemCount(): Int {
return categoryTips.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItem(categoryTips[position])
holder.recyclerviewTipsChild.apply {
categoryTips[position].apply{
adapter = TipsCardAdapter(tips.take(2).toMutableList(), cardClickListener)
}
setRecycledViewPool(viewPool)
}
holder.moreTips.setOnClickListener {
moveToAllTips(categoryTips[position].tips)
}
}
private fun moveToAllTips(tips: List<Tip>) {
val intent = Intent(context, AllTipsActivity::class.java)
intent.putParcelableArrayListExtra(ConstantValue.TIPS_KEY_VALUE, castTipsToArrayListTips(tips))
intent.putExtra(AllTipsActivity.CATEGORY_KEY, CategoryTipsValue.getCategoryIndex(tips[0].category))
context.startActivity(intent)
}
private fun castTipsToArrayListTips(tips: List<Tip>): ArrayList<Tip> {
val newTips = arrayListOf<Tip>()
newTips.addAll(tips)
return newTips
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val titleCategory = itemView.title_tips_category
val recyclerviewTipsChild: RecyclerView = itemView.recyclerview_tips_child
val moreTips: TextView = itemView.btn_loadMore
fun bindItem(categoryTip: CategoryTips) {
titleCategory.text = categoryTip.categoryName
}
}
}
package id.diamondsleep.ui.home.tips
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import id.diamondsleep.BaseViewContract
import id.diamondsleep.R
import id.diamondsleep.getTipsViewModelFactory
import id.diamondsleep.model.CategoryTips
import id.diamondsleep.model.Tip
import id.diamondsleep.utilities.ConstantValue
import id.diamondsleep.utilities.EventObserver
import id.diamondsleep.utilities.OnCardClickListener
import kotlinx.android.synthetic.main.layout_tips.*
import kotlinx.android.synthetic.main.layout_tips.view.*
class TipsFragment : Fragment(), BaseViewContract {
private lateinit var tipsCarouselAdapter: TipsCarouselAdapter
private lateinit var tipsCategoryAdapter: TipsCategoryAdapter
var currentPage = 0
private var NUM_PAGES = 3
var update: Runnable? = null
private val viewModel: TipsViewModel by viewModels {
getTipsViewModelFactory()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { // Inflate the layout for this fragment
val view = inflater.inflate(R.layout.layout_tips, container, false)
tipsCategoryAdapter = TipsCategoryAdapter(cardClickListener)
tipsCarouselAdapter = TipsCarouselAdapter(requireContext(), cardClickListener)
view.let {
setSwipeRefreshLayout(it)
setTipsRecyclerView(it)
setCarouselTips(it)
}
update = Runnable {
if (currentPage == NUM_PAGES) {
currentPage = 0
}
viewPager_tips.setCurrentItem(currentPage++, true)
}
return view
}
private fun setCarouselTips(view: View) {
view.viewPager_tips.adapter = tipsCarouselAdapter
view.viewPager_tips_indicator.setViewPager(view.viewPager_tips)
tipsCarouselAdapter.registerDataSetObserver(view.viewPager_tips_indicator.dataSetObserver)
setCarouselTipsListener(view)
}
private fun setCarouselTipsListener(view: View) {
view.viewPager_tips.addOnPageChangeListener(object : OnPageChangeListener {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
currentPage = position
}
override fun onPageScrollStateChanged(state: Int) {}
})
}
private fun setTipsRecyclerView(view: View) {
view.recyclerview_tips.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = tipsCategoryAdapter
setHasFixedSize(true)
itemAnimator = DefaultItemAnimator()
}
}
private fun setSwipeRefreshLayout(view: View) {
view.swipe_tips.apply {
isRefreshing = true
setOnRefreshListener { reloadPage() }
setColorSchemeResources(R.color.colorPrimary)
}
}
override fun onStart() {
super.onStart()
subscribeToViewModel()
}
override fun subscribeToViewModel() {
viewModel.apply {
tips.observe(viewLifecycleOwner, Observer {
if (it.isNotEmpty()) {
updateTipsView(MapToCategoryTips.convert(it))
}
})
errorMessage.observe(viewLifecycleOwner, EventObserver { errorMessage ->
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
})
loading.observe(viewLifecycleOwner, Observer {
showLoadingState(it)
})
}
}
private fun updateTipsView(categoryTips: List<CategoryTips>) {
val tips = mutableListOf<Tip>()
for (tip in categoryTips) {
tips.add(tip.tips[0])
}
tipsCategoryAdapter.update(categoryTips)
tipsCarouselAdapter.update(tips)
}
override fun showLoadingState(status: Boolean) {
swipe_tips.isRefreshing = status
}
private fun reloadPage() {
clearTips()
viewModel.getTips(0)
recyclerview_tips.visibility = View.VISIBLE
}
private fun clearTips() {
tipsCategoryAdapter.update(listOf())
tipsCarouselAdapter.update(listOf())
}
private fun moveToDetail(cardData: Tip) {
val intent = Intent(requireActivity(), DetailTipsActivity::class.java)
intent.putExtra(ConstantValue.DATA_CONTENT, cardData)
startActivity(intent)
}
private val cardClickListener = object : OnCardClickListener<Tip> {
override fun onClicked(cardData: Tip) {
moveToDetail(cardData)
}
}
}
package id.diamondsleep.ui.home.tips
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import id.diamondsleep.data.source.datatips.TipsRepository
import id.diamondsleep.data.source.datauser.UserRepository
import id.diamondsleep.model.Result
import id.diamondsleep.model.Tip
import id.diamondsleep.utilities.Event
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class TipsViewModel(
private val userRepository: UserRepository,
private val tipsRepository: TipsRepository
) : ViewModel() {
private val _tips = MutableLiveData<List<Tip>>()
val tips: LiveData<List<Tip>> = _tips
private val _errorMessage = MutableLiveData<Event<String>>()
val errorMessage: LiveData<Event<String>> = _errorMessage
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading
init {
getTips(0)
}
fun getTips(page: Int) {
viewModelScope.launch {
val resultTips = tipsRepository.getTips(page)
resultTips.collect { tipResponse ->
when (tipResponse) {
is Result.Loading -> {
setLoadingStatus(true)
}
is Result.Success -> {
_tips.value = tipResponse.data
setLoadingStatus(false)
}
is Result.Error -> {
_errorMessage.value = Event(tipResponse.exception.localizedMessage)
setLoadingStatus(false)
}
}
}
}
}
private fun setLoadingStatus(statusLoading: Boolean) {
_loading.value = statusLoading
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment