Check user validity and add a code view fragment

main
Clément FRÉVILLE 2 years ago
parent 6687ce099d
commit 3b47bb7e7f

@ -0,0 +1,11 @@
package fr.uca.iut.clfreville2.teaiswarm
import fr.uca.iut.clfreville2.teaiswarm.network.GiteaService
import fr.uca.iut.clfreville2.teaiswarm.network.RepositoryService
object TeaIsWarm {
val service: RepositoryService by lazy {
GiteaService()
}
}

@ -17,9 +17,9 @@ import androidx.recyclerview.widget.RecyclerView
import fr.uca.iut.clfreville2.teaiswarm.R
import fr.uca.iut.clfreville2.teaiswarm.REPOSITORY_NAME
import fr.uca.iut.clfreville2.teaiswarm.REPOSITORY_OWNER
import fr.uca.iut.clfreville2.teaiswarm.TeaIsWarm
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
@ -28,7 +28,7 @@ import java.io.IOException
class ActivityListFragment : Fragment(R.layout.activity_list) {
private val service = GiteaService()
private val service = TeaIsWarm.service
var repository: RepositoryIdentifier? = null
var sha: String? = null

@ -0,0 +1,33 @@
package fr.uca.iut.clfreville2.teaiswarm.fragment
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import fr.uca.iut.clfreville2.teaiswarm.R
import fr.uca.iut.clfreville2.teaiswarm.REPOSITORY_NAME
import fr.uca.iut.clfreville2.teaiswarm.REPOSITORY_OWNER
import fr.uca.iut.clfreville2.teaiswarm.TeaIsWarm
import fr.uca.iut.clfreville2.teaiswarm.model.RepositoryIdentifier
import kotlinx.coroutines.launch
class CodeViewFragment : Fragment(R.layout.code_view_fragment) {
private lateinit var content: TextView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val service = TeaIsWarm.service
val bundle = requireArguments()
val repository = RepositoryIdentifier(
bundle.getString(REPOSITORY_OWNER)!!,
bundle.getString(REPOSITORY_NAME)!!
)
content = view.findViewById(R.id.code_content_view)
viewLifecycleOwner.lifecycleScope.launch {
val contents = service.retrieveFileContents(repository, bundle.getString(FILE_PATH)!!)
content.text = contents.content
}
}
}

@ -10,16 +10,16 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import fr.uca.iut.clfreville2.teaiswarm.*
import fr.uca.iut.clfreville2.teaiswarm.model.FileType
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.launch
const val FILE_PATH = "file_path"
class RepositoryDetailsFragment : Fragment(R.layout.repository_details) {
private val service = GiteaService()
private val service = TeaIsWarm.service
private lateinit var repositoryName: TextView
private lateinit var repositoryDescription: TextView
private lateinit var activity: Button
@ -61,6 +61,14 @@ class RepositoryDetailsFragment : Fragment(R.layout.repository_details) {
REPOSITORY_NAME to currentRepositoryName,
FILE_PATH to (currentFilePath ?: "") + file.name
)
when (file.type) {
FileType.FILE -> {
findNavController().navigate(R.id.code_view_fragment, bundle)
}
FileType.DIR -> {
findNavController().navigate(R.id.repository_details_fragment, bundle)
}
else -> {}
}
}
}

@ -12,9 +12,9 @@ import androidx.paging.*
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import fr.uca.iut.clfreville2.teaiswarm.R
import fr.uca.iut.clfreville2.teaiswarm.TeaIsWarm
import fr.uca.iut.clfreville2.teaiswarm.adapter.RepositoryListAdapter
import fr.uca.iut.clfreville2.teaiswarm.model.Repository
import fr.uca.iut.clfreville2.teaiswarm.network.GiteaService
import fr.uca.iut.clfreville2.teaiswarm.network.RepositoryService
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@ -23,7 +23,7 @@ import java.io.IOException
class RepositoryListFragment(private val username: String, private val onClick: (Repository) -> Unit) : Fragment(R.layout.repository_list) {
private val service = GiteaService()
private val service = TeaIsWarm.service
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

@ -5,11 +5,16 @@ import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.core.content.edit
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import fr.uca.iut.clfreville2.teaiswarm.R
import fr.uca.iut.clfreville2.teaiswarm.TeaIsWarm
import fr.uca.iut.clfreville2.teaiswarm.USERNAME
import fr.uca.iut.clfreville2.teaiswarm.model.Owner
import kotlinx.coroutines.launch
class SetupConfigFragment(private val preferences: SharedPreferences) : Fragment(R.layout.setup_config) {
@ -21,10 +26,22 @@ class SetupConfigFragment(private val preferences: SharedPreferences) : Fragment
usernameInput = view.findViewById(R.id.username_input)
confirmButton = view.findViewById(R.id.configure_button)
confirmButton.setOnClickListener {
val username = usernameInput.text.toString()
lifecycleScope.launch {
val owner = TeaIsWarm.service.searchOwner(username)
if (owner is Owner) {
preferences.edit {
putString(USERNAME, usernameInput.text.toString())
}
view.findNavController().navigate(R.id.repository_list_fragment)
} else {
Toast.makeText(
view.context,
resources.getText(R.string.owner_not_found),
Toast.LENGTH_SHORT
).show()
}
}
}
}
}

