Merge branch 'master' into Enzo

Enzo
Jolys Enzo 2 years ago
commit 271e4011d0

@ -39,6 +39,9 @@ dependencies {
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.fragment:fragment:1.5.5'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"

@ -0,0 +1,34 @@
package adaptator
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import api.User
import but.androidstudio.tetris.R
import javax.xml.xpath.XPath
class RecyclerViewAdaptator(var userData: List<User>): RecyclerView.Adapter<RecyclerViewAdaptator.ItemViewHolder>(){
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textViewUsername: TextView = view.findViewById(R.id.item_username)
val textViewXp: TextView = view.findViewById(R.id.item_xp)
val textViewCountry: TextView = view.findViewById(R.id.item_country)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.item_layout, parent, false)
return ItemViewHolder(adapterLayout)
}
override fun getItemCount(): Int = userData.size
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
holder.textViewUsername.text = userData[position].username
holder.textViewXp.text = userData[position].xp.toString()
holder.textViewCountry.text = userData[position].country
}
}

@ -0,0 +1,3 @@
package api
class Data(val users: List<User>)

@ -0,0 +1,9 @@
package api
import retrofit2.Call
import retrofit2.http.GET
interface TetrisAPI {
@GET("users/lists/xp")
fun getAllUsers() : Call<UserResponse>
}

@ -0,0 +1,54 @@
package api
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class TetrisClient(okHttpClient: OkHttpClient) {
private val api: TetrisAPI
init {
// Create Gson object with lenient policy
val gson = GsonBuilder()
.setLenient()
.create()
// Create Retrofit instance
val retrofit = Retrofit.Builder()
.baseUrl("https://ch.tetr.io/api/")
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.build()
// Create API instance
api = retrofit.create(TetrisAPI::class.java)
}
fun getUsers(callback: (List<User>?, Throwable?) -> Unit) {
api.getAllUsers().enqueue(object : Callback<UserResponse> {
override fun onResponse(call: Call<UserResponse>, response: Response<UserResponse>) {
if (response.isSuccessful) {
// API call successful, parse response body
val users = response.body()?.data?.users
callback(users, null)
} else {
// API call failed, handle error
val error = Exception("API call failed with code ${response.code()}")
callback(null, error)
}
}
override fun onFailure(call: Call<UserResponse>, t: Throwable) {
// API call failed, handle error
callback(null, t)
}
})
}
}

@ -0,0 +1,14 @@
package api
class User(val id: String,
val username: String,
val role: String,
val xp: Double,
val supporter: Boolean,
val verified: Boolean,
val country: String,
val timestamp: String,
val gamesPlayed: Int,
val gamesWon: Int,
val gameTime: Int) {
}

@ -0,0 +1,3 @@
package api
class UserResponse(val success: Boolean, val data: Data)

@ -0,0 +1,83 @@
package but.androidstudio.tetris
import adaptator.RecyclerViewAdaptator
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import api.TetrisClient
import api.User
import okhttp3.OkHttpClient
import java.io.InputStream
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
class InfoUserFragment : Fragment() {
private lateinit var recyclerView: RecyclerView
private lateinit var adaptator: RecyclerViewAdaptator
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_info_user, container, false)
// Set up RecyclerView
recyclerView = view.findViewById<RecyclerView>(R.id.tableUser)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
adaptator =RecyclerViewAdaptator(listOf())
recyclerView.adapter = adaptator
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Read the SSL certificate for the request
val certificateStream : InputStream = resources.openRawResource(R.raw.sni_cloudflaressl_com)
// We create a certificateFactory to extract de data of the certificateInputStream
val certificateFactory = CertificateFactory.getInstance("X.509")
val certificate = certificateFactory.generateCertificate(certificateStream)
//To specified the certificate to used
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
keyStore.load(null, null)
keyStore.setCertificateEntry("ca", certificate)
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(keyStore)
//To create a SSL context
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustManagerFactory.trustManagers, SecureRandom())
// We create a OkHttpClient to use the SSLContext
val okHttpClient: OkHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustManagerFactory.trustManagers[0] as X509TrustManager)
.build()
val client = TetrisClient(okHttpClient)
client.getUsers { users, error ->
if (error != null) {
// Handle error
println("Error: ${error.message}")
} else {
// Handle success
adaptator.userData = users!!
recyclerView.adapter?.notifyDataSetChanged()
}
}
}
}

