Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ dependencies {
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.firebase:firebase-analytics:17.1.0'
implementation 'org.rekotlin:rekotlin:1.0.4'
}

apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.gms.google-services'
12 changes: 12 additions & 0 deletions app/src/main/java/com/bogdan/codeforceswatcher/CwApplication.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
package com.bogdan.codeforceswatcher

import android.app.Application
import com.bogdan.codeforceswatcher.redux.AppState
import com.bogdan.codeforceswatcher.redux.appMiddleware
import com.bogdan.codeforceswatcher.redux.appReducer
import com.bogdan.codeforceswatcher.room.RoomController
import com.google.firebase.analytics.FirebaseAnalytics
import org.rekotlin.Store

val store = Store(
reducer = ::appReducer,
state = RoomController.fetchAppState(),
middleware = listOf(appMiddleware)
)

class CwApp : Application() {

Expand All @@ -10,6 +21,7 @@ class CwApp : Application() {

app = this

RoomController.onAppCreated()
FirebaseAnalytics.getInstance(this)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.bogdan.codeforceswatcher.R
import com.bogdan.codeforceswatcher.fragment.ContestsFragment
import com.bogdan.codeforceswatcher.feature.contests.ContestsFragment
import com.bogdan.codeforceswatcher.fragment.UsersFragment
import com.bogdan.codeforceswatcher.network.UserLoader
import com.bogdan.codeforceswatcher.receiver.StartAlarm
import com.bogdan.codeforceswatcher.ui.AppRateDialog
import com.bogdan.codeforceswatcher.util.Prefs
import com.bogdan.codeforceswatcher.network.UserLoader
import kotlinx.android.synthetic.main.activity_main.bottomNavigation
import kotlinx.android.synthetic.main.activity_main.fab
import kotlinx.android.synthetic.main.activity_main.llToolbar
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.bogdan.codeforceswatcher.feature.contests

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.bogdan.codeforceswatcher.R
import com.bogdan.codeforceswatcher.adapter.ContestAdapter
import com.bogdan.codeforceswatcher.feature.contests.redux.ContestsState
import com.bogdan.codeforceswatcher.feature.contests.redux.request.ContestsRequests
import com.bogdan.codeforceswatcher.store
import com.bogdan.codeforceswatcher.util.Analytics
import kotlinx.android.synthetic.main.fragment_contests.recyclerView
import kotlinx.android.synthetic.main.fragment_contests.swipeToRefresh
import org.rekotlin.StoreSubscriber

class ContestsFragment : Fragment(), SwipeRefreshLayout.OnRefreshListener,
StoreSubscriber<ContestsState> {

private val contestAdapter by lazy { ContestAdapter(listOf(), requireContext()) }

override fun onStart() {
super.onStart()
store.subscribe(this) { state -> state.select { it.contests } }
}

override fun onStop() {
super.onStop()
store.unsubscribe(this)
}

override fun newState(state: ContestsState) {
swipeToRefresh.isRefreshing = (state.status == ContestsState.Status.PENDING)
contestAdapter.setItems(state.contests)
}

override fun onRefresh() {
store.dispatch(ContestsRequests.FetchContests())
Analytics.logContestsListRefresh()
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = inflater.inflate(R.layout.fragment_contests, container, false)

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

initViews()

store.dispatch(ContestsRequests.FetchContests())
}

private fun initViews() {
swipeToRefresh.setOnRefreshListener(this)

recyclerView.adapter = contestAdapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.bogdan.codeforceswatcher.feature.contests.redux

import com.bogdan.codeforceswatcher.feature.contests.redux.request.ContestsRequests
import com.bogdan.codeforceswatcher.model.Contest
import com.bogdan.codeforceswatcher.redux.AppState
import org.rekotlin.Action

fun contestsReducer(action: Action, state: AppState): ContestsState {
var newState = state.contests

when (action) {
is ContestsRequests.FetchContests -> {
newState = newState.copy(
status = ContestsState.Status.PENDING
)
}
is ContestsRequests.FetchContests.Success -> {
newState = newState.copy(
status = ContestsState.Status.IDLE,
contests = action.contests.filter { it.phase == "BEFORE" }.sortedBy(Contest::time)
)
}
is ContestsRequests.FetchContests.Failure -> {
newState = newState.copy(
status = ContestsState.Status.IDLE
)
}
}

return newState
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.bogdan.codeforceswatcher.feature.contests.redux

import com.bogdan.codeforceswatcher.model.Contest
import org.rekotlin.StateType

data class ContestsState(
val status: Status = Status.IDLE,
val contests: List<Contest> = listOf()
) : StateType {

enum class Status { IDLE, PENDING }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.bogdan.codeforceswatcher.network.model
package com.bogdan.codeforceswatcher.feature.contests.redux.request

import com.bogdan.codeforceswatcher.model.Contest

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.bogdan.codeforceswatcher.feature.contests.redux.request

import com.bogdan.codeforceswatcher.model.Contest
import com.bogdan.codeforceswatcher.network.RestClient
import com.bogdan.codeforceswatcher.redux.Request
import com.bogdan.codeforceswatcher.store
import org.rekotlin.Action
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class ContestsRequests {

class FetchContests : Request() {

override fun execute() {
RestClient.getContests().enqueue(object : Callback<ContestResponse> {

override fun onResponse(
call: Call<ContestResponse>,
response: Response<ContestResponse>
) {
response.body()?.result?.let { contests ->
store.dispatch(Success(contests))
} ?: store.dispatch(Failure())
}

override fun onFailure(call: Call<ContestResponse>, t: Throwable) {
store.dispatch(Failure(t))
}
})
}

data class Success(val contests: List<Contest>) : Action

data class Failure(val t: Throwable? = null) : Action
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.bogdan.codeforceswatcher.room
package com.bogdan.codeforceswatcher.feature.contests.room

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
Expand All @@ -11,12 +9,12 @@ import com.bogdan.codeforceswatcher.model.Contest
@Dao
interface ContestDao {

@Query("SELECT * FROM contest WHERE phase = 'BEFORE'")
fun getUpcomingContests(): LiveData<List<Contest>>
@Query("SELECT * FROM contest")
fun getUpcomingContests(): List<Contest>

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(contests: List<Contest>)

@Delete
fun deleteAll(contests: List<Contest>)
@Query("DELETE FROM contest")
fun deleteAll()
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.bogdan.codeforceswatcher.network

import com.bogdan.codeforceswatcher.network.model.ContestResponse
import com.bogdan.codeforceswatcher.feature.contests.redux.request.ContestResponse
import com.bogdan.codeforceswatcher.network.model.RatingChangeResponse
import com.bogdan.codeforceswatcher.network.model.UserResponse
import retrofit2.Call
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.bogdan.codeforceswatcher.redux

import org.rekotlin.Middleware
import org.rekotlin.StateType

val appMiddleware: Middleware<StateType> = { _, _ ->
{ next ->
{ action ->
(action as? Request)?.execute()
next(action)
}
}
}
11 changes: 11 additions & 0 deletions app/src/main/java/com/bogdan/codeforceswatcher/redux/AppReducer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.bogdan.codeforceswatcher.redux

import com.bogdan.codeforceswatcher.feature.contests.redux.contestsReducer
import org.rekotlin.Action

fun appReducer(action: Action, state: AppState?): AppState {
requireNotNull(state)
return AppState(
contests = contestsReducer(action, state)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.bogdan.codeforceswatcher.redux

import com.bogdan.codeforceswatcher.feature.contests.redux.ContestsState
import org.rekotlin.StateType

data class AppState(
val contests: ContestsState = ContestsState()
) : StateType
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.bogdan.codeforceswatcher.redux

import org.rekotlin.Action

abstract class Request : Action {

abstract fun execute()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.bogdan.codeforceswatcher.room
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.bogdan.codeforceswatcher.feature.contests.room.ContestDao
import com.bogdan.codeforceswatcher.model.Contest
import com.bogdan.codeforceswatcher.model.User

Expand Down
Loading