diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..aa724b77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..7c2c7847 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +WikiSW - Luan \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..88ea3aa1 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,122 @@ + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..fb7f4a8a --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 00000000..6936ccd6 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000..625b3714 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 00000000..958a5bea --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..60e5be80 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index c0193b60..675d96c2 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ http://docs.starwarsfavorites.apiary.io/# Para obter os personagens, sua aplicação deverá utilizar o recurso `people` da Swapi (documentação disponível no topo do documento). A aplicação deve exibir todos os 87 personagens e permitir pesquisar o personagem pelo nome. Sugerimos exibir as primeiras páginas enquanto carrega as outras, em um formato de scroll infinito. A lista de itens deve exibir as seguintes informações: -+ Nome [name] -+ Altura [height] -+ Genero [gender] -+ Peso [mass] ++ Nome [name] OK ++ Altura [height] OK ++ Genero [gender] OK ++ Peso [mass] OK Os dados devem ser salvos em banco de dados local para acesso offline e atualizados sempre que a tela for aberta. @@ -26,37 +26,27 @@ Os dados devem ser salvos em banco de dados local para acesso offline e atualiza Ao clicar em um item da lista o seu app deve mostrar as informações abaixo: -+ name -+ height -+ mass -+ hair_color -+ skin_color -+ eye_color -+ birth_year -+ gender -+ Nome do Planeta Natal -+ Nome da Espécie ++ name OK ++ height OK ++ mass OK ++ hair_color OK ++ skin_color OK ++ eye_color OK ++ birth_year OK ++ gender OK ++ Nome do Planeta Natal OK ++ Nome da Espécie OK -A busca pelo nome do planeta e da espécie deve ser feita em paralelo. +A busca pelo nome do planeta e da espécie deve ser feita em paralelo. OK ### Favoritos -Na lista e nos detalhes deve ser possível adicionar e remover um personagem a sua lista de favoritos. Tambem deve ser possível filtrar quais personagens foram favoritados na lista principal. +Na lista e nos detalhes deve ser possível adicionar e remover um personagem a sua lista de favoritos. Tambem deve ser possível filtrar quais personagens foram favoritados na lista principal. OK -##### Adição e Remoção de Favoritos -URL BASE: http://private-782d3-starwarsfavorites.apiary-mock.com/ - -Ao adicionar um favorito a aplicação deve fazer um request para a api starwarsfavorites (documentação disponível no topo do documento). A aplicação deve: -+ Exibir a mensagem de retorno da API em caso de sucesso ou erro. -+ Reenviar a requisição da próxima vez que o app for aberto em caso de erro. -+ Salvar no banco de dados local quais personagens foram favoritados. -+ Tratar a remoção de favoritos apenas no banco de dados local. - -Em metade das requisições enviadas para a api starwarsfavorites a aplicação deve adicionar o header `Prefer` com o valor `status=400`. - -P.S.: O candidato deve escolher o ID. ++ Salvar no banco de dados local quais personagens foram favoritados. OK ++ Tratar a remoção de favoritos apenas no banco de dados local. OK --- #### LICENSE diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 00000000..8b4ce9e6 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-parcelize' + id 'kotlin-kapt' +} + +android { + compileSdkVersion 30 + + viewBinding { + enabled = true + } + + defaultConfig { + applicationId "com.knowledge.wikisw_luan" + minSdkVersion 21 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + def room_version = "2.3.0" + def lifecycle_version = "2.3.1" + + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.core:core-ktx:1.3.2' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'com.squareup.retrofit2:retrofit:2.5.0' + implementation 'com.google.code.gson:gson:2.8.7' + implementation "io.insert-koin:koin-android:$koin_version" + implementation "io.insert-koin:koin-androidx-scope:$koin_version" + implementation "io.insert-koin:koin-androidx-viewmodel:$koin_version" + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' + implementation "androidx.room:room-runtime:$room_version" + kapt "androidx.room:room-compiler:$room_version" + kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" + implementation "com.squareup.retrofit2:converter-gson:2.9.0" + implementation "androidx.room:room-ktx:$room_version" + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/knowledge/wikisw_luan/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/knowledge/wikisw_luan/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..01ce8b79 --- /dev/null +++ b/app/src/androidTest/java/com/knowledge/wikisw_luan/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.knowledge.wikisw_luan + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.knowledge.wikisw_luan", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..6b66b6b9 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/SwApplication.kt b/app/src/main/java/com/knowledge/wikisw_luan/SwApplication.kt new file mode 100644 index 00000000..2b3de098 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/SwApplication.kt @@ -0,0 +1,20 @@ +package com.knowledge.wikisw_luan + +import android.app.Application +import com.knowledge.wikisw_luan.data.cache.CharacterData +import com.knowledge.wikisw_luan.di.Modules +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.startKoin + +class SwApplication : Application() { + override fun onCreate() { + super.onCreate() + CharacterData.initDb(applicationContext) + startKoin { + androidLogger() + androidContext(this@SwApplication) + modules(arrayListOf(Modules.swModule)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/activity/CharActivity.kt b/app/src/main/java/com/knowledge/wikisw_luan/activity/CharActivity.kt new file mode 100644 index 00000000..e033243f --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/activity/CharActivity.kt @@ -0,0 +1,79 @@ +package com.knowledge.wikisw_luan.activity + +import android.graphics.Color +import android.os.Bundle +import android.widget.ImageView +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import com.knowledge.wikisw_luan.R +import com.knowledge.wikisw_luan.databinding.CharInfoBinding +import com.knowledge.wikisw_luan.models.CharacterModel +import org.koin.androidx.viewmodel.ext.android.viewModel + +class CharActivity : AppCompatActivity() { + + private lateinit var binding: CharInfoBinding + private val charViewModel: CharViewModel by viewModel() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.char_info) + charViewModel.state.observe(this@CharActivity, {handleState(it)}) + + val charInfo = intent.getParcelableExtra("CharInfo") as? CharacterModel + binding = CharInfoBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + charInfo?.let { + binding.swName.text = it.name + binding.swHeight.text = "Altura: ${it.height}" + binding.swGender.text = "Gênero: ${it.gender}" + binding.swMass.text = "Massa corpórea: ${it.mass}" + binding.swHair.text = "Cor do cabelo: ${it.hairColor}" + binding.swSkin.text = "Cor da pele: ${it.skinColor}" + binding.swEye.text = "Cor dos olhos: ${it.eyeColor}" + binding.swBday.text = "Ano de nascimento: ${it.birthYear}" + binding.swHome.text = "Planeta de origem: ${it.homeWorld}" + binding.swSpecie.text = "Espécie: ${it.species}" + if (it.speciesId.isNotEmpty()) { + charViewModel.getSpecies(it.speciesId) + } else { + binding.swSpecie.text = "Espécie não localizada." + } + if (it.homeWorldId.isNotEmpty()) { + charViewModel.getPlanets(it.homeWorldId) + } else { + binding.swHome.text = "Planeta não localizado." + } + + + binding.swFavorite.setOnClickListener { _ -> + it.isFavorite = !it.isFavorite + charViewModel.getFav(it.name, it.isFavorite) + if (it.isFavorite){ + binding.swFavorite.setColorFilter(Color.RED) + } else { + binding.swFavorite.setColorFilter(Color.GRAY) + } + } + + if (it.isFavorite){ + binding.swFavorite.setColorFilter(Color.RED) + } else { + binding.swFavorite.setColorFilter(Color.GRAY) + } + } + } + private fun handleState(state: Any) { + when (state) { + is SwState.ShowSpecieName -> { + binding.swSpecie.text = "Raça: ${state.specieName}" + + } +// is SwState.ShowPlanetName -> { +// binding.swSpecie.text = "Planeta natal: ${state.planetName}" +// } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/activity/CharViewModel.kt b/app/src/main/java/com/knowledge/wikisw_luan/activity/CharViewModel.kt new file mode 100644 index 00000000..cfc36aca --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/activity/CharViewModel.kt @@ -0,0 +1,39 @@ +package com.knowledge.wikisw_luan.activity + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.knowledge.wikisw_luan.data.repository.SwRepository +import kotlinx.coroutines.launch + +class CharViewModel(private val repository: SwRepository) : ViewModel() { + private val _state: MutableLiveData = MutableLiveData() + val state: MutableLiveData get() = _state + fun getPlanets(planetId: String) { + viewModelScope.launch { + try { + val planet = repository.getPlanets(planetId) + _state.value = SwState.ShowPlanetName(planet) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + fun getSpecies(speciesId: String) { + viewModelScope.launch { + try { + val specieName = repository.getSpecies(speciesId) + _state.value = SwState.ShowSpecieName(specieName) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + fun getFav(charId: String, isFavorite: Boolean) { + viewModelScope.launch { + repository.getFav(charId, isFavorite) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/activity/MainActivity.kt b/app/src/main/java/com/knowledge/wikisw_luan/activity/MainActivity.kt new file mode 100644 index 00000000..968bb0d3 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/activity/MainActivity.kt @@ -0,0 +1,89 @@ +package com.knowledge.wikisw_luan.activity + +import android.content.Intent +import android.os.Bundle +import android.widget.ImageView +import android.widget.SearchView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import com.knowledge.wikisw_luan.R +import com.knowledge.wikisw_luan.activity.SwState.ShowCharacters +import com.knowledge.wikisw_luan.adapter.Adapter +import com.knowledge.wikisw_luan.adapter.ClickWikiListener +import com.knowledge.wikisw_luan.databinding.ActivityMainBinding +import com.knowledge.wikisw_luan.databinding.CharInfoBinding +import com.knowledge.wikisw_luan.models.CharacterModel +import org.koin.androidx.viewmodel.ext.android.viewModel + +class MainActivity : AppCompatActivity(), ClickWikiListener { + + val adapter = Adapter(listener = this) + val listchar = arrayListOf() + val mainViewModel: MainViewModel by viewModel() + private lateinit var binding: ActivityMainBinding + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) + + mainViewModel.state.observe(this@MainActivity, {handleState(it)}) + val characterList = listchar + var showFavorite = false + adapter.updateList(characterList) + binding.rvSw.adapter = adapter + binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(text: String?): Boolean { + return true + } + + override fun onQueryTextChange(text: String?): Boolean { + if (text != null) { + adapter.updateList(characterList.filter { it.name.contains(text, true) }) + } else { + adapter.updateList(characterList) + } + return true + } + }) + binding.searchView.setOnClickListener { binding.searchView.onActionViewExpanded() } + binding.filterButton.setOnClickListener { + showFavorite = !showFavorite + if (showFavorite) { + adapter.updateList(characterList.filter { it.isFavorite }) + } else { + adapter.updateList(characterList) + } + } + } + + override fun onResume() { + super.onResume() + mainViewModel.getCharacters() + } + + private fun handleState(state: Any) { + when (state) { + is ShowCharacters -> { + listchar.clear() + listchar.addAll(state.list) + adapter.updateList(state.list) + } + } + + } + + override fun onListClick(character: CharacterModel) { + val charInfo = Intent(this, CharActivity::class.java) + charInfo.putExtra("CharInfo", character) + startActivity(charInfo) + } + + override fun onFavClick(character: CharacterModel) { + mainViewModel.getFav(character.name, character.isFavorite) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/activity/MainViewModel.kt b/app/src/main/java/com/knowledge/wikisw_luan/activity/MainViewModel.kt new file mode 100644 index 00000000..b35a2c90 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/activity/MainViewModel.kt @@ -0,0 +1,29 @@ +package com.knowledge.wikisw_luan.activity + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.knowledge.wikisw_luan.data.repository.SwRepository +import kotlinx.coroutines.launch + +class MainViewModel(private val repository: SwRepository) : ViewModel() { + private val _state: MutableLiveData = MutableLiveData() + val state: MutableLiveData get() = _state + fun getCharacters() { + viewModelScope.launch { + val local = repository.getLocal() + if (local.isNotEmpty()) { + _state.postValue(SwState.ShowCharacters(local)) + } else { + val list = repository.getCharacters() + _state.postValue(SwState.ShowCharacters(list)) + } + } + } + + fun getFav(charId: String, isFavorite: Boolean) { + viewModelScope.launch { + repository.getFav(charId, isFavorite) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/activity/SwState.kt b/app/src/main/java/com/knowledge/wikisw_luan/activity/SwState.kt new file mode 100644 index 00000000..42a7d8ba --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/activity/SwState.kt @@ -0,0 +1,10 @@ +package com.knowledge.wikisw_luan.activity + +import com.knowledge.wikisw_luan.models.CharacterModel + +sealed class SwState { + class ShowCharacters(val list: List) : SwState() + class ShowSpecieName(val specieName: String) : SwState() + class ShowPlanetName(val planetName: String) : SwState() + +} diff --git a/app/src/main/java/com/knowledge/wikisw_luan/adapter/Adapter.kt b/app/src/main/java/com/knowledge/wikisw_luan/adapter/Adapter.kt new file mode 100644 index 00000000..903b4cfb --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/adapter/Adapter.kt @@ -0,0 +1,78 @@ +package com.knowledge.wikisw_luan.adapter + +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.recyclerview.widget.RecyclerView +import com.knowledge.wikisw_luan.R +import com.knowledge.wikisw_luan.models.CharacterModel + +class Adapter( + private val listener: ClickWikiListener +) : RecyclerView.Adapter() { + + private var characters: List = listOf() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CharViewHolder { + val layoutInflater = LayoutInflater.from(parent.context) + val view = layoutInflater.inflate(R.layout.char_item, parent, false) + return CharViewHolder(view) + } + + override fun onBindViewHolder(holder: CharViewHolder, position: Int) { + holder.bind(characters[position]) + } + + override fun getItemCount(): Int { + return characters.size + } + + fun updateList(list: List) { + characters = list + notifyDataSetChanged() + } + + inner class CharViewHolder(itemView: View) : + RecyclerView.ViewHolder(itemView) { + + private val swName = itemView.findViewById(R.id.sw_name) + private val swHeight = itemView.findViewById(R.id.sw_height) + private val swGender = itemView.findViewById(R.id.sw_gender) + private val swMass = itemView.findViewById(R.id.sw_mass) + private val swConstraint = itemView.findViewById(R.id.sw_container) + private val swFav = itemView.findViewById(R.id.sw_fav) + + fun bind(data: CharacterModel) { + with(itemView) { + swConstraint.setOnClickListener { + listener.onListClick(data) + } + + swFav.setOnClickListener { + data.isFavorite = !data.isFavorite + listener.onFavClick(data) + if (data.isFavorite){ + swFav.setColorFilter(Color.RED) + } else { + swFav.setColorFilter(Color.GRAY) + } + } + + swName.text = data.name + swHeight.text = "Altura: ${data.height}" + swGender.text = "Gênero: ${data.gender}" + swMass.text = "Peso: ${data.mass}" + if (data.isFavorite){ + swFav.setColorFilter(Color.RED) + } else { + swFav.setColorFilter(Color.GRAY) + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/adapter/ClickWikiListener.kt b/app/src/main/java/com/knowledge/wikisw_luan/adapter/ClickWikiListener.kt new file mode 100644 index 00000000..3712d046 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/adapter/ClickWikiListener.kt @@ -0,0 +1,11 @@ +package com.knowledge.wikisw_luan.adapter + +import com.knowledge.wikisw_luan.models.CharacterModel + +interface ClickWikiListener { + + fun onListClick(character: CharacterModel) + + fun onFavClick(character: CharacterModel) + +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/SwAPI.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/SwAPI.kt new file mode 100644 index 00000000..2438d766 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/SwAPI.kt @@ -0,0 +1,18 @@ +package com.knowledge.wikisw_luan.data + +import com.knowledge.wikisw_luan.data.models.BasicResponse +import com.knowledge.wikisw_luan.data.models.SwResponse +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface SwAPI { + @GET("people") + suspend fun getCharacters(@Query("page") page: Int): SwResponse + + @GET("species/{id}/") + suspend fun getSpecies(@Path("id") id: Int): BasicResponse + + @GET("planets/{id}/") + suspend fun getPlanet(@Path("id") id: Int): BasicResponse +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/SwCloud.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/SwCloud.kt new file mode 100644 index 00000000..88db3b95 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/SwCloud.kt @@ -0,0 +1,21 @@ +package com.knowledge.wikisw_luan.data + +import com.knowledge.wikisw_luan.data.models.BasicResponse +import com.knowledge.wikisw_luan.data.models.SwResponse + +class SwCloud( + private val api: SwAPI +) { + suspend fun getCharacters(page: Int): SwResponse { + return api.getCharacters(page) + } + + suspend fun getSpecies(id: Int): BasicResponse { + return api.getSpecies(id) + } + + suspend fun getPlanet(id: Int): BasicResponse { + return api.getPlanet(id) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterDAO.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterDAO.kt new file mode 100644 index 00000000..d8946839 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterDAO.kt @@ -0,0 +1,28 @@ +package com.knowledge.wikisw_luan.data.cache + +import androidx.room.* + +@Dao +interface CharacterDAO { + @Query("SELECT * FROM sw_chars") + fun getAll(): List + + @Query("SELECT * FROM sw_chars where cid == (:id)") + fun loadCharacterById(id: String): CharacterEntity + + @Query("UPDATE sw_chars SET specie = :specie WHERE specie_id == (:id)") + fun update(specie: String, id: String) + + @Query("UPDATE sw_chars SET planet = :planet WHERE planet_id == (:id)") + fun updatePlanet(planet: String, id: String) + + @Query("UPDATE sw_chars SET favorite = :favorite WHERE cid == (:id)") + fun updateFavorite(favorite: Boolean, id: String) + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insertAll(a: List) + + @Update(onConflict = OnConflictStrategy.IGNORE) + fun update(fav: CharacterEntity) + +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterData.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterData.kt new file mode 100644 index 00000000..7b5d3968 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterData.kt @@ -0,0 +1,14 @@ +package com.knowledge.wikisw_luan.data.cache + +import android.content.Context +import androidx.room.Room + +object CharacterData { + lateinit var db: CharacterDatabase + fun initDb(applicationContext: Context) { + db = Room.databaseBuilder( + applicationContext, + CharacterDatabase::class.java, "sw-db" + ).allowMainThreadQueries().build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterDatabase.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterDatabase.kt new file mode 100644 index 00000000..cf15cb59 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterDatabase.kt @@ -0,0 +1,9 @@ +package com.knowledge.wikisw_luan.data.cache + +import androidx.room.Database +import androidx.room.RoomDatabase + +@Database(entities = [CharacterEntity::class], version = 1) +abstract class CharacterDatabase : RoomDatabase() { + abstract fun charDao(): CharacterDAO +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterEntity.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterEntity.kt new file mode 100644 index 00000000..9d8a1b3f --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/cache/CharacterEntity.kt @@ -0,0 +1,24 @@ +package com.knowledge.wikisw_luan.data.cache + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "sw_chars") +data class CharacterEntity( + + @PrimaryKey val cid: String, + @ColumnInfo(name = "name") val name: String, + @ColumnInfo(name = "mass") val mass: String, + @ColumnInfo(name = "height") val height: String, + @ColumnInfo(name = "hair_color") val hairColor: String, + @ColumnInfo(name = "skin_color") val skinColor: String, + @ColumnInfo(name = "eye_color") val eyeColor: String, + @ColumnInfo(name = "birth_year") val birthYear: String, + @ColumnInfo(name = "gender") val gender: String, + @ColumnInfo(name = "specie") var specie: String?, + @ColumnInfo(name = "specie_id") var specieId: String?, + @ColumnInfo(name = "planet") var homeworld: String?, + @ColumnInfo(name = "planet_id") var homeworldId: String?, + @ColumnInfo(name = "favorite") var isFavorite: Boolean +) \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/mapper/SwMapper.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/mapper/SwMapper.kt new file mode 100644 index 00000000..c080d356 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/mapper/SwMapper.kt @@ -0,0 +1,67 @@ +package com.knowledge.wikisw_luan.data.mapper + +import com.knowledge.wikisw_luan.data.cache.CharacterEntity +import com.knowledge.wikisw_luan.data.models.CharacterResponse +import com.knowledge.wikisw_luan.models.CharacterModel + +object SwMapper { + + fun characterResponseToEntity(response: List, planet: String, specie: String, isFavorite: Boolean): List { + return response.map { characterResponseToEntity(it, "", "", false) } + + } + + fun characterResponseToEntity(response: CharacterResponse, planet: String, specie: String, isFavorite: Boolean): CharacterEntity { + + val specieId = if (response.species.isEmpty()) { + "" + } else { + response.species[0] + } + + return CharacterEntity( + name = response.name, + mass = response.mass, + height = response.height, + hairColor = response.hairColor, + skinColor = response.skinColor, + eyeColor = response.eyeColor, + birthYear = response.birthYear, + gender = response.gender, + homeworldId = response.homeworld, + specieId = specieId, + homeworld = "", + specie = "", + cid = response.name, + isFavorite = isFavorite + + ) + + } + + fun characterEntityToModel(entity: List) : List { + return entity.map { characterEntityToModel(it) } + } + + fun characterEntityToModel(entity: CharacterEntity) : CharacterModel { + return CharacterModel( + name = entity.name, + mass = entity.mass, + height = entity.height, + hairColor = entity.hairColor, + skinColor = entity.skinColor, + eyeColor = entity.eyeColor, + birthYear = entity.birthYear, + gender = entity.gender, + homeWorld = entity.homeworld ?: "Planeta não informado", + homeWorldId = entity.homeworldId.orEmpty(), + speciesId = entity.specieId.orEmpty(), + species = entity.specie ?: "Raça não informada", + isFavorite = entity.isFavorite + + ) + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/models/BasicResponse.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/models/BasicResponse.kt new file mode 100644 index 00000000..dd310041 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/models/BasicResponse.kt @@ -0,0 +1,5 @@ +package com.knowledge.wikisw_luan.data.models + +data class BasicResponse( + val name: String +) diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/models/CharacterResponse.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/models/CharacterResponse.kt new file mode 100644 index 00000000..628bd3bf --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/models/CharacterResponse.kt @@ -0,0 +1,16 @@ +package com.knowledge.wikisw_luan.data.models + +import com.google.gson.annotations.SerializedName + +data class CharacterResponse( + val name: String, + val mass: String, + val height: String, + @SerializedName("hair_color") val hairColor: String, + @SerializedName("skin_color") val skinColor: String, + @SerializedName("eye_color") val eyeColor: String, + @SerializedName("birth_year") val birthYear: String, + val gender: String, + val homeworld: String, + val species: List +) diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/models/SwResponse.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/models/SwResponse.kt new file mode 100644 index 00000000..e92bd8c0 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/models/SwResponse.kt @@ -0,0 +1,6 @@ +package com.knowledge.wikisw_luan.data.models + +data class SwResponse( + val results: List, + val next: String? +) diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/repository/FavAPI.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/repository/FavAPI.kt new file mode 100644 index 00000000..30ca96c2 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/repository/FavAPI.kt @@ -0,0 +1,10 @@ +package com.knowledge.wikisw_luan.data.repository + +import retrofit2.http.Headers +import retrofit2.http.POST + +interface FavAPI { + @Headers("prefer: status=400") + @POST("favorite/{id}") + suspend fun getWilson() +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/data/repository/SwRepository.kt b/app/src/main/java/com/knowledge/wikisw_luan/data/repository/SwRepository.kt new file mode 100644 index 00000000..d408a3f8 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/data/repository/SwRepository.kt @@ -0,0 +1,52 @@ +package com.knowledge.wikisw_luan.data.repository + +import com.knowledge.wikisw_luan.data.SwCloud +import com.knowledge.wikisw_luan.data.cache.CharacterDAO +import com.knowledge.wikisw_luan.data.mapper.SwMapper +import com.knowledge.wikisw_luan.models.CharacterModel + +class SwRepository( + private val cloud: SwCloud, private val cache: CharacterDAO +) { + + var page: Int = 1 + + suspend fun getCharacters(): List { + val response = cloud.getCharacters(page) + cache.insertAll(SwMapper.characterResponseToEntity(response.results, "", "", false)) + page++ + if (!response.next.isNullOrEmpty()) { + getCharacters() + } + return SwMapper.characterEntityToModel(cache.getAll()) + } + + suspend fun getLocal(): List { + val local = cache.getAll() + return if (local.isNotEmpty()) { + SwMapper.characterEntityToModel(local) + } else { + arrayListOf() + } + } + + suspend fun getPlanets(planetsId: String): String { + val response = cloud.getPlanet(getInt(planetsId)) + cache.updatePlanet(response.name, planetsId) + return response.name + } + + suspend fun getSpecies(speciesId: String): String { + val response = cloud.getSpecies(getInt(speciesId)) + cache.update(response.name, speciesId) + return response.name + } + + private fun getInt(id: String): Int { + return id.filter { it.isDigit() }.toInt() + } + + fun getFav(id: String, favorite: Boolean) { + cache.updateFavorite(favorite, id) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/di/Modules.kt b/app/src/main/java/com/knowledge/wikisw_luan/di/Modules.kt new file mode 100644 index 00000000..67059116 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/di/Modules.kt @@ -0,0 +1,44 @@ +package com.knowledge.wikisw_luan.di + +import androidx.room.Room +import com.google.gson.GsonBuilder +import com.knowledge.wikisw_luan.activity.CharViewModel +import com.knowledge.wikisw_luan.activity.MainViewModel +import com.knowledge.wikisw_luan.data.SwAPI +import com.knowledge.wikisw_luan.data.SwCloud +import com.knowledge.wikisw_luan.data.cache.CharacterData +import com.knowledge.wikisw_luan.data.cache.CharacterDatabase +import com.knowledge.wikisw_luan.data.repository.FavAPI +import com.knowledge.wikisw_luan.data.repository.SwRepository +import okhttp3.OkHttpClient +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.create + +object Modules { + val swModule = module { + single { + Retrofit.Builder() + .baseUrl("https://swapi.dev/api/") + .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())) + .client(OkHttpClient.Builder().build()) + .build() + .create(SwAPI::class.java) + } + single { + Retrofit.Builder() + .baseUrl("http://private-782d3-starwarsfavorites.apiary-mock.com/") + .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())) + .client(OkHttpClient.Builder().build()) + .build() + .create(FavAPI::class.java) + } + single { SwCloud(get()) } + single { SwRepository(get(), CharacterData.db.charDao()) } + viewModel { MainViewModel(get()) } + viewModel { CharViewModel(get()) } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/knowledge/wikisw_luan/models/CharacterModel.kt b/app/src/main/java/com/knowledge/wikisw_luan/models/CharacterModel.kt new file mode 100644 index 00000000..36305469 --- /dev/null +++ b/app/src/main/java/com/knowledge/wikisw_luan/models/CharacterModel.kt @@ -0,0 +1,21 @@ +package com.knowledge.wikisw_luan.models + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class CharacterModel( + val name: String, + val mass: String, + val height: String, + val hairColor: String, + val skinColor: String, + val eyeColor: String, + val birthYear: String, + val gender: String, + val homeWorld: String, + val homeWorldId: String, + val species: String, + val speciesId: String, + var isFavorite: Boolean = false +) : Parcelable diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic__47674.xml b/app/src/main/res/drawable/ic__47674.xml new file mode 100644 index 00000000..3dbfa0c2 --- /dev/null +++ b/app/src/main/res/drawable/ic__47674.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic__64516.xml b/app/src/main/res/drawable/ic__64516.xml new file mode 100644 index 00000000..c62c89d6 --- /dev/null +++ b/app/src/main/res/drawable/ic__64516.xml @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_sithjedi.xml b/app/src/main/res/drawable/ic_sithjedi.xml new file mode 100644 index 00000000..09660235 --- /dev/null +++ b/app/src/main/res/drawable/ic_sithjedi.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..8d5ae402 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,42 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/char_info.xml b/app/src/main/res/layout/char_info.xml new file mode 100644 index 00000000..c4be4963 --- /dev/null +++ b/app/src/main/res/layout/char_info.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/char_item.xml b/app/src/main/res/layout/char_item.xml new file mode 100644 index 00000000..6b3aa2e4 --- /dev/null +++ b/app/src/main/res/layout/char_item.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..a571e600 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..61da551c Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..c41dd285 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..db5080a7 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..6dba46da Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..da31a871 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..15ac6817 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..b216f2d3 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..f25a4197 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e96783cc Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 00000000..a7463a67 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,18 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..9ce18290 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,12 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #616161 + #FF0000 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..fe540011 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + WikiSW - Luan + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 00000000..997b12f9 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,18 @@ + + + + \ No newline at end of file diff --git a/app/src/test/java/com/knowledge/wikisw_luan/ExampleUnitTest.kt b/app/src/test/java/com/knowledge/wikisw_luan/ExampleUnitTest.kt new file mode 100644 index 00000000..4be619d4 --- /dev/null +++ b/app/src/test/java/com/knowledge/wikisw_luan/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.knowledge.wikisw_luan + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..cf69c0c5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,30 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = "1.4.32" + ext.koin_version = "2.0.1" + repositories { + google() + mavenCentral() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.0.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + maven { url 'https://jitpack.io' } + jcenter() // Warning: this repository is going to shut down soon + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..25217527 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..f6b961fd Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..df94db4c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon May 31 19:34:16 BRT 2021 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..cccdd3d5 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..f9553162 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..f076ed21 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = "WikiSW - Luan" +include ':app'