@ -34,5 +34,13 @@ class MainFragment : Fragment() {
.replace(R.id.homeLayout, OptionFragment())
.commit()
}
val buttonClassement: Button = view.findViewById(R.id.buttonClassement)
buttonClassement.setOnClickListener {
val fragmentManager = requireActivity().supportFragmentManager
fragmentManager.beginTransaction()
.replace(R.id.homeLayout, InfoUserFragment())
.commit()
}
}
}

@ -0,0 +1,38 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Username"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="XP"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Country"
android:textStyle="bold" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:orientation="vertical"
android:id="@+id/tableUser"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

@ -38,6 +38,12 @@
android:layout_height="wrap_content"
android:text="@string/start" />
<Button
android:id="@+id/buttonClassement"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Classement" />
<Button
android:id="@+id/buttonOption"
android:layout_width="match_parent"

@ -0,0 +1,25 @@
<?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="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/item_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:id="@+id/item_xp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:id="@+id/item_country"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>

@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFLTCCBNOgAwIBAgIQBVK/egzBVp4B3exMiwpZ0zAKBggqhkjOPQQDAjBKMQsw
CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX
Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjIwNTIzMDAwMDAwWhcNMjMwNTIz
MjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG
A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEe
MBwGA1UEAxMVc25pLmNsb3VkZmxhcmVzc2wuY29tMFkwEwYHKoZIzj0CAQYIKoZI
zj0DAQcDQgAEtjMD8/gzUYFeKx2j9gc0o3ZHCQH48eYDZmKkiZjB10TyyT4QH2Hn
3QfD8eRHKrTU6PlnYol/p2WL/5MnVff9ZKOCA24wggNqMB8GA1UdIwQYMBaAFKXO
N+rrsHUOlGeItEX62SQQh5YfMB0GA1UdDgQWBBSUimg81mec3SrIMXpku3tYBLc0
qzA0BgNVHREELTArggkqLnRldHIuaW+CB3RldHIuaW+CFXNuaS5jbG91ZGZsYXJl
c3NsLmNvbTAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
AQUFBwMCMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
bS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwN6A1oDOGMWh0dHA6Ly9jcmw0LmRp
Z2ljZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwPgYDVR0gBDcwNTAz
BgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20v
Q1BTMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln
aWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j
b20vQ2xvdWRmbGFyZUluY0VDQ0NBLTMuY3J0MAwGA1UdEwEB/wQCMAAwggF+Bgor
BgEEAdZ5AgQCBIIBbgSCAWoBaAB1AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nh
d31tBr1uAAABgO6iKgwAAAQDAEYwRAIgAdeVVw138Q+T/kUu/RdyojBt8cYE3+Ta
C8mJjoLZvY4CIDUEiw5lfUGLpXoH8X4HB4zISWVfIpGf2UmBCZ0goKMMAHcANc8Z
G7+xbFe/D61MbULLu7YnICZR6j/hKu+oA8M71kwAAAGA7qIqLQAABAMASDBGAiEA
lQ2PRS+mQxU0RkZm73SCIUDfLjSMjRFiCXjLJo7FJ78CIQDhgBsqhkZULuN8T0BJ
kOSZRde6wJpeD3pFg/qIzgMo6gB2ALc++yTfnE26dfI5xbpY9Gxd/ELPep81xJ4d
CYEl7bSZAAABgO6iKh0AAAQDAEcwRQIhAOJMesd21/xYT7JgrgKPGUo4WJqlAsvV
HurtPpkBy8cCAiAsSKnLvxW+og6m7YTmKnjEPVWdl2wVejrM2djmJd13JDAKBggq
hkjOPQQDAgNIADBFAiBLUqhRLadDrgcbV6AeabEnpLy7LfMj7btLFB3DLLYL0QIh
AJg9/jdsmybn7D3mhywg0hAmWWSlqLVp2jp47GU8mJCe
-----END CERTIFICATE-----
Loading…
Cancel
Save