Compare commits

...

3 Commits

Author SHA1 Message Date
d_yanis 59fa85e6c6 Merging old version
1 year ago
d_yanis 8eaa9e65cb refactoring
1 year ago
d_yanis 3f4148cf89 WIP
1 year ago

@ -56,7 +56,7 @@ android {
} }
dependencies { dependencies {
implementation("io.coil-kt:coil-compose:2.6.0")
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)

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

@ -1,6 +1,7 @@
package com.iqball.app package com.iqball.app
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -9,25 +10,22 @@ import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.iqball.app.api.EitherBodyConverter import com.iqball.app.api.EitherBodyConverter
import com.iqball.app.api.EitherCallAdapterFactory import com.iqball.app.api.EitherCallAdapterFactory
import com.iqball.app.api.service.AuthService
import com.iqball.app.api.service.IQBallService import com.iqball.app.api.service.IQBallService
import com.iqball.app.page.DisplayHomePage import com.iqball.app.page.HomePage
import com.iqball.app.page.RegisterPage import com.iqball.app.page.RegisterPage
import com.iqball.app.ui.theme.IQBallTheme import com.iqball.app.ui.theme.IQBallTheme
import kotlinx.coroutines.runBlocking
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create import retrofit2.create
import java.lang.reflect.Type
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val gson = Gson() val gson = Gson()
val retrofit = Retrofit.Builder() val retrofit = Retrofit.Builder()
@ -48,7 +46,8 @@ class MainActivity : ComponentActivity() {
IQBallTheme { IQBallTheme {
// A surface container using the 'background' color from the theme // A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
App(service) //App(service)
HomePage(service)
} }
} }
} }
@ -57,5 +56,12 @@ class MainActivity : ComponentActivity() {
@Composable @Composable
fun App(service: IQBallService) { fun App(service: IQBallService) {
DisplayHomePage() runBlocking {
val result = service.login(AuthService.LoginRequest("yanis@mail.com", "123456"))
val auth = result.getOrNull()!!
Log.d("test", "test")
service.getUserData(auth.token)
}
RegisterPage(service)
} }

@ -1,10 +1,12 @@
package com.iqball.app.api.service package com.iqball.app.api.service
import com.iqball.app.model.Tactic
import com.iqball.app.model.Team
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Header import retrofit2.http.Header
interface UserService { interface UserService {
data class UserDataResponse(val teams: List<Any>, val tactics: List<Any>) data class UserDataResponse(val teams: List<Team>, val tactics: List<Tactic>)
@GET("user-data") @GET("user-data")
suspend fun getUserData(@Header("Authorization") auth: String): APIResult<UserDataResponse> suspend fun getUserData(@Header("Authorization") auth: String): APIResult<UserDataResponse>

@ -0,0 +1,9 @@
package com.iqball.app.model
data class Tactic (
val id: Int,
val name: String,
val ownerId: Int,
val courtType: String,
val creationDate: Long
)

@ -0,0 +1,29 @@
package com.iqball.app.model;
class Team public constructor(
private val id: Int,
private val name: String,
private val picture: String,
private val mainColor: String,
private val secondColor: String
) {
public fun getId() : Int {
return id
}
public fun getName() : String {
return name
}
public fun getPicture() : String {
return picture
}
public fun getMainColor() : String {
return mainColor
}
public fun getSecondColor() : String {
return secondColor
}
}

@ -1,139 +1,394 @@
package com.iqball.app.page package com.iqball.app.page
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Divider import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.core.graphics.toColorInt
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.ui.Alignment import androidx.compose.material3.TopAppBarDefaults.pinnedScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.iqball.app.R import com.iqball.app.model.Tactic
import com.iqball.app.ui.theme.Orange import com.iqball.app.model.Team
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.TextUnit
import arrow.core.Either
import coil.compose.AsyncImage
import com.iqball.app.api.service.AuthService
import com.iqball.app.api.service.IQBallService
import com.iqball.app.api.service.UserService
import kotlinx.coroutines.runBlocking
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
@Preview @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun DisplayHomePage() { fun HomePage(service: IQBallService) {
HomePage() val tactics: List<Tactic>
val teams: List<Team>
var invalid = false
val data = getDataFromApi(service)
if (data == null) {
tactics = listOf<Tactic>()
teams = listOf<Team>()
invalid = true
} else {
tactics = data.tactics
teams = data.teams
}
val scrollBehavior = pinnedScrollBehavior(rememberTopAppBarState())
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
CenterAlignedTopAppBar(
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.secondary,
),
title = {
Text(
"IQBall",
fontSize = 40.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
scrollBehavior = scrollBehavior
)
},
) { innerPadding ->
Body(innerPadding, tactics, teams, invalid)
}
} }
@Composable @Composable
fun HomePage() { fun Body(padding: PaddingValues, tactics: List<Tactic>, teams: List<Team>, invalid: Boolean) {
Column { Column(
AppHeader() modifier = Modifier
PersonalSpace() .padding(padding)
PersonalSpaceMenu() ) {
var isTactics by remember { mutableStateOf(true) }
TabButtons(isTactics) { newIsTactic ->
isTactics = newIsTactic
}
if (isTactics) {
ListTacticCard(tactics)
} else {
ListTeamCard(teams)
}
if (invalid) {
TextCentered(text = "Erreur : Aucune connexion internet. Veillez activer votre connexion internet puis relancer l'application", fontSize = 20.sp )
}
} }
} }
@Composable @Composable
fun AppHeader() { fun TabButtons(isTactics: Boolean, onToggle: (Boolean) -> Unit) {
Box( Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier modifier = Modifier
.background(Color.DarkGray) .padding(top = 10.dp, start = 2.dp, end = 2.dp)
.fillMaxWidth(), .fillMaxWidth()
contentAlignment = Alignment.Center .padding(top = 10.dp, bottom = 10.dp)
) { ) {
Row { val tacticTitle = "Espace personnel"
Text( val teamTitle = "Mes équipes"
text = stringResource(R.string.app_name), val spaceButton = 5.dp
color = Orange, if (isTactics) {
fontWeight = FontWeight.Bold, FilledButton(tacticTitle) {}
fontSize = 25.sp Spacer(
modifier = Modifier
.padding(spaceButton)
)
OutlinedButton(teamTitle) {
onToggle(false)
}
} else {
OutlinedButton(tacticTitle) {
onToggle(true)
}
Spacer(
modifier = Modifier
.padding(spaceButton)
) )
//rajouter petit bonhomme avec le nom FilledButton(teamTitle) {}
} }
} }
} }
@Composable @Composable
fun PersonalSpace() { fun ListTacticCard(tactics: List<Tactic>) {
Box( LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
modifier = Modifier modifier = Modifier
.background(Color.Gray) .padding(5.dp),
.fillMaxWidth(), content = {
contentAlignment = Alignment.Center items(tactics) { tactic ->
TacticCard(tactic)
}
}
)
}
@Composable
fun ListTeamCard(teams: List<Team>) {
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
modifier = Modifier
.padding(5.dp),
content = {
items(teams) { team ->
TeamCard(team)
}
}
)
}
@Composable
fun TacticCard(tactic: Tactic) {
Column(
modifier = Modifier
.padding(5.dp)
.border(
border = BorderStroke(1.dp, Color(0xFFDADCE0)),
shape = RoundedCornerShape(8.dp)
)
.shadow(1.dp, shape = RoundedCornerShape(8.dp))
.background(
color = Color(0xFFFFFFFF)
)
.padding(15.dp)
) { ) {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Row {
Text( TextCentered(text = tactic.name, fontSize = 16.sp)
text = stringResource(R.string.espace_personnel), }
color = Color.White, Row {
fontWeight = FontWeight.Bold, val date =LocalDateTime.ofInstant(Instant.ofEpochMilli(tactic.creationDate), ZoneId.systemDefault())
fontSize = 15.sp, val dateFormatted = date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy kk:mm"))
modifier = Modifier.padding(5.dp) TextCentered(text = dateFormatted , fontSize = 10.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(2.dp))
}
}
}
@Composable
fun TeamCard(team: Team) {
var mainColor = Color.White
var secondColor = Color.White
var validMain = true
var validSecond = true
try {
mainColor = Color(team.getMainColor().toColorInt())
} catch (e : Exception) {
validMain = false
}
try {
secondColor = Color(team.getSecondColor().toColorInt())
} catch (e : Exception) {
validSecond = false
}
Column(
modifier = Modifier
.padding(5.dp)
.border(
border = BorderStroke(1.dp, Color(0xFFDADCE0)),
shape = RoundedCornerShape(8.dp)
) )
Box( .shadow(1.dp, shape = RoundedCornerShape(8.dp))
modifier = Modifier .background(
.border(2.dp, Color.Black, RoundedCornerShape(5.dp)) color = Color(0xFFFFFFFF)
.fillMaxWidth(), )
contentAlignment = Alignment.Center .padding(15.dp)
) {
Text( ) {
text = "Aucune tactique créée !", AsyncImage(
fontSize = 10.sp, model = team.getPicture(),
modifier = Modifier.padding(5.dp) contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.border(
border = BorderStroke(1.dp, Color(0xFFDADCE0)),
shape = RectangleShape
) )
} )
TextCentered(text = team.getName())
Row {
TeamColorCard("Couleur principale", mainColor, 0.5f)
TeamColorCard("Couleur secondaire", secondColor)
}
if(!validMain || !validSecond) {
TextCentered(text = "Erreur : Format des couleurs invalides", fontSize = 16.sp)
} }
} }
} }
@Composable @Composable
fun PersonalSpaceMenu() { fun TeamColorCard(text: String, color: Color, fraction : Float = 1f) {
Box( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxWidth(fraction)
.background(Color.LightGray)
) { ) {
Column { Box(
Row { contentAlignment = Alignment.Center,
Row { modifier = Modifier
Box( .fillMaxWidth()
modifier = Modifier .padding(2.dp)
.background(Color.DarkGray)
.padding(5.dp)
) {
Text(text = "Mes équipes")
}
Divider(
modifier = Modifier.align(Alignment.Bottom),
color = Color.DarkGray,
thickness = 3.dp
)
//ajouter button add si jamais on fait ajout team en android
}
} ) {
Row { Canvas(
Box( modifier = Modifier.size(30.dp),
modifier = Modifier onDraw = {
.background(Color.DarkGray) drawCircle(color = color)
.padding(5.dp)
) {
Text(text = "Mes dernières stratégies")
} }
Divider( )
modifier = Modifier.align(Alignment.Bottom), }
color = Color.DarkGray, TextCentered(text = text, fontSize = 6.sp)
thickness = 3.dp }
) }
@Composable
fun FilledButton(text: String, onClick: () -> Unit) {
Button(
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.tertiary,
),
onClick = { onClick() }
) {
Text(text)
}
}
@Composable
fun OutlinedButton(text: String, onClick: () -> Unit) {
OutlinedButton(
border = BorderStroke(
1.dp,
color = MaterialTheme.colorScheme.tertiary
),
colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colorScheme.tertiary
),
onClick = { onClick() }) {
Text(text)
}
}
@Composable
fun TextCentered( modifier: Modifier = Modifier, text: String, fontSize: TextUnit = 18.sp, fontWeight: FontWeight? = null) {
Text(text = text,
modifier = modifier
.fillMaxWidth(),
textAlign = TextAlign.Center,
fontSize = fontSize,
fontWeight = fontWeight
)
}
fun getDataFromApi(service: IQBallService) : UserService.UserDataResponse?{
var res : UserService.UserDataResponse? = null
try {
runBlocking {
val result = service.login(AuthService.LoginRequest("yanis@mail.com", "123456"))
when (result) {
is Either.Left -> null
is Either.Right -> {
val data = service.getUserData(result.value.token)
when (data) {
is Either.Left -> null
is Either.Right -> {
res = data.value
}
}
}
} }
} }
return res
} catch (error : Exception) {
return res
} }
}
fun getStubTeam() : ArrayList<Team> {
val teams = ArrayList<Team>()
teams.addAll(
listOf(
Team(1, "equipe1", "https://www.shutterstock.com/image-vector/batman-logo-icon-vector-template-600nw-1998917738.jpg", "#4500FF", "#456789"),
Team(2, "equipe2", "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/2f899b52-daf8-4098-83fe-5c5e27b69915/d4s4nzj-5f915488-7462-4908-b3c5-1605b0e4dc32.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcLzJmODk5YjUyLWRhZjgtNDA5OC04M2ZlLTVjNWUyN2I2OTkxNVwvZDRzNG56ai01ZjkxNTQ4OC03NDYyLTQ5MDgtYjNjNS0xNjA1YjBlNGRjMzIuanBnIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.KqdQgobH9kzyMIeYIneNdyWgKTpGbztwSKqK5pO3YYs", "121212", "#564738"),
Team(3, "equipe3", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ1jiizrhhGsr48WrxxBbDpkFrRKeAYlGgcNQ&usqp=CAU", "#987654", "121212"),
Team(4, "equipe4", "https://www.shutterstock.com/image-vector/batman-logo-icon-vector-template-600nw-1998917738.jpg", "121212", "121212")
)
)
return teams
}
fun getStubTactic() : ArrayList<Tactic> {
val tactics = ArrayList<Tactic>()
tactics.addAll(
listOf(
Tactic(1, "Test", 1, "testType", 1),
Tactic(2, "Test2", 1, "testType", 1),
Tactic(3, "Test3", 4, "test23Type", 1),
Tactic(3, "Test6", 4, "test23Type", 1),
Tactic(1, "Test", 1, "testType", 1),
Tactic(2, "Test2", 1, "testType", 1),
Tactic(3, "Test3", 4, "test23Type", 1),
Tactic(3, "Test6", 4, "test23Type", 1),
Tactic(1, "Test", 1, "testType", 1),
Tactic(2, "Test2", 1, "testType", 1),
Tactic(3, "Test3", 4, "test23Type", 1),
Tactic(3, "Test6", 4, "test23Type", 1),
Tactic(1, "Test", 1, "testType", 1),
Tactic(2, "Test2", 1, "testType", 1),
Tactic(3, "Test3", 4, "test23Type", 1),
Tactic(3, "Test6", 4, "test23Type", 1),
Tactic(1, "Test", 1, "testType", 1),
Tactic(2, "Test2", 1, "testType", 1),
Tactic(3, "Test3", 4, "test23Type", 1),
Tactic(3, "Test6", 4, "test23Type", 1)
)
)
return tactics
} }

