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..7e70c687 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Star Wars \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..7643783a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,123 @@ + + + + + + + + + + \ 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..61a9130c --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..e465fd63 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000..b617266a --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 00000000..a5f05cd8 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..d5d35ec4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /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..54983a27 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,28 @@ -# Desafio Android +# Star Wars -O desafio consiste em criar uma Wiki de Star Wars onde é mostrada uma lista de personagens e o usuário pode favoritar alguns deles. É recomendado a utilização de Kotlin ou Java no projeto. +# Sobre o projeto -O candidato deve dar **fork** neste repositório e após o termino do desenvolvimento, realizar um **pull request** para análise do time. Em casos especiais o candidato tambem pode enviar o projeto compactado para hugo@popcode.com.br. Prefira vários commits durante o projeto invés de um unico commit no final. +O projeto consiste em listar os personagens da franquia de Star Wars e verificar os detalhes de cada um. -A documentação das APIs que serão utilizadas no desafio estão disponíveis nos links abaixo: +## Layout mobile + -http://swapi.dev/ +# Funcionalidades Implementadas +- Lista de personagens +- Pesquisa do personagem pelo nome +- Dados salvos no banco local para acesso offline +- Detalhes do personagem -http://docs.starwarsfavorites.apiary.io/# +# Tecnologias utilizadas -### Lista de Personagens +## Back-end +- Kotlin -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. +## Recursos +- Fragment +- ViewPager +- SharedPreferences +- Retrofit +- Room -A lista de itens deve exibir as seguintes informações: -+ Nome [name] -+ Altura [height] -+ Genero [gender] -+ Peso [mass] -Os dados devem ser salvos em banco de dados local para acesso offline e atualizados sempre que a tela for aberta. - -### Detalhes do Personagem - -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 - -A busca pelo nome do planeta e da espécie deve ser feita em paralelo. - -### 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. - -##### 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. - ---- -#### LICENSE -``` -MIT License - -Copyright (c) 2017 Popcode Mobile Solutions - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -``` 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..f214cd77 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,73 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-android-extensions' + id 'kotlin-kapt' +} + +android { + compileSdkVersion 29 + buildToolsVersion "30.0.3" + + defaultConfig { + applicationId "com.example.starwars" + minSdkVersion 21 + targetSdkVersion 29 + 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 { + + 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.2.1' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + + //Legacy + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + + //Navigation Fragment + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.2' + + // Retrofit + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.6.0' + + // Room components + implementation "androidx.room:room-runtime:2.2.5" + kapt "androidx.room:room-compiler:2.2.5" + implementation "androidx.room:room-ktx:2.2.5" + androidTestImplementation "androidx.room:room-testing:2.2.5" + + // Lifecycle components + implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" + implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" + + + //ViewPager2 + implementation 'androidx.viewpager2:viewpager2:1.0.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/example/starwars/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/starwars/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..b0292c14 --- /dev/null +++ b/app/src/androidTest/java/com/example/starwars/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.starwars + +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.example.starwars", 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..331f8545 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/adapter/PeopleAdapter.kt b/app/src/main/java/com/example/starwars/adapter/PeopleAdapter.kt new file mode 100644 index 00000000..f23ba3a5 --- /dev/null +++ b/app/src/main/java/com/example/starwars/adapter/PeopleAdapter.kt @@ -0,0 +1,108 @@ +package com.example.starwars.adapter + +import android.content.Intent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Filter +import android.widget.Filterable +import androidx.recyclerview.widget.RecyclerView +import com.example.starwars.R +import com.example.starwars.data.room.ResultEntity +import com.example.starwars.presentation.view.Detalhes +import kotlinx.android.synthetic.main.custom_row_people.view.* +import java.util.* + +class PeopleAdapter : RecyclerView.Adapter(), Filterable { + + //Atribudos a serem utilizados no detalhe do personagem + companion object { + var nameCompanion: String = "" + var heightCompanion: String = "" + var genderCompanion: String = "" + var massCompanion: String = "" + var hair_colorCompanion: String = "" + var skin_colorCompanion: String = "" + var eye_colorCompanion: String = "" + var birth_yearCompanion: String = "" + + } + + //Declara uma Lista vazia + private var myListResults = emptyList() + + //Lista Auxiliar + private var listFilter = emptyList() + + inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.custom_row_people, parent, false) + ) + } + + //Retorna quantidade da lista + override fun getItemCount(): Int { + return listFilter.size + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + val context = holder.itemView.context + val currentItem = listFilter[position] + holder.itemView.textName.text = "Nome: " + currentItem.name + holder.itemView.textHeight.text = "Altura: " + currentItem.height + holder.itemView.textGender.text = "Genero: " + currentItem.gender + holder.itemView.textMass.text = "Peso: " + currentItem.mass + + holder.itemView.custom_row.setOnClickListener { + nameCompanion = currentItem.name + heightCompanion = currentItem.height + genderCompanion = currentItem.gender + massCompanion = currentItem.mass + hair_colorCompanion = currentItem.hair_color + skin_colorCompanion = currentItem.skin_color + eye_colorCompanion = currentItem.eye_color + birth_yearCompanion = currentItem.birth_year + + context.startActivity(Intent(holder.itemView.context, Detalhes::class.java)) + + } + } + + fun setData(newList: List) { + this.myListResults = myListResults + newList + listFilter = myListResults + notifyDataSetChanged() + } + + //Responsavel por filtrar e pesquisar um dado + override fun getFilter(): Filter { + return object : Filter() { + override fun performFiltering(p0: CharSequence?): FilterResults { + val charSearch = p0.toString() + if (charSearch.isEmpty()) { + listFilter = myListResults + } else { + val resultList = mutableListOf() + for (row in myListResults) { + if (row.name.toLowerCase(Locale.ROOT) + .contains(charSearch.toLowerCase(Locale.ROOT)) + ) { + resultList.add(row) + } + } + listFilter = resultList + } + val filterResults = FilterResults() + filterResults.values = listFilter + return filterResults + } + + override fun publishResults(p0: CharSequence?, p1: FilterResults?) { + listFilter = p1?.values as MutableList + notifyDataSetChanged() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/data/api/MyInterceptor.kt b/app/src/main/java/com/example/starwars/data/api/MyInterceptor.kt new file mode 100644 index 00000000..e3a9f3ca --- /dev/null +++ b/app/src/main/java/com/example/starwars/data/api/MyInterceptor.kt @@ -0,0 +1,17 @@ +package com.example.starwars.data.api + +import okhttp3.Interceptor +import okhttp3.Response + +class MyInterceptor : Interceptor { + //Insere valores de headers + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + .newBuilder() + .addHeader("Content-Type", "application/json") + .addHeader("X-Platform", "Android") + .addHeader("X-Auth-Token", "123456789") + .build() + return chain.proceed(request) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/data/api/RetrofitInstance.kt b/app/src/main/java/com/example/starwars/data/api/RetrofitInstance.kt new file mode 100644 index 00000000..06cb68ae --- /dev/null +++ b/app/src/main/java/com/example/starwars/data/api/RetrofitInstance.kt @@ -0,0 +1,27 @@ +package com.example.starwars.data.api + +import com.example.starwars.util.Constants.Companion.BASE_URL +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +object RetrofitInstance { + + private val client = OkHttpClient.Builder().apply { + addInterceptor(MyInterceptor()) + }.build() + + // Captura o link da Api + private val retrofit by lazy { + Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build() + } + + // Inicializa a Api + val api: SimpleApi by lazy { + retrofit.create(SimpleApi::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/data/api/SimpleApi.kt b/app/src/main/java/com/example/starwars/data/api/SimpleApi.kt new file mode 100644 index 00000000..4e8078ca --- /dev/null +++ b/app/src/main/java/com/example/starwars/data/api/SimpleApi.kt @@ -0,0 +1,16 @@ +package com.example.starwars.data.api + +import com.example.starwars.model.People +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface SimpleApi { + + //Endpoint Listar Personagens + @GET("people") + suspend fun getPeople( + @Query("page") page: String + ): Response + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/data/room/ResultDao.kt b/app/src/main/java/com/example/starwars/data/room/ResultDao.kt new file mode 100644 index 00000000..30546843 --- /dev/null +++ b/app/src/main/java/com/example/starwars/data/room/ResultDao.kt @@ -0,0 +1,16 @@ +package com.example.starwars.data.room + +import androidx.lifecycle.LiveData +import androidx.room.* + +@Dao +interface ResultDao { + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun addResult(result: ResultEntity) + + @Query("DELETE FROM result_table") + suspend fun deleteAllResults() + + @Query("SELECT * FROM result_table ORDER BY id ASC") + fun readAllData(): LiveData> // Captura todos os dados da Entidade que esta no db +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/data/room/ResultDatabase.kt b/app/src/main/java/com/example/starwars/data/room/ResultDatabase.kt new file mode 100644 index 00000000..8e1db820 --- /dev/null +++ b/app/src/main/java/com/example/starwars/data/room/ResultDatabase.kt @@ -0,0 +1,34 @@ +package com.example.starwars.data.room + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database(entities = [ResultEntity::class], version = 1, exportSchema = false) +abstract class ResultDatabase : RoomDatabase() { + + //Cria o Database + abstract fun resultDao(): ResultDao + + companion object { + @Volatile + private var INSTANCE: ResultDatabase? = null + + fun getDatabase(context: Context): ResultDatabase { + val tempInstance = INSTANCE + if (tempInstance != null) { + return tempInstance + } + synchronized(this) { + val instance = Room.databaseBuilder( + context.applicationContext, + ResultDatabase::class.java, + "result_base" + ).build() + INSTANCE = instance + return instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/data/room/ResultEntity.kt b/app/src/main/java/com/example/starwars/data/room/ResultEntity.kt new file mode 100644 index 00000000..55334973 --- /dev/null +++ b/app/src/main/java/com/example/starwars/data/room/ResultEntity.kt @@ -0,0 +1,25 @@ +package com.example.starwars.data.room + +import android.os.Parcelable +import androidx.room.Entity +import androidx.room.PrimaryKey +import kotlinx.android.parcel.Parcelize + +@Parcelize + +//Criação da tabela +@Entity(tableName = "result_table") +//Atributos da tabela +data class ResultEntity( + @PrimaryKey(autoGenerate = true) + val id: Int, + val name: String, + val height: String, + val gender: String, + val mass: String, + val hair_color: String, + val skin_color: String, + val eye_color: String, + val birth_year: String, + val homeworld: String +): Parcelable diff --git a/app/src/main/java/com/example/starwars/model/People.kt b/app/src/main/java/com/example/starwars/model/People.kt new file mode 100644 index 00000000..54efd41d --- /dev/null +++ b/app/src/main/java/com/example/starwars/model/People.kt @@ -0,0 +1,8 @@ +package com.example.starwars.model + +import com.example.starwars.data.room.ResultEntity + +data class People( + val next: String, + val results: List +) \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/fragment/SplashFragment.kt b/app/src/main/java/com/example/starwars/presentation/fragment/SplashFragment.kt new file mode 100644 index 00000000..b07fc27b --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/fragment/SplashFragment.kt @@ -0,0 +1,45 @@ +package com.example.starwars.presentation.fragment + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.Handler +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.navigation.fragment.findNavController +import com.example.starwars.R +import com.example.starwars.presentation.view.Inicio +import kotlinx.android.synthetic.main.activity_main.* + +class SplashFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + val view = inflater.inflate(R.layout.fragment_splash, container, false) + + // Temporizador + Handler().postDelayed({ + // Verifica a condição do Shared + if (onBoardindFinished()) { + val intent = Intent(requireContext(), Inicio::class.java) + startActivity(intent) + activity?.finish() + } else { + findNavController().navigate(R.id.action_splashFragment_to_viewPagerFragment) + } + }, 3000) + + return view + } + + // Captura valor inicial do Shared + private fun onBoardindFinished(): Boolean { + val sharedPref = requireActivity().getSharedPreferences("onBoarding", Context.MODE_PRIVATE) + return sharedPref.getBoolean("Finished", false) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/ViewPagerAdapter.kt b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/ViewPagerAdapter.kt new file mode 100644 index 00000000..20ad9676 --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/ViewPagerAdapter.kt @@ -0,0 +1,26 @@ +package com.example.starwars.presentation.fragment.onboarding + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.Lifecycle +import androidx.viewpager2.adapter.FragmentStateAdapter + +class ViewPagerAdapter( + list: ArrayList, + fm: FragmentManager, + lifecycle: Lifecycle +) : FragmentStateAdapter(fm, lifecycle) { + + // Declara valor como uma List + private val fragmentList = list + + // Retorna o tamanho da List + override fun getItemCount(): Int { + return fragmentList.size + } + + // Obtem posição da List + override fun createFragment(position: Int): Fragment { + return fragmentList[position] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/ViewPagerFragment.kt b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/ViewPagerFragment.kt new file mode 100644 index 00000000..a9d67a51 --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/ViewPagerFragment.kt @@ -0,0 +1,39 @@ +package com.example.starwars.presentation.fragment.onboarding + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.starwars.R +import com.example.starwars.presentation.fragment.onboarding.screens.FirstScreen +import com.example.starwars.presentation.fragment.onboarding.screens.SecondScreen +import kotlinx.android.synthetic.main.fragment_view_pager.view.* + +class ViewPagerFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + val view = inflater.inflate(R.layout.fragment_view_pager, container, false) + + // Anexa todos os Screens ao ArrayList + val fragmentList = arrayListOf( + FirstScreen(), + SecondScreen() + ) + + // Declara e inicializa o adapter, passando todos os Screens que o fragmentList possui + val adapter = ViewPagerAdapter( + fragmentList,requireActivity().supportFragmentManager, + lifecycle + ) + + // Anexa a viewPage o adapter inicializado + view.viewPager.adapter = adapter + + return view + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/screens/FirstScreen.kt b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/screens/FirstScreen.kt new file mode 100644 index 00000000..701e4472 --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/screens/FirstScreen.kt @@ -0,0 +1,31 @@ +package com.example.starwars.presentation.fragment.onboarding.screens + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.viewpager2.widget.ViewPager2 +import com.example.starwars.R +import kotlinx.android.synthetic.main.fragment_first_screen.view.* + +class FirstScreen : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + val view = inflater.inflate(R.layout.fragment_first_screen, container, false) + + // Obtendo a referencia XML do viewPager2 + val viewPager = activity?.findViewById(R.id.viewPager) + + // Se o textView for clicado é passado para proxima Screen + view.seguir1.setOnClickListener{ + viewPager?.currentItem = 1 + } + + return view + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/screens/SecondScreen.kt b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/screens/SecondScreen.kt new file mode 100644 index 00000000..034d6e7b --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/fragment/onboarding/screens/SecondScreen.kt @@ -0,0 +1,39 @@ +package com.example.starwars.presentation.fragment.onboarding.screens + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.starwars.R +import com.example.starwars.presentation.view.Inicio +import kotlinx.android.synthetic.main.fragment_second_screen.view.* + +class SecondScreen : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + val view = inflater.inflate(R.layout.fragment_second_screen, container, false) + + // Se textView for pressionada, o fragment Inicio sera aberta + view.comecar.setOnClickListener{ + val intent = Intent(requireContext(), Inicio::class.java) + startActivity(intent) + onBoardingFinished() + } + return view + } + + // Realiza o Set Bollean no Finished do Shared + private fun onBoardingFinished(){ + val sharedPref = requireActivity().getSharedPreferences("onBoarding", Context.MODE_PRIVATE) + val editor = sharedPref.edit() + editor.putBoolean("Finished",true) + editor.apply() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/view/Detalhes.kt b/app/src/main/java/com/example/starwars/presentation/view/Detalhes.kt new file mode 100644 index 00000000..01c1af43 --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/view/Detalhes.kt @@ -0,0 +1,34 @@ +package com.example.starwars.presentation.view + +import android.annotation.SuppressLint +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import com.example.starwars.R +import com.example.starwars.adapter.PeopleAdapter +import com.example.starwars.adapter.PeopleAdapter.Companion.birth_yearCompanion +import com.example.starwars.adapter.PeopleAdapter.Companion.eye_colorCompanion +import com.example.starwars.adapter.PeopleAdapter.Companion.genderCompanion +import com.example.starwars.adapter.PeopleAdapter.Companion.hair_colorCompanion +import com.example.starwars.adapter.PeopleAdapter.Companion.heightCompanion +import com.example.starwars.adapter.PeopleAdapter.Companion.massCompanion +import com.example.starwars.adapter.PeopleAdapter.Companion.nameCompanion +import com.example.starwars.adapter.PeopleAdapter.Companion.skin_colorCompanion +import kotlinx.android.synthetic.main.activity_detalhes.* + +class Detalhes : AppCompatActivity() { + @SuppressLint("SetTextI18n") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_detalhes) + + textNameCompanion.text = nameCompanion + textHeightCompanion.text = "Altura: $heightCompanion" + textGenderCompanion.text = "Genero: $genderCompanion" + textHair_colorCompanion.text = "Cor do Cabelo: $hair_colorCompanion" + textSkin_colorCompanion.text = "Cor da Pele: $skin_colorCompanion" + textEye_colorCompanion.text = "Cor dos Olhos: $eye_colorCompanion" + textBirth_yearCompanion.text = "Ano de Nascimento: $birth_yearCompanion" + textMassCompanion.text = "Peso: $massCompanion" + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/view/Inicio.kt b/app/src/main/java/com/example/starwars/presentation/view/Inicio.kt new file mode 100644 index 00000000..a9202ea3 --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/view/Inicio.kt @@ -0,0 +1,142 @@ +package com.example.starwars.presentation.view + +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.os.Handler +import android.view.Menu +import android.widget.Toast +import androidx.appcompat.widget.SearchView +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.starwars.R +import com.example.starwars.adapter.PeopleAdapter +import com.example.starwars.data.room.ResultEntity +import com.example.starwars.repository.RepositoryApi +import com.example.starwars.viewmodel.PeopleViewModel +import com.example.starwars.viewmodel.PeopleViewModelFactory +import com.example.starwars.viewmodel.PeopleViewModelRoom +import kotlinx.android.synthetic.main.activity_detalhes.* +import kotlinx.android.synthetic.main.activity_inicio.* + +class Inicio : AppCompatActivity() { + + // Declarando ViewModel Room + lateinit var peopleViewModelRoom: PeopleViewModelRoom + + // Declarando ViewModel Api + private lateinit var viewModel: PeopleViewModel + + // Adapter + private val peopleAdapter by lazy { PeopleAdapter() } + + //Pagina + var page: Int = 1 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_inicio) + + peopleViewModelRoom = ViewModelProvider(this).get(PeopleViewModelRoom::class.java) + + //Adiciona Suporte Toolbar + setSupportActionBar(toolbar) + + //Executa metodo que inicia e carrega o recyclerview + setupRecyclerView() + + /* + Verifica conectividade e procede com uma ação + */ + if (isNeworkAvailable()) { + acaoComInternet() + } else { + acaoSemInternet() + } + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.menu, menu) + + // obter id do icon search + val search = menu?.findItem(R.id.id_search) + val searchView = search?.actionView as SearchView + searchView.queryHint = "Nome do personagem" + + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + return false + } + + override fun onQueryTextChange(newText: String?): Boolean { + peopleAdapter.filter.filter(newText) + return true + } + } + + ) + return super.onCreateOptionsMenu(menu) + } + + //METODOS UTEIS + + //Caso esteja com Internet + fun acaoComInternet() { + //Declara e Inicializa o Repositorio da Api + val repositoryApi = RepositoryApi() + //Informa o repositorio ao Factory + val viewModelFactory = PeopleViewModelFactory(repositoryApi) + viewModel = ViewModelProvider(this, viewModelFactory).get(PeopleViewModel::class.java) + while (page <= 9) { + var pagina = "" + page + viewModel.getPeople(pagina) + page++ + } + + peopleViewModelRoom.deleteAllResults() + viewModel.myResponse.observe(this, Observer { response -> + peopleAdapter.setData(response) + for (result in response) { + val resultEntity = ResultEntity( + 0, result.name, result.height, result.gender, result.mass, result.hair_color, + result.skin_color, result.eye_color, result.birth_year, result.homeworld + ) + peopleViewModelRoom.addResult(resultEntity) + } + }) + } + + //Caso esteja sem internet + fun acaoSemInternet() { + Toast.makeText(this, "Sem internet, verifique sua conexão", Toast.LENGTH_SHORT).show() + //ROOM + peopleViewModelRoom.readAllData.observe(this, Observer { result -> + peopleAdapter.setData(result) + }) + } + + // Pega o conteudo do Adapter e joga para o RecyclerView + private fun setupRecyclerView() { + recyclerView.adapter = peopleAdapter + recyclerView.layoutManager = LinearLayoutManager(this) + } + + //VERIFICA A CONEXAO COM A INTERNET(Wifi e Movel) + private fun isNeworkAvailable(): Boolean { + val connectivityManager = + getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val wifi: NetworkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI) + val mobi: NetworkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) + if (wifi.isConnectedOrConnecting || mobi.isConnectedOrConnecting) { + return true + } else return false + } + + override fun onBackPressed() { + finish() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/presentation/view/MainActivity.kt b/app/src/main/java/com/example/starwars/presentation/view/MainActivity.kt new file mode 100644 index 00000000..f03910e0 --- /dev/null +++ b/app/src/main/java/com/example/starwars/presentation/view/MainActivity.kt @@ -0,0 +1,13 @@ +package com.example.starwars.presentation.view + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import com.example.starwars.R + +class MainActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + //Classe Inicial + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/repository/RepositoryApi.kt b/app/src/main/java/com/example/starwars/repository/RepositoryApi.kt new file mode 100644 index 00000000..4a24d7fa --- /dev/null +++ b/app/src/main/java/com/example/starwars/repository/RepositoryApi.kt @@ -0,0 +1,15 @@ +package com.example.starwars.repository + +import com.example.starwars.data.api.RetrofitInstance +import com.example.starwars.model.People +import retrofit2.Response + +class RepositoryApi { + + // Metodo que chama o metodo da Api + // Captura todos os personagens da pagina + suspend fun getPeople(page: String): Response { + return RetrofitInstance.api.getPeople(page) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/repository/RepositoryRoom.kt b/app/src/main/java/com/example/starwars/repository/RepositoryRoom.kt new file mode 100644 index 00000000..97cf3fd4 --- /dev/null +++ b/app/src/main/java/com/example/starwars/repository/RepositoryRoom.kt @@ -0,0 +1,22 @@ +package com.example.starwars.repository + +import androidx.lifecycle.LiveData +import com.example.starwars.data.room.ResultDao +import com.example.starwars.data.room.ResultEntity + +class RepositoryRoom(private val resultDao: ResultDao) { + + // Captura todos os dados da Entidade que esta no db + val readAllData: LiveData> = resultDao.readAllData() + + // Adicionar Resultado + suspend fun addResult(resultEntity: ResultEntity) { + resultDao.addResult(resultEntity) + } + + // Deleta todos Results + suspend fun deleteAllResults() { + resultDao.deleteAllResults() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/util/Constants.kt b/app/src/main/java/com/example/starwars/util/Constants.kt new file mode 100644 index 00000000..fa8558d1 --- /dev/null +++ b/app/src/main/java/com/example/starwars/util/Constants.kt @@ -0,0 +1,9 @@ +package com.example.starwars.util + +class Constants { + + companion object { + //Link api Base - Personagens + const val BASE_URL = "http://swapi.dev/api/" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModel.kt b/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModel.kt new file mode 100644 index 00000000..26f63603 --- /dev/null +++ b/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModel.kt @@ -0,0 +1,28 @@ +package com.example.starwars.viewmodel + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.starwars.data.room.ResultEntity +import com.example.starwars.repository.RepositoryApi +import kotlinx.coroutines.launch + +class PeopleViewModel(private val repository: RepositoryApi) : ViewModel() { + + val myResponse: MutableLiveData> = MutableLiveData() + var next: Boolean = false + + // Metoto Get + fun getPeople(page: String) { + viewModelScope.launch { + val response = repository.getPeople(page) + if (response.isSuccessful) { + myResponse.value = response.body()?.results + next = true + } else { + myResponse.value = null + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModelFactory.kt b/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModelFactory.kt new file mode 100644 index 00000000..d8787f97 --- /dev/null +++ b/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModelFactory.kt @@ -0,0 +1,12 @@ +package com.example.starwars.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.starwars.repository.RepositoryApi + +class PeopleViewModelFactory(private val repository: RepositoryApi) : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + return PeopleViewModel(repository) as T + } +} diff --git a/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModelRoom.kt b/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModelRoom.kt new file mode 100644 index 00000000..37f2f2ac --- /dev/null +++ b/app/src/main/java/com/example/starwars/viewmodel/PeopleViewModelRoom.kt @@ -0,0 +1,40 @@ +package com.example.starwars.viewmodel + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.LiveData +import androidx.lifecycle.viewModelScope +import com.example.starwars.data.room.ResultDatabase +import com.example.starwars.data.room.ResultEntity +import com.example.starwars.repository.RepositoryRoom +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +class PeopleViewModelRoom(application: Application) : AndroidViewModel(application) { + + // Captura todos os dados da Entidade que esta no db + val readAllData: LiveData> // LiveData + private val repositoryRoom: RepositoryRoom // Repositório + + // Inicializa os valores + init { + // Captura o Dao do Database + val resultDao = ResultDatabase.getDatabase(application.baseContext).resultDao() + repositoryRoom = RepositoryRoom(resultDao) // Repositorio recebe o Dao + readAllData = repositoryRoom.readAllData // Captura todos os dados da tabela + } + + // Adiciona Result + fun addResult(resultEntity: ResultEntity) { + viewModelScope.launch(Dispatchers.IO) { + repositoryRoom.addResult(resultEntity) + } + } + + // Deleta todos Results + fun deleteAllResults() { + viewModelScope.launch(Dispatchers.IO) { + repositoryRoom.deleteAllResults() + } + } +} \ No newline at end of file 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_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_search.xml b/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 00000000..07b76d62 --- /dev/null +++ b/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/logo_inicial.png b/app/src/main/res/drawable/logo_inicial.png new file mode 100644 index 00000000..30c2eb03 Binary files /dev/null and b/app/src/main/res/drawable/logo_inicial.png differ diff --git a/app/src/main/res/drawable/logo_lista.png b/app/src/main/res/drawable/logo_lista.png new file mode 100644 index 00000000..94b71da7 Binary files /dev/null and b/app/src/main/res/drawable/logo_lista.png differ diff --git a/app/src/main/res/drawable/logo_persona.png b/app/src/main/res/drawable/logo_persona.png new file mode 100644 index 00000000..0d2d2249 Binary files /dev/null and b/app/src/main/res/drawable/logo_persona.png differ diff --git a/app/src/main/res/layout/activity_detalhes.xml b/app/src/main/res/layout/activity_detalhes.xml new file mode 100644 index 00000000..6cec3543 --- /dev/null +++ b/app/src/main/res/layout/activity_detalhes.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_inicio.xml b/app/src/main/res/layout/activity_inicio.xml new file mode 100644 index 00000000..ed4b667a --- /dev/null +++ b/app/src/main/res/layout/activity_inicio.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + \ 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 new file mode 100644 index 00000000..99681975 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_row_people.xml b/app/src/main/res/layout/custom_row_people.xml new file mode 100644 index 00000000..7a1ef532 --- /dev/null +++ b/app/src/main/res/layout/custom_row_people.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_first_screen.xml b/app/src/main/res/layout/fragment_first_screen.xml new file mode 100644 index 00000000..1c9695e2 --- /dev/null +++ b/app/src/main/res/layout/fragment_first_screen.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_second_screen.xml b/app/src/main/res/layout/fragment_second_screen.xml new file mode 100644 index 00000000..0cf8e5d2 --- /dev/null +++ b/app/src/main/res/layout/fragment_second_screen.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_splash.xml b/app/src/main/res/layout/fragment_splash.xml new file mode 100644 index 00000000..6a2ff78d --- /dev/null +++ b/app/src/main/res/layout/fragment_splash.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_view_pager.xml b/app/src/main/res/layout/fragment_view_pager.xml new file mode 100644 index 00000000..4ced013f --- /dev/null +++ b/app/src/main/res/layout/fragment_view_pager.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml new file mode 100644 index 00000000..0a3e9f06 --- /dev/null +++ b/app/src/main/res/menu/menu.xml @@ -0,0 +1,13 @@ + + + + + + \ 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/navigation/my_nav.xml b/app/src/main/res/navigation/my_nav.xml new file mode 100644 index 00000000..c3806e3a --- /dev/null +++ b/app/src/main/res/navigation/my_nav.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file 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..ea0bd108 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ 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..fe2b8639 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #673AB7 + #673AB7 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ 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..4c7981f7 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,12 @@ + + Star Wars + SEGUIR + COMEÇAR + DETALHES + + LISTA DE PERSONAGENS + Acompanhe a lista de personagens de Star Wars + + OLA + Bem Vindo + \ 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..c9a76e0a --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/test/java/com/example/starwars/ExampleUnitTest.kt b/app/src/test/java/com/example/starwars/ExampleUnitTest.kt new file mode 100644 index 00000000..e1d1ab0b --- /dev/null +++ b/app/src/test/java/com/example/starwars/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.starwars + +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..ea6e2aef --- /dev/null +++ b/build.gradle @@ -0,0 +1,26 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = "1.3.72" + repositories { + google() + jcenter() + } + dependencies { + classpath "com.android.tools.build:gradle:4.1.1" + 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() + jcenter() + } +} + +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..98bed167 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# 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 +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=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..4be2bade --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Dec 30 08:48:38 BRT 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip 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..898ae885 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +rootProject.name = "Star Wars" \ No newline at end of file