From 8f503b64a41b1e8e5dad7a5486bf7b1ff03bf244 Mon Sep 17 00:00:00 2001 From: clfreville2 Date: Thu, 23 Mar 2023 19:27:33 +0100 Subject: [PATCH] List commits in a repository --- app/build.gradle | 10 ++ .../iut/clfreville2/teaiswarm/MainActivity.kt | 32 +++- .../teaiswarm/RepositoryDetailActivity.kt | 36 +++-- .../fragment/ActivityListFragment.kt | 149 ++++++++++++++++++ .../iut/clfreville2/teaiswarm/model/Author.kt | 5 + .../teaiswarm/model/CommitActivity.kt | 3 + .../clfreville2/teaiswarm/model/FileType.kt | 14 ++ .../clfreville2/teaiswarm/model/RepoCommit.kt | 3 + .../teaiswarm/model/Verification.kt | 3 + .../teaiswarm/model/VersionedFile.kt | 2 +- .../teaiswarm/network/GiteaService.kt | 27 +++- .../teaiswarm/network/RepositoryService.kt | 6 +- .../network/StubRepositoryService.kt | 30 +++- app/src/main/res/layout/activity_list.xml | 9 ++ app/src/main/res/layout/activity_main.xml | 17 ++ app/src/main/res/layout/activity_row_item.xml | 9 ++ .../main/res/layout/repository_row_item.xml | 6 +- app/src/main/res/values/strings.xml | 6 + 18 files changed, 330 insertions(+), 37 deletions(-) create mode 100644 app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/fragment/ActivityListFragment.kt create mode 100644 app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Author.kt create mode 100644 app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/CommitActivity.kt create mode 100644 app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/FileType.kt create mode 100644 app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/RepoCommit.kt create mode 100644 app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Verification.kt create mode 100644 app/src/main/res/layout/activity_list.xml create mode 100644 app/src/main/res/layout/activity_row_item.xml diff --git a/app/build.gradle b/app/build.gradle index 4fdfb4c..aec6586 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,6 +36,9 @@ android { } dependencies { + def nav_version = "2.5.3" + def paging_version = "3.1.1" + def fragment_version = "1.5.6" implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.6.1' @@ -45,8 +48,15 @@ dependencies { implementation 'androidx.navigation:navigation-ui-ktx:2.5.3' implementation 'com.squareup.moshi:moshi:1.14.0' implementation 'com.squareup.moshi:moshi-kotlin:1.14.0' + implementation 'com.squareup.moshi:moshi-adapters:1.14.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-moshi:2.9.0' + implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" + implementation "androidx.navigation:navigation-ui-ktx:$nav_version" + implementation "androidx.paging:paging-runtime:$paging_version" + implementation "androidx.fragment:fragment-ktx:$fragment_version" + + //implementation 'androidx.core:core-ktx:+' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/MainActivity.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/MainActivity.kt index 9e39ce3..fb924be 100644 --- a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/MainActivity.kt +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/MainActivity.kt @@ -3,12 +3,13 @@ package fr.uca.iut.clfreville2.teaiswarm import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.widget.Button import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView import fr.uca.iut.clfreville2.teaiswarm.model.Repository import fr.uca.iut.clfreville2.teaiswarm.network.GiteaService -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlin.math.max const val REPOSITORY_OWNER = "repository_owner" const val REPOSITORY_NAME = "repository_name" @@ -17,18 +18,24 @@ class MainActivity : AppCompatActivity() { private val service = GiteaService() private lateinit var repositories: RecyclerView + private lateinit var previousButton: Button + private lateinit var nextButton: Button + private var currentPage = 1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) repositories = findViewById(R.id.repositories_view) - lifecycleScope.launch(Dispatchers.IO) { - val repos = service.listActiveRepositories("clement.freville2", 1) - lifecycleScope.launch { - repositories.adapter = RepositoryListAdapter(repos) { repo -> - adapterOnClick(repo) - } - } + previousButton = findViewById(R.id.previous_repository_list) + nextButton = findViewById(R.id.next_repository_list) + updateList() + previousButton.setOnClickListener { + currentPage = max(currentPage - 1, 0) + updateList() + } + nextButton.setOnClickListener { + currentPage += 1 + updateList() } } @@ -38,4 +45,13 @@ class MainActivity : AppCompatActivity() { intent.putExtra(REPOSITORY_NAME, repository.name) startActivity(intent) } + + private fun updateList() { + lifecycleScope.launch { + val repos = service.listActiveRepositories("clement.freville2", currentPage) + repositories.adapter = RepositoryListAdapter(repos) { repo -> + adapterOnClick(repo) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/RepositoryDetailActivity.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/RepositoryDetailActivity.kt index 12cd7f1..4d622e5 100644 --- a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/RepositoryDetailActivity.kt +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/RepositoryDetailActivity.kt @@ -1,45 +1,57 @@ package fr.uca.iut.clfreville2.teaiswarm +import android.content.Intent import android.os.Bundle import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView import fr.uca.iut.clfreville2.teaiswarm.model.RepositoryIdentifier +import fr.uca.iut.clfreville2.teaiswarm.model.VersionedFile import fr.uca.iut.clfreville2.teaiswarm.network.GiteaService -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +const val FILE_PATH = "file_path" + class RepositoryDetailActivity : AppCompatActivity() { private val service = GiteaService() private lateinit var repositoryName: TextView private lateinit var versionedFiles: RecyclerView + private lateinit var currentRepositoryOwner: String + private lateinit var currentRepositoryName: String + private var currentFilePath: String? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_repository_detail) repositoryName = findViewById(R.id.repository_detail_name) - var currentRepositoryOwner: String? = null - var currentRepositoryName: String? = null val bundle: Bundle? = intent.extras if (bundle != null) { - currentRepositoryOwner = bundle.getString(REPOSITORY_OWNER) - currentRepositoryName = bundle.getString(REPOSITORY_NAME) + currentRepositoryOwner = bundle.getString(REPOSITORY_OWNER)!! + currentRepositoryName = bundle.getString(REPOSITORY_NAME)!! + currentFilePath = bundle.getString(FILE_PATH) } - currentRepositoryName?.let { - repositoryName.text = currentRepositoryName - } + repositoryName.text = currentRepositoryName versionedFiles = findViewById(R.id.versioned_files_view) - lifecycleScope.launch(Dispatchers.IO) { - val repos = service.listFileContents(RepositoryIdentifier(currentRepositoryOwner!!, currentRepositoryName!!), "") - lifecycleScope.launch { - versionedFiles.adapter = FileListAdapter(repos) {} + lifecycleScope.launch { + val repos = service.listFileContents(RepositoryIdentifier(currentRepositoryOwner, currentRepositoryName), currentFilePath ?: "") + versionedFiles.adapter = FileListAdapter(repos) { + file -> adapterOnClick(file) } } } + + private fun adapterOnClick(file: VersionedFile) { + val intent = Intent(this, RepositoryDetailActivity()::class.java) + intent.putExtra(REPOSITORY_OWNER, currentRepositoryOwner) + intent.putExtra(REPOSITORY_NAME, currentRepositoryName) + intent.putExtra(FILE_PATH, (currentFilePath ?: "") + file.name) + startActivity(intent) + } } diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/fragment/ActivityListFragment.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/fragment/ActivityListFragment.kt new file mode 100644 index 0000000..4c6a544 --- /dev/null +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/fragment/ActivityListFragment.kt @@ -0,0 +1,149 @@ +package fr.uca.iut.clfreville2.teaiswarm.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.paging.* +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import fr.uca.iut.clfreville2.teaiswarm.R +import fr.uca.iut.clfreville2.teaiswarm.model.CommitActivity +import fr.uca.iut.clfreville2.teaiswarm.model.RepositoryIdentifier +import fr.uca.iut.clfreville2.teaiswarm.network.GiteaService +import fr.uca.iut.clfreville2.teaiswarm.network.RepositoryService +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import retrofit2.HttpException +import java.io.IOException + +class ActivityListFragment : Fragment(R.layout.activity_list) { + + private val service = GiteaService() + var repository: RepositoryIdentifier? = null + var sha: String? = null + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + updateCommits() + } + + private fun updateCommits() { + val viewModel by viewModels( + factoryProducer = { + ActivityViewModelFactory( + service, + repository!!, + sha + ) + } + ) + val pagingAdapter = ActivityAdapter(ActivityComparator) + val recyclerView = requireView().findViewById(R.id.activity_list_view) + recyclerView.adapter = pagingAdapter + recyclerView.layoutManager = LinearLayoutManager(requireContext()) + viewLifecycleOwner.lifecycleScope.launch { + viewModel.flow.collectLatest { pagingData -> + pagingAdapter.submitData(pagingData) + } + } + } + + class ActivitySource( + private val service: RepositoryService, + private val repository: RepositoryIdentifier, + private val sha: String? + ) : PagingSource() { + + override suspend fun load(params: LoadParams): LoadResult = + try { + val nextPageNumber = params.key ?: 1 + val response = service.listCommits(repository, sha, nextPageNumber) + LoadResult.Page( + data = response, + prevKey = nextPageNumber - 1, + nextKey = nextPageNumber + 1 + ) + } catch (e: IOException) { + LoadResult.Error(e) + } catch (e: HttpException) { + LoadResult.Error(e) + } + + override fun getRefreshKey(state: PagingState): Int? = + state.anchorPosition?.let { anchorPosition -> + val anchorPage = state.closestPageToPosition(anchorPosition) + anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1) + } + } + + class ActivityAdapter(diffCallback: DiffUtil.ItemCallback) : + PagingDataAdapter(diffCallback) { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): ViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.activity_row_item, parent, false) + return ViewHolder(view) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) = + holder.bind(getItem(position)) + } + + class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + private val commitNameView: TextView + + init { + commitNameView = view.findViewById(R.id.commit_name) + } + + fun bind(commit: CommitActivity?) { + commit?.let { + commitNameView.text = it.commit.message + } + } + } + + object ActivityComparator : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: CommitActivity, newItem: CommitActivity): Boolean = + oldItem.sha == newItem.sha + + override fun areContentsTheSame(oldItem: CommitActivity, newItem: CommitActivity): Boolean = + oldItem == newItem + } + + class ActivityViewModel( + private val service: RepositoryService, + private val repository: RepositoryIdentifier, + private val sha: String? + ) : ViewModel() { + val flow = Pager( + PagingConfig(pageSize = 10, enablePlaceholders = true) + ) { + ActivitySource(service, repository, sha) + }.flow + } + + class ActivityViewModelFactory( + private val service: RepositoryService, + private val repository: RepositoryIdentifier, + private val sha: String? + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(ActivityViewModel::class.java)) { + @Suppress("UNCHECKED_CAST") + return ActivityViewModel(service, repository, sha) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } + } +} diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Author.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Author.kt new file mode 100644 index 0000000..1add311 --- /dev/null +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Author.kt @@ -0,0 +1,5 @@ +package fr.uca.iut.clfreville2.teaiswarm.model + +import java.util.Date + +data class Author(val name: String, val email: String, val date: Date) diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/CommitActivity.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/CommitActivity.kt new file mode 100644 index 0000000..a5851ac --- /dev/null +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/CommitActivity.kt @@ -0,0 +1,3 @@ +package fr.uca.iut.clfreville2.teaiswarm.model + +data class CommitActivity(val sha: String, val commit: Commit, val author: Owner?, val committer: Owner?) diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/FileType.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/FileType.kt new file mode 100644 index 0000000..4d05535 --- /dev/null +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/FileType.kt @@ -0,0 +1,14 @@ +package fr.uca.iut.clfreville2.teaiswarm.model + +import com.squareup.moshi.Json + +enum class FileType { + @Json(name = "file") + FILE, + @Json(name = "dir") + DIR, + @Json(name = "symlink") + SYMLINK, + @Json(name = "submodule") + SUBMODULE +} diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/RepoCommit.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/RepoCommit.kt new file mode 100644 index 0000000..d5eb4eb --- /dev/null +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/RepoCommit.kt @@ -0,0 +1,3 @@ +package fr.uca.iut.clfreville2.teaiswarm.model + +data class Commit(val author: Author, val committer: Author, val message: String) diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Verification.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Verification.kt new file mode 100644 index 0000000..6a2a369 --- /dev/null +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/Verification.kt @@ -0,0 +1,3 @@ +package fr.uca.iut.clfreville2.teaiswarm.model + +data class Verification(val verified: Boolean) \ No newline at end of file diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/VersionedFile.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/VersionedFile.kt index 5e89a5a..d026e5a 100644 --- a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/VersionedFile.kt +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/model/VersionedFile.kt @@ -1,3 +1,3 @@ package fr.uca.iut.clfreville2.teaiswarm.model -data class VersionedFile(val name: String) +data class VersionedFile(val name: String, val type: FileType) diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/GiteaService.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/GiteaService.kt index 8bd570f..8774022 100644 --- a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/GiteaService.kt +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/GiteaService.kt @@ -1,23 +1,29 @@ package fr.uca.iut.clfreville2.teaiswarm.network import com.squareup.moshi.Moshi +import com.squareup.moshi.adapters.EnumJsonAdapter +import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import fr.uca.iut.clfreville2.teaiswarm.model.* -import fr.uca.iut.clfreville2.teaiswarm.model.Repository -import fr.uca.iut.clfreville2.teaiswarm.model.RepositoryIdentifiable -import fr.uca.iut.clfreville2.teaiswarm.model.VersionedFile +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query +import java.util.* interface GiteaApiService { @GET("users/{username}/repos") suspend fun listActiveRepositories(@Path("username") username: String, @Query("page") page: Int): List + @GET("repos/{owner}/{repo}/commits") + suspend fun listCommits(@Path("owner") owner: String, @Path("repo") repo: String, @Query("sha") sha: String?, @Query("page") page: Int): List + @GET("repos/{owner}/{repo}/contents/{filePath}") suspend fun listFileContents(@Path("owner") owner: String, @Path("repo") repo: String, @Path("filePath") filePath: String): List } @@ -26,11 +32,21 @@ class GiteaService(private val handle: GiteaApiService) : RepositoryService { constructor() : this(createRetrofit().create(GiteaApiService::class.java)) - override suspend fun listActiveRepositories(username: String, page: Int): List = + override suspend fun listActiveRepositories(username: String, page: Int): List = withContext(Dispatchers.IO) { handle.listActiveRepositories(username, page) + } + + override suspend fun listCommits( + repository: RepositoryIdentifiable, + sha: String?, + page: Int + ): List = withContext(Dispatchers.IO) { + handle.listCommits(repository.identifier.owner, repository.identifier.name, sha, page) + } - override suspend fun listFileContents(repository: RepositoryIdentifiable, filePath: String): List = + override suspend fun listFileContents(repository: RepositoryIdentifiable, filePath: String): List = withContext(Dispatchers.IO) { handle.listFileContents(repository.identifier.owner, repository.identifier.name, filePath) + } } private const val CODEFIRST_API_BASE = "https://codefirst.iut.uca.fr/git/api/v1/" @@ -42,6 +58,7 @@ private fun createRetrofit(): Retrofit = .baseUrl(CODEFIRST_API_BASE) .addConverterFactory(MoshiConverterFactory.create( Moshi.Builder() + .add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe()) .add(KotlinJsonAdapterFactory()) .build())) .client(httpClient) diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/RepositoryService.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/RepositoryService.kt index 944ad28..ec53bcd 100644 --- a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/RepositoryService.kt +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/RepositoryService.kt @@ -1,12 +1,12 @@ package fr.uca.iut.clfreville2.teaiswarm.network -import fr.uca.iut.clfreville2.teaiswarm.model.Repository -import fr.uca.iut.clfreville2.teaiswarm.model.RepositoryIdentifiable -import fr.uca.iut.clfreville2.teaiswarm.model.VersionedFile +import fr.uca.iut.clfreville2.teaiswarm.model.* interface RepositoryService { suspend fun listActiveRepositories(username: String, page: Int): List + suspend fun listCommits(repository: RepositoryIdentifiable, sha: String?, page: Int): List + suspend fun listFileContents(repository: RepositoryIdentifiable, filePath: String): List } diff --git a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/StubRepositoryService.kt b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/StubRepositoryService.kt index a612cb8..bb94e1b 100644 --- a/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/StubRepositoryService.kt +++ b/app/src/main/java/fr/uca/iut/clfreville2/teaiswarm/network/StubRepositoryService.kt @@ -1,9 +1,8 @@ package fr.uca.iut.clfreville2.teaiswarm.network -import fr.uca.iut.clfreville2.teaiswarm.model.Owner -import fr.uca.iut.clfreville2.teaiswarm.model.Repository -import fr.uca.iut.clfreville2.teaiswarm.model.RepositoryIdentifiable -import fr.uca.iut.clfreville2.teaiswarm.model.VersionedFile +import fr.uca.iut.clfreville2.teaiswarm.model.* +import java.util.Date +import kotlin.random.Random class StubRepositoryService : RepositoryService { @@ -28,6 +27,22 @@ class StubRepositoryService : RepositoryService { else -> listOf() }.map { Repository(Owner(-1, ""), it) } + override suspend fun listCommits( + repository: RepositoryIdentifiable, + sha: String?, + page: Int + ): List { + val author = Author("clement.freville2", "clement.freville2@etu.uca.fr", Date()) + return (0..10).map { + CommitActivity( + randomCommitSha(), + Commit(author, author, "Implement parser"), + null, + null + ) + } + } + override suspend fun listFileContents(repository: RepositoryIdentifiable, filePath: String) = listOf( "cli", @@ -39,5 +54,10 @@ class StubRepositoryService : RepositoryService { ".gitignore", "CONVENTIONS.md", "README.md" - ).map { VersionedFile(it) } + ).map { VersionedFile(it, if (it.contains(".")) { FileType.FILE } else { FileType.DIR }) } } + +val CHAR_POOL = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); +fun randomCommitSha() = (1..40) + .map { Random.nextInt(0, CHAR_POOL.size).let { CHAR_POOL[it] } } + .joinToString("") diff --git a/app/src/main/res/layout/activity_list.xml b/app/src/main/res/layout/activity_list.xml new file mode 100644 index 0000000..cfe3162 --- /dev/null +++ b/app/src/main/res/layout/activity_list.xml @@ -0,0 +1,9 @@ + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4e2d1c5..ebbeb24 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -12,4 +12,21 @@ android:layout_height="match_parent" app:layoutManager="LinearLayoutManager"/> + +