@ -10,4 +10,9 @@ val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71) val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260) val Pink40 = Color(0xFF7D5260)
val Orange = Color(0xFFFF8000) val black = Color(0xFF191A21)
val orange = Color(0xFFFFA239)
val blue = Color(0xFF0D6EFD)
val grey = Color(0xFF282A36)
val back = Color(0xFFf8f8f8)

@ -18,23 +18,28 @@ import androidx.core.view.WindowCompat
private val DarkColorScheme = darkColorScheme( private val DarkColorScheme = darkColorScheme(
primary = Purple80, primary = Purple80,
secondary = PurpleGrey80, secondary = PurpleGrey80,
tertiary = Pink80 tertiary = Pink80,
primaryContainer = black
) )
private val LightColorScheme = lightColorScheme( private val LightColorScheme = lightColorScheme(
primary = Purple40, primary = black,
secondary = PurpleGrey40, secondary = orange,
tertiary = Pink40 tertiary = blue,
primaryContainer = black,
surface = grey,
background = back
/* Other default colors to override
background = Color(0xFFFFFBFE), /* Other default colors to override
surface = Color(0xFFFFFBFE), background = Color(0xFFFFFBFE),
onPrimary = Color.White, surface = Color(0xFFFFFBFE),
onSecondary = Color.White, onPrimary = Color.White,
onTertiary = Color.White, onSecondary = Color.White,
onBackground = Color(0xFF1C1B1F), onTertiary = Color.White,
onSurface = Color(0xFF1C1B1F), onBackground = Color(0xFF1C1B1F),
*/ onSurface = Color(0xFF1C1B1F),
*/
) )
@Composable @Composable

Loading…
Cancel
Save