@ -0,0 +1,3 @@
package fr.uca.iut.clfreville2.teaiswarm.model
data class FileContent(val type: FileType, val size: Int, val content: String, val last_commit_sha: String)

@ -8,6 +8,7 @@ import fr.uca.iut.clfreville2.teaiswarm.model.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET
@ -15,6 +16,8 @@ import retrofit2.http.Path
import retrofit2.http.Query
import java.util.*
const val HTTP_NOT_FOUND = 404;
interface GiteaApiService {
@GET("users/{username}/repos")
@ -25,6 +28,12 @@ interface GiteaApiService {
@GET("repos/{owner}/{repo}/contents/{filePath}")
suspend fun listFileContents(@Path("owner") owner: String, @Path("repo") repo: String, @Path("filePath") filePath: String): List<VersionedFile>
@GET("repos/{owner}/{repo}/contents/{filePath}")
suspend fun retrieveFileContents(@Path("owner") owner: String, @Path("repo") repo: String, @Path("filePath") filePath: String): FileContent
@GET("users/{owner}")
suspend fun searchOwner(@Path("owner") owner: String): Owner?
}
class GiteaService(private val handle: GiteaApiService) : RepositoryService {
@ -54,6 +63,23 @@ class GiteaService(private val handle: GiteaApiService) : RepositoryService {
override suspend fun listFileContents(repository: RepositoryIdentifiable, filePath: String): List<VersionedFile> = withContext(Dispatchers.IO) {
handle.listFileContents(repository.identifier.owner, repository.identifier.name, filePath)
}
override suspend fun retrieveFileContents(
repository: RepositoryIdentifiable,
filePath: String
): FileContent = withContext(Dispatchers.IO) {
handle.retrieveFileContents(repository.identifier.owner, repository.identifier.name, filePath)
}
override suspend fun searchOwner(owner: String): Owner? = try {
handle.searchOwner(owner)
} catch (ex: HttpException) {
if (ex.code() == HTTP_NOT_FOUND) {
null
} else {
throw ex
}
}
}
private const val CODEFIRST_API_BASE = "https://codefirst.iut.uca.fr/git/api/v1/"

@ -9,4 +9,8 @@ interface RepositoryService {
suspend fun listCommits(repository: RepositoryIdentifiable, sha: String?, page: Int): List<CommitActivity>
suspend fun listFileContents(repository: RepositoryIdentifiable, filePath: String): List<VersionedFile>
suspend fun retrieveFileContents(repository: RepositoryIdentifiable, filePath: String): FileContent
suspend fun searchOwner(owner: String): Owner?
}

@ -55,6 +55,20 @@ class StubRepositoryService : RepositoryService {
"CONVENTIONS.md",
"README.md"
).map { VersionedFile(it, if (it.contains(".")) { FileType.FILE } else { FileType.DIR }) }
// See KT-2425
override suspend fun retrieveFileContents(
repository: RepositoryIdentifiable,
filePath: String
) = FileContent(
FileType.FILE, 82, """
#!/bin/bash
container_id=$(docker run --detach nginx)
docker stop ${'$'}container_id""", randomCommitSha()
)
override suspend fun searchOwner(owner: String): Owner =
Owner(1, owner)
}
val CHAR_POOL = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/code_content_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

@ -4,20 +4,27 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="@+id/username_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/configure_button"
android:autofillHints="" />
android:autofillHints=""
app:layout_constraintBottom_toTopOf="@+id/configure_button" />
<Button
android:id="@+id/configure_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configure"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
android:text="@string/configure" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -28,4 +28,8 @@
android:id="@+id/repository_details_fragment"
android:name="fr.uca.iut.clfreville2.teaiswarm.fragment.RepositoryDetailsFragment"
android:label="RepositoryDetailsFragment" />
<fragment
android:id="@+id/code_view_fragment"
android:name="fr.uca.iut.clfreville2.teaiswarm.fragment.CodeViewFragment"
android:label="CodeViewFragment" />
</navigation>

@ -14,4 +14,5 @@
<string name="username">Username</string>
<string name="configure">Configure</string>
<string name="activity">Activity</string>
<string name="owner_not_found">User not found</string>
</resources>
Loading…
Cancel
Save