diff --git a/.idea/misc.xml b/.idea/misc.xml
index af0bbdd..29bb4c5 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 6bdcee9..60f6666 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,6 +6,9 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
+
+apply plugin: 'io.gitlab.arturbosch.detekt'
+
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
@@ -29,7 +32,10 @@ android {
}
dependencies {
+
// standard
+ implementation project(':wrapper')
+ detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:1.2.2"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
@@ -58,13 +64,15 @@ dependencies {
//Card view
implementation 'androidx.cardview:cardview:1.0.0'
-
// TESTING
testImplementation 'junit:junit:4.12'
testImplementation "io.mockk:mockk:1.9.3"
testImplementation "com.squareup.okhttp3:mockwebserver:4.2.1"
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test:rules:1.2.0'
implementation "com.squareup.retrofit2:retrofit:2.6.2"
implementation "com.squareup.retrofit2:converter-gson:2.6.2"
diff --git a/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/TestHelper.kt b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/TestHelper.kt
new file mode 100644
index 0000000..017874f
--- /dev/null
+++ b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/TestHelper.kt
@@ -0,0 +1,22 @@
+package it.unisannio.ding.ids.wedroid.app
+
+import androidx.lifecycle.*
+
+class OneTimeObserver(private val handler: (T) -> Unit) : Observer, LifecycleOwner {
+ private val lifecycle = LifecycleRegistry(this)
+ init {
+ lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ }
+
+ override fun getLifecycle(): Lifecycle = lifecycle
+
+ override fun onChanged(t: T) {
+ handler(t)
+ lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+ }
+}
+
+fun LiveData.observeOnce(onChangeHandler: (T) -> Unit) {
+ val observer = OneTimeObserver(handler = onChangeHandler)
+ observe(observer, observer)
+}
diff --git a/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/data/dao/BoardDaoTest.kt b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/data/dao/BoardDaoTest.kt
new file mode 100644
index 0000000..e6151bb
--- /dev/null
+++ b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/data/dao/BoardDaoTest.kt
@@ -0,0 +1,110 @@
+package it.unisannio.ding.ids.wedroid.app.data.dao
+
+import android.content.Context
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import androidx.room.Room
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import it.unisannio.ding.ids.wedroid.app.data.database.BoardDatabase
+import it.unisannio.ding.ids.wedroid.app.data.entity.Board
+import it.unisannio.ding.ids.wedroid.app.observeOnce
+import junit.framework.TestCase.assertEquals
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.io.IOException
+
+@RunWith(AndroidJUnit4::class)
+class BoardDaoTest {
+ private lateinit var dao: BoardDao
+ private lateinit var db: BoardDatabase
+
+ @get:Rule
+ val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+ @Before
+ fun createDb() {
+ val context = ApplicationProvider.getApplicationContext()
+ db = Room.inMemoryDatabaseBuilder(
+ context, BoardDatabase::class.java
+ ).build()
+ dao = db.boardDao()
+ }
+
+ @After
+ @Throws(IOException::class)
+ fun closeDb() {
+ db.close()
+ }
+
+ @Test
+ fun emptyDatabaseOnCreation() {
+ dao.getAllBoard().observeOnce {
+ assertEquals(0, it.size)
+ }
+ }
+
+ @Test
+ fun insert() {
+ val board = Board("id", "title")
+
+ runBlocking {
+ dao.insert(board)
+ }
+
+ dao.getAllBoard().observeOnce {
+ assertEquals(1, it.size)
+ assertEquals(board, it[0])
+ }
+ }
+
+ @Test
+ fun replaceOnConflict() {
+ val board0 = Board("id", "title0")
+ val board1 = Board("id", "title1")
+
+ runBlocking {
+ dao.insert(board0)
+ dao.insert(board1)
+ }
+
+ dao.getAllBoard().observeOnce {
+ assertEquals(1, it.size)
+ assertEquals("title1", it[0].title)
+ }
+ }
+
+ @Test
+ fun getInAscendingOrder() {
+ val board0 = Board("id0", "title0")
+ val board1 = Board("id1", "title1")
+
+ runBlocking {
+ dao.insert(board1)
+ dao.insert(board0)
+ }
+
+ dao.getAllBoard().observeOnce {
+ assertEquals(2, it.size)
+ assertEquals(board0, it[0])
+ assertEquals(board1, it[1])
+ }
+ }
+
+ @Test
+ fun delete() {
+ val board = Board("id", "title")
+
+ runBlocking {
+ dao.insert(board)
+ dao.delete(board)
+ }
+
+ dao.getAllBoard().observeOnce {
+ assertEquals(0, it.size)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/BoardsListsActivityTest.kt b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/BoardsListsActivityTest.kt
new file mode 100644
index 0000000..6fe7e0a
--- /dev/null
+++ b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/BoardsListsActivityTest.kt
@@ -0,0 +1,52 @@
+package it.unisannio.ding.ids.wedroid.app.view
+
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.swipeDown
+import androidx.test.espresso.action.ViewActions.swipeLeft
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.contrib.RecyclerViewActions
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.ActivityTestRule
+import it.unisannio.ding.ids.wedroid.app.R
+import it.unisannio.ding.ids.wedroid.app.view.adapter.BoardsListAdapter
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class BoardsListsActivityTest {
+
+ @get:Rule
+ val activityRule = ActivityTestRule(BoardsListsActivity::class.java)
+
+ fun swipeLeftToDelete() {
+ onView(withId(R.id.boardList))
+ .perform(
+ RecyclerViewActions.actionOnItemAtPosition(
+ 0, swipeLeft()
+ )
+ )
+ }
+
+ fun pullToRefresh() {
+ onView(withId(R.id.pullToRefresh))
+ .perform(swipeDown())
+
+ }
+
+ @Test
+ fun openNewBoardActivity() {
+ onView(withId(R.id.fab))
+ .perform(click())
+
+ onView(withId(R.id.newBoardName))
+ .check(matches(isDisplayed()))
+ }
+
+}
+
diff --git a/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/LoginActivityTest.kt b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/LoginActivityTest.kt
new file mode 100644
index 0000000..62af7b7
--- /dev/null
+++ b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/LoginActivityTest.kt
@@ -0,0 +1,87 @@
+package it.unisannio.ding.ids.wedroid.app.view
+
+import androidx.test.espresso.Espresso.closeSoftKeyboard
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.typeText
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.RootMatchers.withDecorView
+import androidx.test.espresso.matcher.ViewMatchers.*
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.ActivityTestRule
+import it.unisannio.ding.ids.wedroid.app.R
+import org.hamcrest.CoreMatchers.not
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class LoginActivityTest {
+ @get:Rule
+ val activityRule = ActivityTestRule(LoginActivity::class.java)
+
+ @Test
+ fun loginWithEmptyUrl() {
+ onView(withId(R.id.username))
+ .perform(typeText("username"))
+ onView(withId(R.id.password))
+ .perform(typeText("password"))
+ closeSoftKeyboard()
+ onView(withId(R.id.button))
+ .perform(click())
+
+ onView(withText(R.string.login_empty_field))
+ .inRoot(withDecorView(not(activityRule.activity.window.decorView)))
+ .check(matches(isDisplayed()))
+ }
+
+ @Test
+ fun loginWithEmptyUsername() {
+ onView(withId(R.id.instanceServer))
+ .perform(typeText("https://wekan.com"))
+ onView(withId(R.id.password))
+ .perform(typeText("password"))
+ closeSoftKeyboard()
+ onView(withId(R.id.button))
+ .perform(click())
+
+ onView(withText(R.string.login_empty_field))
+ .inRoot(withDecorView(not(activityRule.activity.window.decorView)))
+ .check(matches(isDisplayed()))
+
+ }
+
+ @Test
+ fun loginWithEmptyPassword() {
+ onView(withId(R.id.instanceServer))
+ .perform(typeText("https://wekan.com"))
+ onView(withId(R.id.username))
+ .perform(typeText("username"))
+ closeSoftKeyboard()
+ onView(withId(R.id.button))
+ .perform(click())
+
+ onView(withText(R.string.login_empty_field))
+ .inRoot(withDecorView(not(activityRule.activity.window.decorView)))
+ .check(matches(isDisplayed()))
+ }
+
+ @Test
+ fun loginWithUnformedInstance(){
+ onView(withId(R.id.instanceServer))
+ .perform(typeText("not an URL"))
+ onView(withId(R.id.username))
+ .perform(typeText("username"))
+ onView(withId(R.id.password))
+ .perform(typeText("password"))
+ closeSoftKeyboard()
+ onView(withId(R.id.button))
+ .perform(click())
+
+ onView(withText(R.string.login_unformed_instance))
+ .inRoot(withDecorView(not(activityRule.activity.window.decorView)))
+ .check(matches(isDisplayed()))
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/NewBoardActivityTest.kt b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/NewBoardActivityTest.kt
new file mode 100644
index 0000000..4f49761
--- /dev/null
+++ b/app/src/androidTest/java/it/unisannio/ding/ids/wedroid/app/view/NewBoardActivityTest.kt
@@ -0,0 +1,37 @@
+package it.unisannio.ding.ids.wedroid.app.view
+
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.RootMatchers.withDecorView
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.ActivityTestRule
+import it.unisannio.ding.ids.wedroid.app.R
+import org.hamcrest.core.IsNot.not
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class NewBoardActivityTest {
+
+ @get:Rule
+ val activityRule = ActivityTestRule(NewBoardActivity::class.java)
+
+ @Test
+ fun showToastOnEmptyName() {
+ onView(withId(R.id.newBoardDone))
+ .perform(click())
+
+ onView(withText(R.string.on_add_new_board_empty_name))
+ .inRoot(withDecorView(not(activityRule.activity.window.decorView)))
+ .check(matches(isDisplayed()))
+ }
+
+}
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8247651..b41ddfe 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,14 +11,26 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
+
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
-
+
+
+
+
+
+
+
>
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insert(board: Board)
+
+ @Delete
+ suspend fun delete(board: Board)
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/database/BoardDatabase.java b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/database/BoardDatabase.java
new file mode 100644
index 0000000..07181ba
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/database/BoardDatabase.java
@@ -0,0 +1,30 @@
+package it.unisannio.ding.ids.wedroid.app.data.database;
+
+import android.content.Context;
+
+import androidx.room.Database;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+
+import it.unisannio.ding.ids.wedroid.app.data.dao.BoardDao;
+import it.unisannio.ding.ids.wedroid.app.data.entity.Board;
+
+@Database(entities = Board.class, version = 1, exportSchema = false)
+public abstract class BoardDatabase extends RoomDatabase {
+ private static volatile BoardDatabase INSTANCE;
+ public abstract BoardDao boardDao();
+
+ public static BoardDatabase getDatabase(Context context) {
+ if (INSTANCE != null)
+ return INSTANCE;
+ synchronized (BoardDatabase.class) {
+ INSTANCE = Room.databaseBuilder(
+ context.getApplicationContext(),
+ BoardDatabase.class,
+ "board_database"
+ ).build();
+
+ return INSTANCE;
+ }
+ }
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/entity/Board.kt b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/entity/Board.kt
new file mode 100644
index 0000000..eb61071
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/entity/Board.kt
@@ -0,0 +1,15 @@
+package it.unisannio.ding.ids.wedroid.app.data.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "board_table")
+data class Board(
+ @PrimaryKey @ColumnInfo(name = "id") val id: String,
+ @ColumnInfo(name = "title") val title: String = ""
+)
+
+fun it.unisannio.ding.ids.wedroid.wrapper.entity.Board.convert(): Board {
+ return Board(this.id, this.title)
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/repository/BoardRepository.kt b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/repository/BoardRepository.kt
new file mode 100644
index 0000000..1218371
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/data/repository/BoardRepository.kt
@@ -0,0 +1,161 @@
+package it.unisannio.ding.ids.wedroid.app.data.repository
+
+import android.util.Log
+import it.unisannio.ding.ids.wedroid.app.data.dao.BoardDao
+import it.unisannio.ding.ids.wedroid.app.data.entity.Board
+import it.unisannio.ding.ids.wedroid.app.data.entity.convert
+import it.unisannio.ding.ids.wedroid.app.util.PreferenceReader
+import it.unisannio.ding.ids.wedroid.wrapper.api.BoardService
+import it.unisannio.ding.ids.wedroid.wrapper.entity.BoardBackgroundColor
+import it.unisannio.ding.ids.wedroid.wrapper.entity.BoardPermission
+import it.unisannio.ding.ids.wedroid.wrapper.entity.BoardPrototype
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+
+class BoardRepository(
+ private val dao: BoardDao,
+ private val service: BoardService,
+ private val reader: PreferenceReader
+) {
+ val allBoards by lazy {
+ dao.getAllBoard()
+ }
+
+ init {
+ synchronize()
+ }
+
+ fun synchronize() {
+ service.getBoardsFromUser(reader.userId)
+ .enqueue(object :
+ Callback> {
+ override fun onFailure(
+ call: Call>,
+ t: Throwable
+ ) = logNetworkError(t.message)
+
+ override fun onResponse(
+ call: Call>,
+ response: Response>
+ ) {
+ CoroutineScope(Dispatchers.IO).launch {
+ synchronizeCallback(response)
+ }
+ }
+ })
+ }
+
+ private suspend fun synchronizeCallback(
+ response: Response>
+ ) {
+ if (!response.isSuccessful) {
+ logNetworkError("${response.code()} ${response.message()}")
+ return
+ }
+
+ // read boards from the body
+ val boards = (response.body() ?: return)
+ .map { it.convert() }
+
+ addNewBoardToDb(boards)
+
+ removeOldBoardsFromDb(boards)
+ }
+
+ fun insertBoard(title: String, isPrivate: Boolean, color: BoardBackgroundColor) {
+ val permission = if (isPrivate) BoardPermission.PRIVATE else BoardPermission.PUBLIC
+
+ service.newBoard(
+ BoardPrototype.Builder()
+ .setOwner(reader.userId)
+ .setTitle(title)
+ .setBackgroundColor(color)
+ .setBoardPermission(permission)
+ .build()
+ ).enqueue(object : Callback {
+ override fun onFailure(
+ call: Call,
+ t: Throwable
+ ) = logNetworkError(t.message)
+
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ CoroutineScope(Dispatchers.IO).launch {
+ insertBoardCallback(response, title)
+ }
+ }
+ })
+ }
+
+ private suspend fun insertBoardCallback(
+ response: Response,
+ title: String
+ ) {
+ if (!response.isSuccessful) {
+ logNetworkError("${response.code()} ${response.message()}")
+ return
+ }
+
+ val board = response.body()
+
+ if (board == null) {
+ logNetworkError("empty body")
+ return
+ }
+
+ dao.insert(Board(board.id, title))
+ }
+
+ fun deleteBoard(id: String) {
+ service.deleteBoard(id).enqueue(
+ object : Callback {
+ override fun onFailure(call: Call, t: Throwable) {
+ logNetworkError(t.message)
+ }
+
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ CoroutineScope(Dispatchers.IO).launch {
+ deleteBoardCallback(response, id)
+ }
+ }
+ })
+ }
+
+ private suspend fun deleteBoardCallback(
+ response: Response,
+ id: String
+ ) {
+ if (!response.isSuccessful) {
+ logNetworkError("${response.code()} ${response.message()}")
+ return
+ }
+
+ dao.delete(Board(id))
+ }
+
+ private suspend fun addNewBoardToDb(boards: Collection) {
+ boards.forEach {
+ dao.insert(it)
+ }
+ }
+
+ private suspend fun removeOldBoardsFromDb(boards: Collection) {
+ allBoards.value?.minus(boards)
+ ?.forEach {
+ dao.delete(it)
+ }
+ }
+
+ private fun logNetworkError(message: String?) {
+ Log.e("RETROFIT", message)
+ }
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/ServicesFactory.kt b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/ServicesFactory.kt
index 457a197..5e3d8dd 100644
--- a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/ServicesFactory.kt
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/ServicesFactory.kt
@@ -1,10 +1,17 @@
package it.unisannio.ding.ids.wedroid.app.util
-import it.unisannio.ding.ids.wedroid.wrapper.api.*
+import it.unisannio.ding.ids.wedroid.wrapper.api.BoardService
+import it.unisannio.ding.ids.wedroid.wrapper.api.CardCommentService
+import it.unisannio.ding.ids.wedroid.wrapper.api.CardService
+import it.unisannio.ding.ids.wedroid.wrapper.api.ChecklistService
+import it.unisannio.ding.ids.wedroid.wrapper.api.ListService
+import it.unisannio.ding.ids.wedroid.wrapper.api.SwimlanesService
+import it.unisannio.ding.ids.wedroid.wrapper.api.UserService
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
+
class ServicesFactory(
reader: PreferenceReader
) {
@@ -75,4 +82,3 @@ class ServicesFactory(
}
}
}
-
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/SharedPreferenceHelper.kt b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/SharedPreferenceHelper.kt
index 4ee1c06..41907b7 100644
--- a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/SharedPreferenceHelper.kt
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/util/SharedPreferenceHelper.kt
@@ -2,7 +2,8 @@ package it.unisannio.ding.ids.wedroid.app.util
import android.content.Context
-class SharedPreferenceHelper(context : Context) : PreferenceReader, PreferenceWriter {
+class SharedPreferenceHelper(context: Context) : PreferenceReader, PreferenceWriter {
+
private val sp = context.getSharedPreferences("userinfo", Context.MODE_PRIVATE)
override fun getBaseUrl(): String? {
@@ -20,8 +21,7 @@ class SharedPreferenceHelper(context : Context) : PreferenceReader, PreferenceWr
override fun setBaseUrl(baseUrl: String?) {
val editor = sp.edit()
editor.putString("url", baseUrl).apply()
-
- }
+ }
override fun setUserId(userId: String?) {
val editor = sp.edit()
@@ -41,4 +41,5 @@ class SharedPreferenceHelper(context : Context) : PreferenceReader, PreferenceWr
val editor = sp.edit()
editor.putString("boardId", token).apply()
}
-}
\ No newline at end of file
+}
+
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/BoardsListsActivity.kt b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/BoardsListsActivity.kt
new file mode 100644
index 0000000..228a206
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/BoardsListsActivity.kt
@@ -0,0 +1,133 @@
+package it.unisannio.ding.ids.wedroid.app.view
+
+import android.content.Intent
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import it.unisannio.ding.ids.wedroid.app.R
+import it.unisannio.ding.ids.wedroid.app.util.PreferenceReader
+import it.unisannio.ding.ids.wedroid.app.util.SharedPreferenceHelper
+import it.unisannio.ding.ids.wedroid.app.view.adapter.BoardsListAdapter
+import it.unisannio.ding.ids.wedroid.app.viewModel.BoardsListViewModel
+import it.unisannio.ding.ids.wedroid.wrapper.entity.BoardBackgroundColor
+
+import kotlinx.android.synthetic.main.activity_boards_lists.*
+import kotlinx.android.synthetic.main.content_boards_lists.*
+import java.util.Locale
+
+class BoardsListsActivity : AppCompatActivity() {
+ private lateinit var viewModel: BoardsListViewModel
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_boards_lists)
+ setSupportActionBar(toolbar)
+ val reader: PreferenceReader = SharedPreferenceHelper(this)
+
+ if (reader.token == "")
+ startActivityForResult(
+ Intent(this, LoginActivity::class.java),
+ LOGIN_CODE
+ )
+ else initializeUi()
+ }
+
+ private fun initializeUi() {
+ viewModel = ViewModelProvider(this).get(BoardsListViewModel::class.java)
+
+ val adapter = BoardsListAdapter(this)
+ boardList.adapter = adapter
+ boardList.layoutManager = LinearLayoutManager(this)
+
+ viewModel.allBoards.observe(this, Observer {
+ it.let { adapter.setBoards(it) }
+ pullToRefresh.isRefreshing = false
+ })
+
+ swipeLeftToDelete()
+
+ fab.setOnClickListener {
+ startActivityForResult(
+ Intent(this, NewBoardActivity::class.java),
+ NEW_BOARD_CODE
+ )
+ }
+
+ pullToRefresh.setColorSchemeColors(getColor(R.color.colorAccent))
+ pullToRefresh.setOnRefreshListener {
+ viewModel.refresh()
+ }
+ }
+
+ private fun swipeLeftToDelete() {
+ val swipeToDelete = ItemTouchHelper(
+ object : ItemTouchHelper.SimpleCallback(
+ 0, ItemTouchHelper.LEFT
+ ) {
+ override fun onMove(
+ recyclerView: RecyclerView,
+ viewHolder: RecyclerView.ViewHolder,
+ target: RecyclerView.ViewHolder
+ ): Boolean {
+ return false
+ }
+
+ override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
+ val pos = viewHolder.adapterPosition
+ viewModel.deleteBoard(pos)
+ }
+ })
+
+ swipeToDelete.attachToRecyclerView(boardList)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ when (requestCode) {
+ LOGIN_CODE -> onLoginResult(resultCode)
+ NEW_BOARD_CODE -> if (data != null) onAddBoardResult(resultCode, data)
+ else -> finish()
+ }
+ }
+
+ private fun onLoginResult(resultCode: Int) {
+ when (resultCode) {
+ LoginActivity.LOGIN_OK -> initializeUi()
+ LoginActivity.LOGIN_ERROR -> finish()
+ else -> finish()
+ }
+ }
+
+ private fun onAddBoardResult(resultCode: Int, data: Intent) {
+ if (resultCode != NewBoardActivity.RESULT_OK) {
+ Toast.makeText(this, R.string.on_add_new_board_error, Toast.LENGTH_LONG)
+ .show()
+ return
+ }
+
+ val title = data.getStringExtra(NewBoardActivity.BOARD_NAME)
+ if (title == null) {
+ Toast.makeText(this, R.string.on_null_new_board_name, Toast.LENGTH_LONG)
+ .show()
+ return
+ }
+
+ val isPrivate = data.getBooleanExtra(NewBoardActivity.BOARD_PRIVATE, true)
+
+ val colorName = data.getStringExtra(NewBoardActivity.BOARD_BACKGROUND_COLOR) ?: "belize"
+ val backgroundColor = BoardBackgroundColor
+ .valueOf(colorName.toUpperCase(Locale.ROOT))
+
+ viewModel.insertBoard(title, isPrivate, backgroundColor)
+ }
+
+ companion object {
+ const val NEW_BOARD_CODE = 17
+ const val LOGIN_CODE = 19
+ }
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/LoginActivity.kt b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/LoginActivity.kt
new file mode 100644
index 0000000..811db1a
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/LoginActivity.kt
@@ -0,0 +1,97 @@
+package it.unisannio.ding.ids.wedroid.app.view
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.view.View
+import android.webkit.URLUtil
+import android.widget.Toast
+import it.unisannio.ding.ids.wedroid.app.R
+import it.unisannio.ding.ids.wedroid.app.util.SharedPreferenceHelper
+import it.unisannio.ding.ids.wedroid.wrapper.api.LoginService
+import it.unisannio.ding.ids.wedroid.wrapper.entity.UserPrototype
+import kotlinx.android.synthetic.main.activity_login.*
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+class LoginActivity : AppCompatActivity() {
+ lateinit var sph: SharedPreferenceHelper
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_login)
+ sph = SharedPreferenceHelper(this)
+
+ setResult(LOGIN_ERROR)
+
+ val id = sph.userId
+ val token = sph.token
+ val url = sph.baseUrl
+ }
+
+ fun loginButton(v: View) {
+ if (username.text.isBlank() || instanceServer.text.isBlank() || password.text.isBlank()) {
+ Toast.makeText(this, R.string.login_empty_field, Toast.LENGTH_LONG)
+ .show()
+ return
+ }
+
+ val userNameText = username.text.toString()
+ val passwordText = password.text.toString()
+ val instanceServerText = instanceServer.text.toString()
+
+ if (!URLUtil.isValidUrl(instanceServerText)){
+ Toast.makeText(this, R.string.login_unformed_instance, Toast.LENGTH_LONG)
+ .show()
+ return
+ }
+
+ val service = Retrofit.Builder()
+ .addConverterFactory(GsonConverterFactory.create())
+ .baseUrl(instanceServerText)
+ .build()
+ .create(LoginService::class.java)
+
+ service.login(userNameText, passwordText).enqueue(object : Callback {
+ override fun onFailure(call: Call, t: Throwable) {
+ Toast.makeText(
+ applicationContext,
+ R.string.login_network_error,
+ Toast.LENGTH_LONG
+ ).show()
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+
+ if (response.code() != 200) {
+ Toast.makeText(
+ applicationContext,
+ R.string.login_wrong_field,
+ Toast.LENGTH_LONG
+ ).show()
+ return
+ }
+ val users = response.body()
+ sph.baseUrl = instanceServer.text.toString()
+ sph.token = users?.token
+ sph.userId = users?.id
+
+ Toast.makeText(
+ applicationContext,
+ R.string.login_success,
+ Toast.LENGTH_LONG
+ ).show()
+
+ setResult(LOGIN_OK)
+ finish()
+ }
+ })
+ }
+
+ companion object {
+ const val LOGIN_OK = 0
+ const val LOGIN_ERROR = 1
+ }
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/NewBoardActivity.java b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/NewBoardActivity.java
new file mode 100644
index 0000000..887b245
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/NewBoardActivity.java
@@ -0,0 +1,69 @@
+package it.unisannio.ding.ids.wedroid.app.view;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import android.util.Log;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.Switch;
+import android.widget.Toast;
+
+import it.unisannio.ding.ids.wedroid.app.R;
+import it.unisannio.ding.ids.wedroid.wrapper.entity.BoardBackgroundColor;
+
+public class NewBoardActivity extends AppCompatActivity {
+ private EditText boardName;
+ private Switch isPrivate;
+ private Spinner colorPicker;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_new_board);
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ boardName = findViewById(R.id.newBoardName);
+ isPrivate = findViewById(R.id.newBoardPermission);
+
+ colorPicker = findViewById(R.id.newBoardColor);
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(
+ this,
+ R.array.board_background_colors,
+ android.R.layout.simple_spinner_item
+ );
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ colorPicker.setAdapter(adapter);
+
+ }
+
+ public void onDone(View v) {
+ if (boardName.getText().toString().equals("")) {
+ Toast.makeText(this, R.string.on_add_new_board_empty_name, Toast.LENGTH_LONG)
+ .show();
+ return;
+ }
+
+ Intent data = new Intent();
+ data.putExtra(BOARD_NAME, boardName.getText().toString());
+ data.putExtra(BOARD_PRIVATE, isPrivate.isChecked());
+ data.putExtra(BOARD_BACKGROUND_COLOR, colorPicker.getSelectedItem().toString());
+ setResult(RESULT_OK, data);
+ finish();
+ }
+
+ public void onCancel(View v) {
+ finish();
+ }
+
+ public static final int RESULT_OK = 17;
+ public static final String BOARD_NAME = "BOARD_NAME";
+ public static final String BOARD_PRIVATE = "BOARD_PRIVATE";
+ public static final String BOARD_BACKGROUND_COLOR = "BOARD_BACKGROUND_COLOR";
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/adapter/BoardsListAdapter.kt b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/adapter/BoardsListAdapter.kt
new file mode 100644
index 0000000..8d66b87
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/view/adapter/BoardsListAdapter.kt
@@ -0,0 +1,55 @@
+package it.unisannio.ding.ids.wedroid.app.view.adapter
+
+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 it.unisannio.ding.ids.wedroid.app.R
+import it.unisannio.ding.ids.wedroid.app.data.entity.Board
+import it.unisannio.ding.ids.wedroid.app.view.BoardViewActivity
+
+class BoardsListAdapter internal constructor(
+ context: Context
+) : RecyclerView.Adapter() {
+
+ private val inflater = LayoutInflater.from(context)
+ private var boards = emptyList()
+
+ inner class BoardViewHolder(
+ view: View
+ ) : RecyclerView.ViewHolder(view) {
+ val boardTitle: TextView = view.findViewById(R.id.boardTitle)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BoardViewHolder {
+ val view = inflater.inflate(R.layout.board_recycle_item, parent, false)
+ return BoardViewHolder(view)
+ }
+
+ override fun getItemCount(): Int {
+ return boards.size
+ }
+
+ override fun onBindViewHolder(holder: BoardViewHolder, position: Int) {
+ val board = boards[position]
+ holder.boardTitle.text = board.title
+
+ holder.itemView.setOnClickListener {
+ val intent = Intent(it.context, BoardViewActivity::class.java)
+ intent.putExtra("idBoard", board.id)
+ it.context.startActivity(intent)
+ }
+ }
+
+ internal fun setBoards(boards: List) {
+ this.boards = boards
+ notifyDataSetChanged()
+ }
+
+ companion object {
+ const val BOARD_ID = "BOARD_ID"
+ }
+}
diff --git a/app/src/main/java/it/unisannio/ding/ids/wedroid/app/viewmodel/BoardsListViewModel.java b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/viewmodel/BoardsListViewModel.java
new file mode 100644
index 0000000..56b1037
--- /dev/null
+++ b/app/src/main/java/it/unisannio/ding/ids/wedroid/app/viewmodel/BoardsListViewModel.java
@@ -0,0 +1,53 @@
+package it.unisannio.ding.ids.wedroid.app.viewModel;
+
+import android.app.Application;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+
+import java.util.List;
+
+import it.unisannio.ding.ids.wedroid.app.data.database.BoardDatabase;
+import it.unisannio.ding.ids.wedroid.app.data.entity.Board;
+import it.unisannio.ding.ids.wedroid.app.data.repository.BoardRepository;
+import it.unisannio.ding.ids.wedroid.app.util.PreferenceReader;
+import it.unisannio.ding.ids.wedroid.app.util.ServicesFactory;
+import it.unisannio.ding.ids.wedroid.app.util.SharedPreferenceHelper;
+import it.unisannio.ding.ids.wedroid.wrapper.entity.BoardBackgroundColor;
+
+public class BoardsListViewModel extends AndroidViewModel {
+ private BoardRepository repository;
+ private LiveData> allBoards;
+
+ public BoardsListViewModel(@NonNull Application application) {
+ super(application);
+ PreferenceReader reader = new SharedPreferenceHelper(application);
+ repository = new BoardRepository(
+ BoardDatabase.getDatabase(application).boardDao(),
+ ServicesFactory.Companion.getInstance(reader).getBoardService(),
+ reader
+ );
+
+ allBoards = repository.getAllBoards();
+ }
+
+ public LiveData> getAllBoards() {
+ return allBoards;
+ }
+
+ public void insertBoard(String title, boolean isPrivate, BoardBackgroundColor color) {
+ repository.insertBoard(title, isPrivate, color);
+ }
+
+ public void deleteBoard(int position) {
+ List boards = allBoards.getValue();
+
+ if (boards != null)
+ repository.deleteBoard(boards.get(position).getId());
+ }
+
+ public void refresh() {
+ repository.synchronize();
+ }
+}
diff --git a/app/src/main/res/drawable/ic_add_black_24dp.xml b/app/src/main/res/drawable/ic_add_black_24dp.xml
new file mode 100644
index 0000000..6b6146e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_add_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_boards_lists.xml b/app/src/main/res/layout/activity_boards_lists.xml
new file mode 100644
index 0000000..7282fa5
--- /dev/null
+++ b/app/src/main/res/layout/activity_boards_lists.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000..1d6bf2a
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 707df3a..0000000
--- a/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_new_board.xml b/app/src/main/res/layout/activity_new_board.xml
new file mode 100644
index 0000000..d32de4d
--- /dev/null
+++ b/app/src/main/res/layout/activity_new_board.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/board_recycle_item.xml b/app/src/main/res/layout/board_recycle_item.xml
new file mode 100644
index 0000000..3f472f3
--- /dev/null
+++ b/app/src/main/res/layout/board_recycle_item.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_boards_lists.xml b/app/src/main/res/layout/content_boards_lists.xml
new file mode 100644
index 0000000..dc3adf9
--- /dev/null
+++ b/app/src/main/res/layout/content_boards_lists.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_new_board.xml b/app/src/main/res/layout/content_new_board.xml
new file mode 100644
index 0000000..851e4dd
--- /dev/null
+++ b/app/src/main/res/layout/content_new_board.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 464feb3..7ebf0d8 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,4 +1,8 @@
16dp
+
10dp
+
+ 8dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a97c690..57620b6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -12,4 +12,34 @@
Add Card
Enter text here...
Enter card name
+ BoardsListActivity
+ NewBoardActivity
+ Board name
+ Private
+ Cancel
+ Done
+ There was a problem with the name of the new board
+ It was not possible to add a new board
+ Name cannot be empty
+
+
+ - Belize
+ - Nephritis
+ - Pomegranate
+ - Pumpkin
+ - Wisteria
+ - Moderatepink
+ - Strongcyan
+ - Limegreen
+ - Midnight
+ - Dark
+ - Relax
+ - Corteza
+
+ Riempire tutti i campi
+ Formato URL non valido
+ Controlla la tua connessione internet
+ Credenziali non corrette
+ Login effettuato con successo
+
diff --git a/app/src/test/java/it/unisannio/ding/ids/wedroid/app/TestHelper.kt b/app/src/test/java/it/unisannio/ding/ids/wedroid/app/TestHelper.kt
new file mode 100644
index 0000000..f2a68ee
--- /dev/null
+++ b/app/src/test/java/it/unisannio/ding/ids/wedroid/app/TestHelper.kt
@@ -0,0 +1,12 @@
+package it.unisannio.ding.ids.wedroid.app
+
+import kotlin.reflect.KClass
+import kotlin.reflect.KFunction
+import kotlin.reflect.full.declaredFunctions
+import kotlin.reflect.jvm.isAccessible
+
+fun getPrivateFun(name: String, kClass: KClass<*>): KFunction<*>? {
+ return kClass.declaredFunctions
+ .find { it.name == name }
+ .also { it?.isAccessible = true }
+}
diff --git a/app/src/test/java/it/unisannio/ding/ids/wedroid/app/data/repository/BoardRepositoryTest.kt b/app/src/test/java/it/unisannio/ding/ids/wedroid/app/data/repository/BoardRepositoryTest.kt
new file mode 100644
index 0000000..d8def75
--- /dev/null
+++ b/app/src/test/java/it/unisannio/ding/ids/wedroid/app/data/repository/BoardRepositoryTest.kt
@@ -0,0 +1,318 @@
+package it.unisannio.ding.ids.wedroid.app.data.repository
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import io.mockk.*
+import it.unisannio.ding.ids.wedroid.app.data.dao.BoardDao
+import it.unisannio.ding.ids.wedroid.app.data.entity.Board
+import it.unisannio.ding.ids.wedroid.app.getPrivateFun
+import it.unisannio.ding.ids.wedroid.app.util.PreferenceReader
+import it.unisannio.ding.ids.wedroid.wrapper.api.BoardService
+import junit.framework.TestCase.*
+import kotlinx.coroutines.*
+import okhttp3.mockwebserver.MockWebServer
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import retrofit2.Response
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import kotlin.reflect.full.callSuspend
+
+class BoardRepositoryTest {
+ private val reader = mockk()
+ private val webServer = MockWebServer()
+ private lateinit var service: BoardService
+
+ @Before
+ fun setUp() {
+ webServer.start()
+ service = Retrofit.Builder()
+ .baseUrl(webServer.url("/"))
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(BoardService::class.java)
+
+ mockkStatic(Log::class)
+ every { reader.userId } returns "user id"
+ every { Log.e(any(), any()) } returns 0
+ }
+
+ @After
+ fun teardown() {
+ webServer.close()
+ }
+
+ @Test
+ fun addNewBoardsToDb() {
+ val dao = mockk()
+ var count = 0
+
+ coEvery {
+ dao.insert(any())
+ } answers {
+ count++
+ }
+
+ val addNewBoardToDb = getPrivateFun(
+ "addNewBoardToDb", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ val board0 = Board("id0", "title0")
+ val board1 = Board("id1", "title1")
+ val board2 = Board("id2", "title2")
+
+ runBlocking {
+ addNewBoardToDb?.callSuspend(
+ repository,
+ listOf(board0, board1, board2)
+ )
+ }
+
+ coVerifyAll {
+ dao.insert(board0)
+ dao.insert(board1)
+ dao.insert(board2)
+ }
+
+ assertEquals(3, count)
+ }
+
+ @Test
+ fun insertBoardCallbackSuccess() {
+ val dao = mockk()
+ val response =
+ mockk>()
+ val board = mockk()
+
+ every { response.isSuccessful } returns true
+ every { response.body() } returns board
+ every { board.id } returns "id"
+ coEvery { dao.insert(any()) } answers {}
+
+ val insertBoard = getPrivateFun(
+ "insertBoardCallback", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ insertBoard?.callSuspend(
+ repository,
+ response,
+ "title"
+ )
+ }
+
+ coVerify { dao.insert(Board("id", "title")) }
+ }
+
+ @Test
+ fun insertBoardCallbackEmptyBody() {
+ val dao = mockk()
+ val response =
+ mockk>()
+
+ every { response.isSuccessful } returns true
+ every { response.body() } returns null
+
+ val insertBoard = getPrivateFun(
+ "insertBoardCallback", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ insertBoard?.callSuspend(
+ repository,
+ response,
+ "title"
+ )
+ }
+
+ verify { Log.e("RETROFIT", "empty body") }
+ }
+
+ @Test
+ fun insertBoardCallbackError() {
+ val dao = mockk()
+ val response =
+ mockk>()
+
+ every { response.isSuccessful } returns false
+ every { response.code() } returns 400
+ every { response.message() } returns "Error"
+
+ val insertBoard = getPrivateFun(
+ "insertBoardCallback", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ insertBoard?.callSuspend(
+ repository,
+ response,
+ "title"
+ )
+ }
+
+ verify { Log.e("RETROFIT", "400 Error") }
+ }
+
+ @Test
+ fun deleteBoardCallbackSuccess() {
+ val dao = mockk()
+ val response =
+ mockk>()
+
+ every { response.isSuccessful } returns true
+ coEvery { dao.delete(any()) } answers {}
+
+ val deleteBoard = getPrivateFun(
+ "deleteBoardCallback", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ deleteBoard?.callSuspend(
+ repository,
+ response,
+ "id"
+ )
+ }
+
+ coVerify { dao.delete(Board("id")) }
+ }
+
+ @Test
+ fun deleteBoardCallbackError() {
+ val dao = mockk()
+ val response =
+ mockk>()
+
+ every { response.isSuccessful } returns false
+ every { response.code() } returns 400
+ every { response.message() } returns "Error"
+
+ val deleteBoard = getPrivateFun(
+ "deleteBoardCallback", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ deleteBoard?.callSuspend(
+ repository,
+ response,
+ "id"
+ )
+ }
+
+ verify { Log.e("RETROFIT", "400 Error") }
+ }
+
+ @Test
+ fun deleteOldBoardFromDb() {
+ val dao = mockk()
+ val dbBoards = mockk>>()
+
+ val board0 = Board("id0", "title0")
+ val board1 = Board("id1", "title1")
+ val board2 = Board("id2", "title2")
+ val board3 = Board("id2", "title3")
+
+ every { dbBoards.value } returns listOf(
+ board0, board1, board2, board3
+ )
+ coEvery { dao.getAllBoard() } returns dbBoards
+ coEvery { dao.delete(any()) } answers {}
+
+ val removeOldBoards = getPrivateFun(
+ "removeOldBoardsFromDb", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ removeOldBoards?.callSuspend(
+ repository,
+ listOf(
+ board0, board1, board3
+ )
+ )
+ }
+
+ coVerify { dao.delete(board2) }
+ }
+
+ @Test
+ fun synchronizeCallbackError() {
+ val dao = mockk()
+ val response =
+ mockk>>()
+
+ every { response.isSuccessful } returns false
+ every { response.code() } returns 400
+ every { response.message() } returns "Error"
+
+ val synchronize = getPrivateFun(
+ "synchronizeCallback", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ synchronize?.callSuspend(
+ repository,
+ response
+ )
+ }
+
+ verify { Log.e("RETROFIT", "400 Error") }
+ }
+
+ @Test
+ fun synchronizeCallbackEmptyBody() {
+ val dao = mockk()
+ val response =
+ mockk>>()
+
+ every { response.isSuccessful } returns true
+ every { response.body() } returns null
+
+ val synchronize = getPrivateFun(
+ "synchronizeCallback", BoardRepository::class
+ )
+
+ val repository = BoardRepository(
+ dao, service, reader
+ )
+
+ runBlocking {
+ synchronize?.callSuspend(
+ repository,
+ response
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 7dd7b0c..e65847d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,21 +5,24 @@ buildscript {
repositories {
google()
jcenter()
-
+ maven { url "https://plugins.gradle.org/m2/" }
}
+
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.2.2"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
+ apply plugin: 'checkstyle'
+
repositories {
google()
jcenter()
-
}
}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000..ca6d646
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml
new file mode 100644
index 0000000..05426c6
--- /dev/null
+++ b/config/detekt/detekt.yml
@@ -0,0 +1,580 @@
+build:
+ maxIssues: 10
+ weights:
+ # complexity: 2
+ # LongParameterList: 1
+ # style: 1
+ # comments: 1
+
+config:
+ validation: true
+ # when writing own rules with new properties, exclude the property path e.g.: "my_rule_set,.*>.*>[my_property]"
+ excludes: ""
+
+processors:
+ active: true
+ exclude:
+ # - 'DetektProgressListener'
+ # - 'FunctionCountProcessor'
+ # - 'PropertyCountProcessor'
+ # - 'ClassCountProcessor'
+ # - 'PackageCountProcessor'
+ # - 'KtFileCountProcessor'
+
+console-reports:
+ active: true
+ exclude:
+ # - 'ProjectStatisticsReport'
+ # - 'ComplexityReport'
+ # - 'NotificationReport'
+ # - 'FindingsReport'
+ - 'FileBasedFindingsReport'
+ # - 'BuildFailureReport'
+
+comments:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ CommentOverPrivateFunction:
+ active: false
+ CommentOverPrivateProperty:
+ active: false
+ EndOfSentenceFormat:
+ active: false
+ endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!:]$)
+ UndocumentedPublicClass:
+ active: false
+ searchInNestedClass: true
+ searchInInnerClass: true
+ searchInInnerObject: true
+ searchInInnerInterface: true
+ UndocumentedPublicFunction:
+ active: false
+ UndocumentedPublicProperty:
+ active: false
+
+complexity:
+ active: true
+ ComplexCondition:
+ active: true
+ threshold: 4
+ ComplexInterface:
+ active: false
+ threshold: 10
+ includeStaticDeclarations: false
+ ComplexMethod:
+ active: true
+ threshold: 15
+ ignoreSingleWhenExpression: false
+ ignoreSimpleWhenEntries: false
+ ignoreNestingFunctions: false
+ nestingFunctions: run,let,apply,with,also,use,forEach,isNotNull,ifNull
+ LabeledExpression:
+ active: false
+ ignoredLabels: ""
+ LargeClass:
+ active: true
+ threshold: 600
+ LongMethod:
+ active: true
+ threshold: 60
+ LongParameterList:
+ active: true
+ threshold: 6
+ ignoreDefaultParameters: false
+ MethodOverloading:
+ active: false
+ threshold: 6
+ NestedBlockDepth:
+ active: true
+ threshold: 4
+ StringLiteralDuplication:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ threshold: 3
+ ignoreAnnotation: true
+ excludeStringsWithLessThan5Characters: true
+ ignoreStringsRegex: '$^'
+ TooManyFunctions:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ thresholdInFiles: 11
+ thresholdInClasses: 11
+ thresholdInInterfaces: 11
+ thresholdInObjects: 11
+ thresholdInEnums: 11
+ ignoreDeprecated: false
+ ignorePrivate: false
+ ignoreOverridden: false
+
+empty-blocks:
+ active: true
+ EmptyCatchBlock:
+ active: true
+ allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
+ EmptyClassBlock:
+ active: true
+ EmptyDefaultConstructor:
+ active: true
+ EmptyDoWhileBlock:
+ active: true
+ EmptyElseBlock:
+ active: true
+ EmptyFinallyBlock:
+ active: true
+ EmptyForBlock:
+ active: true
+ EmptyFunctionBlock:
+ active: true
+ ignoreOverriddenFunctions: false
+ EmptyIfBlock:
+ active: true
+ EmptyInitBlock:
+ active: true
+ EmptyKtFile:
+ active: true
+ EmptySecondaryConstructor:
+ active: true
+ EmptyWhenBlock:
+ active: true
+ EmptyWhileBlock:
+ active: true
+
+exceptions:
+ active: true
+ ExceptionRaisedInUnexpectedLocation:
+ active: false
+ methodNames: 'toString,hashCode,equals,finalize'
+ InstanceOfCheckForException:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ NotImplementedDeclaration:
+ active: false
+ PrintStackTrace:
+ active: false
+ RethrowCaughtException:
+ active: false
+ ReturnFromFinally:
+ active: false
+ ignoreLabeled: false
+ SwallowedException:
+ active: false
+ ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException'
+ allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
+ ThrowingExceptionFromFinally:
+ active: false
+ ThrowingExceptionInMain:
+ active: false
+ ThrowingExceptionsWithoutMessageOrCause:
+ active: false
+ exceptions: 'IllegalArgumentException,IllegalStateException,IOException'
+ ThrowingNewInstanceOfSameException:
+ active: false
+ TooGenericExceptionCaught:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ exceptionNames:
+ - ArrayIndexOutOfBoundsException
+ - Error
+ - Exception
+ - IllegalMonitorStateException
+ - NullPointerException
+ - IndexOutOfBoundsException
+ - RuntimeException
+ - Throwable
+ allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
+ TooGenericExceptionThrown:
+ active: true
+ exceptionNames:
+ - Error
+ - Exception
+ - Throwable
+ - RuntimeException
+
+formatting:
+ active: true
+ android: true
+ autoCorrect: true
+ AnnotationOnSeparateLine:
+ active: false
+ autoCorrect: true
+ ChainWrapping:
+ active: true
+ autoCorrect: true
+ CommentSpacing:
+ active: true
+ autoCorrect: true
+ Filename:
+ active: true
+ FinalNewline:
+ active: false
+ autoCorrect: true
+ ImportOrdering:
+ active: false
+ autoCorrect: true
+ Indentation:
+ active: false
+ autoCorrect: true
+ indentSize: 4
+ continuationIndentSize: 4
+ MaximumLineLength:
+ active: true
+ maxLineLength: 120
+ ModifierOrdering:
+ active: true
+ autoCorrect: true
+ MultiLineIfElse:
+ active: false
+ autoCorrect: true
+ NoBlankLineBeforeRbrace:
+ active: true
+ autoCorrect: true
+ NoConsecutiveBlankLines:
+ active: true
+ autoCorrect: true
+ NoEmptyClassBody:
+ active: true
+ autoCorrect: true
+ NoLineBreakAfterElse:
+ active: true
+ autoCorrect: true
+ NoLineBreakBeforeAssignment:
+ active: true
+ autoCorrect: true
+ NoMultipleSpaces:
+ active: true
+ autoCorrect: true
+ NoSemicolons:
+ active: true
+ autoCorrect: true
+ NoTrailingSpaces:
+ active: true
+ autoCorrect: true
+ NoUnitReturn:
+ active: true
+ autoCorrect: true
+ NoUnusedImports:
+ active: true
+ autoCorrect: true
+ NoWildcardImports:
+ active: true
+ PackageName:
+ active: true
+ autoCorrect: true
+ ParameterListWrapping:
+ active: true
+ autoCorrect: true
+ indentSize: 4
+ SpacingAroundColon:
+ active: true
+ autoCorrect: true
+ SpacingAroundComma:
+ active: true
+ autoCorrect: true
+ SpacingAroundCurly:
+ active: true
+ autoCorrect: true
+ SpacingAroundDot:
+ active: true
+ autoCorrect: true
+ SpacingAroundKeyword:
+ active: true
+ autoCorrect: true
+ SpacingAroundOperators:
+ active: true
+ autoCorrect: true
+ SpacingAroundParens:
+ active: true
+ autoCorrect: true
+ SpacingAroundRangeOperator:
+ active: true
+ autoCorrect: true
+ StringTemplate:
+ active: true
+ autoCorrect: true
+
+naming:
+ active: true
+ ClassNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ classPattern: '[A-Z$][a-zA-Z0-9$]*'
+ ConstructorParameterNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ parameterPattern: '[a-z][A-Za-z0-9]*'
+ privateParameterPattern: '[a-z][A-Za-z0-9]*'
+ excludeClassPattern: '$^'
+ ignoreOverridden: true
+ EnumNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*'
+ ForbiddenClassName:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ forbiddenName: ''
+ FunctionMaxLength:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ maximumFunctionNameLength: 30
+ FunctionMinLength:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ minimumFunctionNameLength: 3
+ FunctionNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$'
+ excludeClassPattern: '$^'
+ ignoreOverridden: true
+ FunctionParameterNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ parameterPattern: '[a-z][A-Za-z0-9]*'
+ excludeClassPattern: '$^'
+ ignoreOverriddenFunctions: true
+ InvalidPackageDeclaration:
+ active: false
+ rootPackage: ''
+ MatchingDeclarationName:
+ active: true
+ MemberNameEqualsClassName:
+ active: true
+ ignoreOverriddenFunction: true
+ ObjectPropertyNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ constantPattern: '[A-Za-z][_A-Za-z0-9]*'
+ propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
+ privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'
+ PackageNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ packagePattern: '^[a-z]+(\.[a-z][A-Za-z0-9]*)*$'
+ TopLevelPropertyNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ constantPattern: '[A-Z][_A-Z0-9]*'
+ propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
+ privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'
+ VariableMaxLength:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ maximumVariableNameLength: 64
+ VariableMinLength:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ minimumVariableNameLength: 1
+ VariableNaming:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ variablePattern: '[a-z][A-Za-z0-9]*'
+ privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
+ excludeClassPattern: '$^'
+ ignoreOverridden: true
+
+performance:
+ active: true
+ ArrayPrimitive:
+ active: true
+ ForEachOnRange:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ SpreadOperator:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ UnnecessaryTemporaryInstantiation:
+ active: true
+
+potential-bugs:
+ active: true
+ Deprecation:
+ active: false
+ DuplicateCaseInWhenExpression:
+ active: true
+ EqualsAlwaysReturnsTrueOrFalse:
+ active: true
+ EqualsWithHashCodeExist:
+ active: true
+ ExplicitGarbageCollectionCall:
+ active: true
+ HasPlatformType:
+ active: false
+ ImplicitDefaultLocale:
+ active: false
+ InvalidRange:
+ active: true
+ IteratorHasNextCallsNextMethod:
+ active: true
+ IteratorNotThrowingNoSuchElementException:
+ active: true
+ LateinitUsage:
+ active: false
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ excludeAnnotatedProperties: ""
+ ignoreOnClassesPattern: ""
+ MissingWhenCase:
+ active: true
+ RedundantElseInWhen:
+ active: true
+ UnconditionalJumpStatementInLoop:
+ active: false
+ UnreachableCode:
+ active: true
+ UnsafeCallOnNullableType:
+ active: true
+ UnsafeCast:
+ active: false
+ UselessPostfixExpression:
+ active: false
+ WrongEqualsTypeParameter:
+ active: true
+
+style:
+ active: true
+ CollapsibleIfStatements:
+ active: false
+ DataClassContainsFunctions:
+ active: false
+ conversionFunctionPrefix: 'to'
+ DataClassShouldBeImmutable:
+ active: false
+ EqualsNullCall:
+ active: true
+ EqualsOnSignatureLine:
+ active: false
+ ExplicitItLambdaParameter:
+ active: false
+ ExpressionBodySyntax:
+ active: false
+ includeLineWrapping: false
+ ForbiddenComment:
+ active: true
+ values: 'TODO:,FIXME:,STOPSHIP:'
+ allowedPatterns: ""
+ ForbiddenImport:
+ active: false
+ imports: ''
+ forbiddenPatterns: ""
+ ForbiddenVoid:
+ active: false
+ ignoreOverridden: false
+ ignoreUsageInGenerics: false
+ FunctionOnlyReturningConstant:
+ active: true
+ ignoreOverridableFunction: true
+ excludedFunctions: 'describeContents'
+ excludeAnnotatedFunction: "dagger.Provides"
+ LibraryCodeMustSpecifyReturnType:
+ active: true
+ LoopWithTooManyJumpStatements:
+ active: true
+ maxJumpCount: 1
+ MagicNumber:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ ignoreNumbers: '-1,0,1,2'
+ ignoreHashCodeFunction: true
+ ignorePropertyDeclaration: false
+ ignoreLocalVariableDeclaration: false
+ ignoreConstantDeclaration: true
+ ignoreCompanionObjectPropertyDeclaration: true
+ ignoreAnnotation: false
+ ignoreNamedArgument: true
+ ignoreEnums: false
+ ignoreRanges: false
+ MandatoryBracesIfStatements:
+ active: false
+ MaxLineLength:
+ active: true
+ maxLineLength: 120
+ excludePackageStatements: true
+ excludeImportStatements: true
+ excludeCommentStatements: false
+ MayBeConst:
+ active: true
+ ModifierOrder:
+ active: true
+ NestedClassesVisibility:
+ active: false
+ NewLineAtEndOfFile:
+ active: true
+ NoTabs:
+ active: false
+ OptionalAbstractKeyword:
+ active: true
+ OptionalUnit:
+ active: false
+ OptionalWhenBraces:
+ active: false
+ PreferToOverPairSyntax:
+ active: false
+ ProtectedMemberInFinalClass:
+ active: true
+ RedundantExplicitType:
+ active: false
+ RedundantVisibilityModifierRule:
+ active: false
+ ReturnCount:
+ active: true
+ max: 2
+ excludedFunctions: "equals"
+ excludeLabeled: false
+ excludeReturnFromLambda: true
+ excludeGuardClauses: false
+ SafeCast:
+ active: true
+ SerialVersionUIDInSerializableClass:
+ active: false
+ SpacingBetweenPackageAndImports:
+ active: false
+ ThrowsCount:
+ active: true
+ max: 2
+ TrailingWhitespace:
+ active: false
+ UnderscoresInNumericLiterals:
+ active: false
+ acceptableDecimalLength: 5
+ UnnecessaryAbstractClass:
+ active: true
+ excludeAnnotatedClasses: "dagger.Module"
+ UnnecessaryApply:
+ active: false
+ UnnecessaryInheritance:
+ active: true
+ UnnecessaryLet:
+ active: false
+ UnnecessaryParentheses:
+ active: false
+ UntilInsteadOfRangeTo:
+ active: false
+ UnusedImports:
+ active: false
+ UnusedPrivateClass:
+ active: true
+ UnusedPrivateMember:
+ active: false
+ allowedNames: "(_|ignored|expected|serialVersionUID)"
+ UseArrayLiteralsInAnnotations:
+ active: false
+ UseCheckOrError:
+ active: false
+ UseDataClass:
+ active: false
+ excludeAnnotatedClasses: ""
+ allowVars: false
+ UseIfInsteadOfWhen:
+ active: false
+ UseRequire:
+ active: false
+ UselessCallOnNotNull:
+ active: true
+ UtilityClassWithPublicConstructor:
+ active: true
+ VarCouldBeVal:
+ active: false
+ WildcardImport:
+ active: true
+ excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
+ excludeImports: 'java.util.*,kotlinx.android.synthetic.*'
diff --git a/wrapper/src/main/java/it/unisannio/ding/ids/wedroid/wrapper/entity/BoardBackgroundColor.java b/wrapper/src/main/java/it/unisannio/ding/ids/wedroid/wrapper/entity/BoardBackgroundColor.java
index 32401d9..aee9e1c 100644
--- a/wrapper/src/main/java/it/unisannio/ding/ids/wedroid/wrapper/entity/BoardBackgroundColor.java
+++ b/wrapper/src/main/java/it/unisannio/ding/ids/wedroid/wrapper/entity/BoardBackgroundColor.java
@@ -10,7 +10,7 @@ public enum BoardBackgroundColor {
@SerializedName("pomegranate")
POMEGRANATE,
@SerializedName("pumpkin")
- PUMPIK,
+ PUMPKIN,
@SerializedName("wisteria")
WISTERIA,
@SerializedName("moderatepink")