cleanup: suppression du code legacy (v3 pré-hub)

- Activités obsolètes: MainActivity, Jeux, JeuxParametres, ChatGPTTask
- Layouts associés et questionOLD.json (809 lignes)
- Entrées correspondantes du Manifest
Environ 3900 lignes supprimées. EndGameActivity conservée (utilisée par Classic).
This commit is contained in:
Roman
2026-08-19 18:41:07 +00:00
parent 69954bcff2
commit b3722ed776
9 changed files with 2 additions and 3787 deletions
@@ -1,85 +0,0 @@
package com.example.boidelov3;
//public class ChatGPTTask extends AsyncTask<Void, Void, String> {
//// private Jeux jeuxActivity;
//// private String keyOpenai;
////
//// public ChatGPTTask(Jeux jeuxActivity, String keyOpenai) {
//// this.jeuxActivity = jeuxActivity;
//// this.keyOpenai = keyOpenai;
//// }
////
////
//// @Override
//// protected String doInBackground(Void... voids) {
//// String url = "https://api.openai.com/v1/chat/completions";
//// String apiKey = keyOpenai;
//// System.out.println("apiKey de ChatGPTTASK.java: " + apiKey);
//// String model = "gpt-3.5-turbo";
////
//// String prompt = "Tu es une IA française qui génère des questions ainsi que la categories de la question. Voici des exemples :" +
//// "Celles/Ceux qui ont habité dans plus de 3 villes diferentes';'La vie" +
//// "Ceux qui ont dansé aujourd'hui' ; 'Soirée'" +
//// "'Pour se décoincer, le/la plus timide' ; 'Caractère'" +
//// "'Celles et ceux qui ont déjà dépenser plus de 2000 euros en un achat' ; 'Dépense'" +
//// "'Le/La plus radin(e)' ; 'Caractère'";
//
//// try {
//// URL obj = new URL(url);
//// HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
//// connection.setRequestMethod("POST");
//// connection.setRequestProperty("Authorization", "Bearer " + apiKey);
//// connection.setRequestProperty("Content-Type", "application/json");
////
//// // The request body
//// String body = "{\"model\": \"" + model + "\", \"messages\": [{\"role\": \"user\", \"content\": \"" + prompt + "\"}]}";
//// System.out.println("body: " + body);
//// connection.setDoOutput(true);
//// OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
//// writer.write(body);
//// writer.flush();
//// writer.close();
////
//// // Response from ChatGPT
//// BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
//// String line;
////
//// StringBuffer response = new StringBuffer();
////
//// while ((line = br.readLine()) != null) {
//// response.append(line);
//// }
//// br.close();
////
//// // calls the method to extract the message.
//// return extractMessageFromJSONResponse(response.toString());
////
//// } catch (IOException e) {
//// System.out.println("Il y a eu une erreur" + e);
//// throw new RuntimeException(e);
////
//// }
//// }
////
//// public String extractMessageFromJSONResponse(String response) {
//// int start = response.indexOf("content") + 11;
//// int end = response.indexOf("\"", start);
//// String extractedMessage = response.substring(start, end);
//// System.out.println("extractedMessage: " + extractedMessage);
//// return extractedMessage;
//// }
////
//// @Override
//// protected void onPostExecute(String result) {
//// if (result != null) {
//// // Handle the extracted message here
//// jeuxActivity.handleExtractedMessage(result);
//// } else {
//// Toast.makeText(jeuxActivity.getApplicationContext(), "Échec de la communication avec l'API !", Toast.LENGTH_SHORT).show();
//// jeuxActivity.navigateToJeuxParametres();
//// }
//// }
//
//
// return url;
// }}
File diff suppressed because it is too large Load Diff
@@ -1,480 +0,0 @@
package com.example.boidelov3;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CompoundButton;
import com.google.android.material.switchmaterial.SwitchMaterial;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.example.boidelov3.utils.ErrorHandler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class JeuxParametres extends AppCompatActivity {
private SeekBar seekBar1, seekBar2, seekBar3, seekBarDuration;
private TextView textView1, textView2, textView5, textViewRatioGen, questionCountValue, gorgeesValue, durationValue;
private SwitchMaterial checkBoxGPT;
private Button buttonTestApi;
private EditText editText, editTextKeyGPT;
private AutoCompleteTextView autoCompleteProvider;
private String keyGPT;
private OpenAIService.AIProvider selectedProvider = OpenAIService.AIProvider.OPENAI;
private int nbQuestions;
private List<String> toutlesjoueurs;
@Override
protected void onCreate(Bundle savedInstanceState) {
toutlesjoueurs = getIntent().getStringArrayListExtra("EXTRA_LIST_JOUEUR");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jeux_parametres);
// Initialisation des vues
seekBar1 = findViewById(R.id.seekBar1);
seekBar2 = findViewById(R.id.seekBar2);
seekBar3 = findViewById(R.id.seekBar3);
seekBarDuration = findViewById(R.id.seekBarDuration);
textView1 = findViewById(R.id.textView1);
textView2 = findViewById(R.id.textView2);
textView5 = findViewById(R.id.textView5);
editTextKeyGPT = findViewById(R.id.editTextGPT);
autoCompleteProvider = findViewById(R.id.autoCompleteProvider);
buttonTestApi = findViewById(R.id.ButtonTestApi);
textViewRatioGen = findViewById(R.id.textViewRatioGen);
questionCountValue = findViewById(R.id.questionCountValue);
gorgeesValue = findViewById(R.id.gorgeesValue);
durationValue = findViewById(R.id.durationValue);
// Configuration du dropdown pour le provider IA
String[] providers = new String[]{
OpenAIService.AIProvider.OPENAI.getDisplayName(),
OpenAIService.AIProvider.OPENROUTER.getDisplayName(),
OpenAIService.AIProvider.ZAI.getDisplayName()
};
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, providers);
autoCompleteProvider.setAdapter(adapter);
// Charger le provider sauvegardé
SharedPreferences providerPrefs = getSharedPreferences("MyPrefs", MODE_PRIVATE);
String savedProvider = providerPrefs.getString("aiProvider", OpenAIService.AIProvider.OPENAI.getDisplayName());
autoCompleteProvider.setText(savedProvider, false);
// Définir le provider sélectionné
if (savedProvider.equals(OpenAIService.AIProvider.OPENROUTER.getDisplayName())) {
selectedProvider = OpenAIService.AIProvider.OPENROUTER;
} else if (savedProvider.equals(OpenAIService.AIProvider.ZAI.getDisplayName())) {
selectedProvider = OpenAIService.AIProvider.ZAI;
} else {
selectedProvider = OpenAIService.AIProvider.OPENAI;
}
// Listener pour le changement de provider
autoCompleteProvider.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String selected = (String) parent.getItemAtPosition(position);
SharedPreferences.Editor editor = providerPrefs.edit();
editor.putString("aiProvider", selected);
editor.apply();
if (selected.equals(OpenAIService.AIProvider.OPENROUTER.getDisplayName())) {
selectedProvider = OpenAIService.AIProvider.OPENROUTER;
} else if (selected.equals(OpenAIService.AIProvider.ZAI.getDisplayName())) {
selectedProvider = OpenAIService.AIProvider.ZAI;
} else {
selectedProvider = OpenAIService.AIProvider.OPENAI;
}
}
});
// Initialiser les TextView avec les valeurs par défaut
int initialQuestions = 50;
int initialGorgees = 0;
int initialRatio = 8;
int initialDuration = 0; // 0 pour avoir 4-10 tours par défaut (MIN_DEFI_ROUNDS=4)
questionCountValue.setText(String.valueOf(initialQuestions));
gorgeesValue.setText(String.valueOf(initialGorgees));
durationValue.setText("0"); // Afficher 0 par défaut pour avoir 4-10 tours
textView5.setText("Palier : Grosse merde");
textViewRatioGen.setText("Ratio BDD/OPENAI : 1/" + initialRatio);
// Configuration de la seekBar1
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
seekBar1.setMin(20);
}
seekBar1.setMax(150);
seekBar1.setProgress(50);
// Configuration de la seekBar2
seekBar2.setMax(20);
seekBar2.setProgress(0);
// Configuration de la seekBar3
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
seekBar2.setMin(0);
seekBar3.setMin(1);
}
seekBar3.setMax(15);
seekBar3.setProgress(8);
// Configuration de la seekBarDuration (permet valeurs négatives pour offset)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
seekBarDuration.setMin(-5); // Permet un offset négatif jusqu'à -5
}
seekBarDuration.setMax(15);
seekBarDuration.setProgress(0); // Valeur par défaut à 0 pour avoir 4-10 tours (MIN_DEFI_ROUNDS=4)
// Configuration des listeners pour les seekBars
seekBar1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Ajustement de la valeur au multiple de 10 le plus proche
int adjustedProgress = Math.round(progress / 10) * 10;
seekBar.setProgress(adjustedProgress);
questionCountValue.setText(String.valueOf(adjustedProgress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
seekBar2.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Mise à jour du gorgeesValue en fonction de la valeur de la seekBar2
gorgeesValue.setText(String.valueOf(progress));
// Mise à jour du textView5 en fonction de la valeur de la seekBar2
switch (progress) {
case 0:
textView5.setText("Palier : Grosse merde");
break;
case 2:
textView5.setText("Palier : Petite merde");
break;
case 4:
textView5.setText("Palier : Petit joueur");
break;
case 6:
textView5.setText("Palier : Un p'tit verre ?!");
break;
case 8:
textView5.setText("Palier : ça commence à aller");
break;
case 10:
textView5.setText("Palier : Alcoolique");
break;
case 12:
textView5.setText("Palier : COMA ETHYLIX");
break;
case 13:
textView5.setText("Palier : APÉROOOOO !!");
break;
case 14:
textView5.setText("Palier : LA J'SUIS BIENG");
break;
case 15:
textView5.setText("Palier : J'VOIS PLUS RIENG");
break;
case 17:
textView5.setText("Palier : J'AI PLUS DE VERRES");
break;
case 18 :
textView5.setText("Palier : Soirée Murge");
break;
case 19:
textView5.setText("Palier : Soirée Pétée");
break;
case 20:
textView5.setText("Palier : L'ENDER DRAGON");
break;
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// Configuration du checkBox // Q : IL sert à quoi ?
// R : Il sert à activer/désactiver les vues en dessous
Button buttonTestApi = findViewById(R.id.ButtonTestApi);
checkBoxGPT = findViewById(R.id.checkBoxGPT);
checkBoxGPT.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Activation/désactivation des vues en fonction de l'état du checkBox
autoCompleteProvider.setEnabled(isChecked);
// Pour le champ API key : on garde le layout activé pour le toggle password,
// mais on désactive l'édition du texte
editTextKeyGPT.setFocusable(isChecked);
editTextKeyGPT.setFocusableInTouchMode(isChecked);
editTextKeyGPT.setClickable(isChecked);
editTextKeyGPT.setCursorVisible(isChecked);
if (!isChecked) {
editTextKeyGPT.clearFocus();
}
textViewRatioGen.setEnabled(isChecked);
seekBar3.setEnabled(isChecked);
buttonTestApi.setEnabled(isChecked);
}
});
// Configuration de la seekBar3
seekBar3.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar3, int progress, boolean fromUser) {
textViewRatioGen.setText("Ratio BDD/OPENAI : 1/" + progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar3) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar3) {
}
});
// Configuration de la seekBarDuration
seekBarDuration.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Afficher avec signe +/- pour bien voir l'offset, mais sans signe pour 0
String displayValue;
if (progress > 0) {
displayValue = "+" + progress;
} else {
displayValue = String.valueOf(progress); // Affiche "0" ou "-X"
}
durationValue.setText(displayValue);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// Partie OpenAI : enregistrement de la clé en dur.
// Récupérer une instance des SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", MODE_PRIVATE);
final SharedPreferences.Editor editor = sharedPreferences.edit();
// Récupérer l'EditText
final EditText editText = findViewById(R.id.editTextGPT);
// Récupérer la valeur enregistrée dans les SharedPreferences
String apiKey = editText.getText().toString();
// Récupérer la valeur enregistrée dans les SharedPreferences
String savedText = sharedPreferences.getString("savedText", "");
editText.setText(savedText);
// Enregistrer le contenu de l'EditText lorsque l'utilisateur modifie le texte
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
// Enregistrer le texte dans les SharedPreferences
editor.putString("savedText", editText.getText().toString());
editor.apply();
}
});
}
public void onClickButtonTestAPI(View view) {
String apiKey = editTextKeyGPT.getText().toString();
if (apiKey == null || apiKey.isEmpty()) {
Toast.makeText(this, "Veuillez entrer une clé API", Toast.LENGTH_SHORT).show();
return;
}
// Créer un client OkHttpClient pour effectuer la requête
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
.readTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
.build();
// Déterminer l'URL, le modèle et le format selon le provider sélectionné
String testUrl;
String testModel;
String jsonBody;
boolean isAnthropicFormat = (selectedProvider == OpenAIService.AIProvider.ZAI);
switch (selectedProvider) {
case OPENROUTER:
testUrl = "https://openrouter.ai/api/v1/chat/completions";
testModel = "openai/gpt-3.5-turbo";
// Format OpenAI
jsonBody = "{\"model\":\"" + testModel + "\",\"messages\":[{\"role\":\"user\",\"content\":\"Test\"}],\"max_tokens\":5}";
break;
case ZAI:
testUrl = "https://api.z.ai/v1/messages";
testModel = "claude-3-5-sonnet";
// Format Anthropic
jsonBody = "{\"model\":\"" + testModel + "\",\"messages\":[{\"role\":\"user\",\"content\":\"Test\"}],\"max_tokens\":5}";
break;
case OPENAI:
default:
testUrl = "https://api.openai.com/v1/chat/completions";
testModel = "gpt-3.5-turbo";
jsonBody = "{\"model\":\"" + testModel + "\",\"messages\":[{\"role\":\"user\",\"content\":\"Test\"}],\"max_tokens\":5}";
break;
}
// Construire la requête
Request.Builder requestBuilder = new Request.Builder()
.url(testUrl)
.addHeader("Content-Type", "application/json");
// Ajouter les headers selon le provider
switch (selectedProvider) {
case OPENAI:
case OPENROUTER:
requestBuilder.addHeader("Authorization", "Bearer " + apiKey);
break;
case ZAI:
requestBuilder.addHeader("x-api-key", apiKey);
requestBuilder.addHeader("anthropic-version", "2023-06-01");
break;
}
// Headers spécifiques pour OpenRouter
if (selectedProvider == OpenAIService.AIProvider.OPENROUTER) {
requestBuilder.addHeader("HTTP-Referer", "https://boidelo.app");
requestBuilder.addHeader("X-Title", "Boidelo");
}
Request request = requestBuilder
.post(okhttp3.RequestBody.create(jsonBody, okhttp3.MediaType.get("application/json")))
.build();
// Exécuter la requête de test
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, IOException e) {
String operation = "Test de connexion API " + selectedProvider.getDisplayName();
String details = "Échec de connexion lors du test de l'API";
ErrorHandler.logErrorOnly("JeuxParametres", operation + " - " + details, e);
runOnUiThread(() -> {
String userMessage = "Échec de connexion " + selectedProvider.getDisplayName() + " : " + e.getMessage();
Toast.makeText(getApplicationContext(), userMessage, Toast.LENGTH_SHORT).show();
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
runOnUiThread(() -> {
Toast.makeText(getApplicationContext(),
"Connexion " + selectedProvider.getDisplayName() + " réussie !",
Toast.LENGTH_SHORT).show();
});
} else {
runOnUiThread(() -> {
Toast.makeText(getApplicationContext(),
"Erreur " + selectedProvider.getDisplayName() + " (HTTP " + response.code() + ")",
Toast.LENGTH_SHORT).show();
});
}
response.close();
}
});
}
public void onClickButtonStart(View view) {
// Récupérer les paramètres de la partie
int nombreQuestions = seekBar1.getProgress();
int ajoutGorgees = seekBar2.getProgress();
int ratioBddOpenAI = seekBar3.getProgress();
int durationDefis = seekBarDuration.getProgress();
boolean openAI = checkBoxGPT.isChecked();
toutlesjoueurs = getIntent().getStringArrayListExtra("EXTRA_LIST_JOUEUR");
// Récupérer les joueurs (vous devrez définir comment vous les récupérez)
SharedPreferences sharedPreferences = getSharedPreferences("Joueurs", Context.MODE_PRIVATE);
ArrayList<String> joueurs = new ArrayList<>();
for (int i = 1; i <= 3; i++) {
String joueur = sharedPreferences.getString("J" + i, "");
if (!joueur.isEmpty()) {
joueurs.add(joueur);
}
}
// Récupérer les joueurs supplémentaires en utilisant une boucle
int i = 4;
String nomJoueur = sharedPreferences.getString("J" + i, "");
while (!nomJoueur.isEmpty()) {
joueurs.add(nomJoueur);
i++;
nomJoueur = sharedPreferences.getString("J" + i, "");
}
// Créer une instance de la classe Jeux avec les paramètres récupérés
Jeux jeux = new Jeux();
// Lancer l'activité Jeux avec les paramètres
Intent intent = new Intent(this, Jeux.class);
intent.putExtra("EXTRA_NOMBRE_QUESTIONS", nombreQuestions);
intent.putExtra("EXTRA_AJOUT_GORGEE", ajoutGorgees);
intent.putExtra("EXTRA_RATIO_OPENAI", ratioBddOpenAI);
intent.putExtra("EXTRA_DURATION_DEFIS", durationDefis);
intent.putExtra("EXTRA_OPENAI", openAI);
final EditText editText = findViewById(R.id.editTextGPT);
intent.putExtra("EXTRA_KEY_OPENAI", editText.getText().toString());
intent.putExtra("EXTRA_AI_PROVIDER", selectedProvider.name());
toutlesjoueurs = getIntent().getStringArrayListExtra("EXTRA_LIST_JOUEUR");
intent.putStringArrayListExtra("EXTRA_LIST_JOUEUR", (ArrayList<String>) toutlesjoueurs);
startActivity(intent);
}
}
@@ -1,339 +0,0 @@
package com.example.boidelov3;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
String J1S, J2S, J3S;
private int offset;
private List<String> toutlesjoueurs;
private TextInputEditText J1;
private TextInputEditText J2;
private TextInputEditText J3;
private List<TextInputEditText> editTextList = new ArrayList<>();
private List<View> playerRowList = new ArrayList<>(); // Liste des lignes de joueurs pour suppression
private TextView playerCountText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Récupérer le TextView du compteur
playerCountText = findViewById(R.id.playerCountText);
// Initialiser les 3 champs statiques et ajouter les listeners
J1 = findViewById(R.id.J1);
J2 = findViewById(R.id.J2);
J3 = findViewById(R.id.J3);
// Ajouter un TextWatcher à chaque champ pour mettre à jour le compteur
TextWatcher playerCountWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
updatePlayerCount();
}
@Override
public void afterTextChanged(Editable s) {}
};
if (J1 != null) J1.addTextChangedListener(playerCountWatcher);
if (J2 != null) J2.addTextChangedListener(playerCountWatcher);
if (J3 != null) J3.addTextChangedListener(playerCountWatcher);
// Mise à jour initiale
updatePlayerCount();
}
/**
* Met à jour le compteur de joueurs en temps réel
*/
private void updatePlayerCount() {
int count = 0;
if (J1 != null && J1.getText() != null && !J1.getText().toString().isEmpty()) count++;
if (J2 != null && J2.getText() != null && !J2.getText().toString().isEmpty()) count++;
if (J3 != null && J3.getText() != null && !J3.getText().toString().isEmpty()) count++;
// Compter les champs dynamiques
for (TextInputEditText edit : editTextList) {
if (edit != null && edit.getText() != null && !edit.getText().toString().isEmpty()) {
count++;
}
}
if (playerCountText != null) {
playerCountText.setText("Joueurs: " + count + " / min. 3");
}
}
public void onClickButton1(View view) {
LinearLayout nameEntryLayout = findViewById(R.id.nameEntryLayout);
// Créer un conteneur pour la ligne de joueur (EditText + Bouton supprimer)
FrameLayout playerRow = new FrameLayout(this);
LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
rowParams.setMargins(0, 0, 0, 12); // Marge identique aux champs statiques (12dp)
playerRow.setLayoutParams(rowParams);
// Créer un nouveau TextInputLayout
com.google.android.material.textfield.TextInputLayout textInputLayout = new com.google.android.material.textfield.TextInputLayout(this);
FrameLayout.LayoutParams textInputParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
// Plus d'espace pour le bouton poubelle (68dp au lieu de 52dp)
textInputParams.setMargins(0, 0, 68, 0);
textInputLayout.setLayoutParams(textInputParams);
textInputLayout.setBoxBackgroundMode(com.google.android.material.textfield.TextInputLayout.BOX_BACKGROUND_OUTLINE);
textInputLayout.setHint("Nom");
// Appliquer exactement les mêmes styles que le XML
// Créer un ColorStateList pour la bordure : grise par défaut, primaire quand focus
int[][] states = new int[][] {
new int[] { android.R.attr.state_focused},
new int[] {}
};
int[] colors = new int[] {
androidx.core.content.ContextCompat.getColor(this, R.color.primary),
androidx.core.content.ContextCompat.getColor(this, android.R.color.darker_gray) // Bordure grise par défaut
};
android.content.res.ColorStateList strokeColorStateList = new android.content.res.ColorStateList(states, colors);
textInputLayout.setBoxStrokeColorStateList(strokeColorStateList);
textInputLayout.setBoxStrokeWidth(2); // Largeur de bordure comme dans le XML
textInputLayout.setBoxBackgroundColor(androidx.core.content.ContextCompat.getColor(this, R.color.surface));
textInputLayout.setDefaultHintTextColor(androidx.core.content.ContextCompat.getColorStateList(this, R.color.text_hint));
textInputLayout.setEndIconMode(com.google.android.material.textfield.TextInputLayout.END_ICON_CLEAR_TEXT);
// Créer un nouveau TextInputEditText
TextInputEditText newEditText = new TextInputEditText(this);
newEditText.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
newEditText.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS);
newEditText.setMaxLines(1);
newEditText.setTextSize(16);
newEditText.setTextColor(androidx.core.content.ContextCompat.getColor(this, R.color.text_primary));
newEditText.setHintTextColor(androidx.core.content.ContextCompat.getColor(this, R.color.text_hint));
// Ajouter un TextWatcher pour mettre à jour le compteur en temps réel
newEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
updatePlayerCount();
}
@Override
public void afterTextChanged(Editable s) {}
});
// Ajouter l'EditText au TextInputLayout
textInputLayout.addView(newEditText);
// Créer le bouton de suppression - style élégant avec fond circulaire
ImageButton deleteButton = new ImageButton(this);
int dp40 = (int) (40 * getResources().getDisplayMetrics().density);
FrameLayout.LayoutParams buttonParams = new FrameLayout.LayoutParams(dp40, dp40);
buttonParams.setMargins(0, 0, 8, 0);
buttonParams.gravity = android.view.Gravity.END | android.view.Gravity.CENTER_VERTICAL;
deleteButton.setLayoutParams(buttonParams);
// Utiliser l'icône de poubelle Material (ic_menu_delete est une croix)
deleteButton.setImageResource(android.R.drawable.ic_menu_delete);
deleteButton.setColorFilter(androidx.core.content.ContextCompat.getColor(this, R.color.text_secondary));
deleteButton.setScaleType(ImageButton.ScaleType.CENTER_INSIDE);
// Fond circulaire blanc avec bordure fine
deleteButton.setBackgroundColor(androidx.core.content.ContextCompat.getColor(this, R.color.white));
deleteButton.setPadding(8, 8, 8, 8);
// Arrondir le bouton en cercle via un OutlineProvider
deleteButton.setOutlineProvider(new android.view.ViewOutlineProvider() {
@Override
public void getOutline(android.view.View view, android.graphics.Outline outline) {
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
});
deleteButton.setClipToOutline(true);
deleteButton.setContentDescription("Supprimer ce joueur");
// Configuration du bouton de suppression avec animation
deleteButton.setOnClickListener(v -> removePlayerRow(playerRow, newEditText));
// Ajouter les éléments au conteneur
playerRow.addView(textInputLayout);
playerRow.addView(deleteButton);
// Ajouter à la liste et au layout avec animation
editTextList.add(newEditText);
playerRowList.add(playerRow);
nameEntryLayout.addView(playerRow);
// Animation d'apparition
BoideloAnimationUtils.popIn(playerRow, 300);
BoideloAnimationUtils.triggerHapticFeedback(this);
}
/**
* Supprime une ligne de joueur avec animation
*/
private void removePlayerRow(View playerRow, TextInputEditText editText) {
BoideloAnimationUtils.triggerHapticFeedback(this);
// Animation de suppression
BoideloAnimationUtils.slideOutToRemove(playerRow, 300, () -> {
// Retirer de la liste et du layout après l'animation
editTextList.remove(editText);
playerRowList.remove(playerRow);
ViewGroup parent = (ViewGroup) playerRow.getParent();
if (parent != null) {
parent.removeView(playerRow);
}
// Mettre à jour le compteur après suppression
updatePlayerCount();
});
}
public void onClickButtonStart(View view) {
// Récupérer les 3 premiers champs de saisie
J1 = findViewById(R.id.J1);
if (J1 != null && J1.getText() != null) {
J1S = J1.getText().toString();
} else {
J1S = "";
}
J2 = findViewById(R.id.J2);
if (J2 != null && J2.getText() != null) {
J2S = J2.getText().toString();
} else {
J2S = "";
}
J3 = findViewById(R.id.J3);
if (J3 != null && J3.getText() != null) {
J3S = J3.getText().toString();
} else {
J3S = "";
}
// Creation d'une liste avec tt les j et verif si elle est completé
toutlesjoueurs = new ArrayList<>();
if (!J1S.isEmpty()) {
toutlesjoueurs.add(J1S);
}
if (!J2S.isEmpty()) {
toutlesjoueurs.add(J2S);
}
if (!J3S.isEmpty()) {
toutlesjoueurs.add(J3S);
}
// Ajouter les champs dynamiques
int nbnom = editTextList.size();
for (int i = 0; i < nbnom; i++) {
TextInputEditText editText = editTextList.get(i);
if (editText != null && editText.getText() != null) {
String nom = editText.getText().toString();
if (!nom.isEmpty()) {
toutlesjoueurs.add(nom);
}
}
}
openParametres();
}
public void openParametres(){
// Vérifier s'il y a des noms en double (insensible à la casse)
List<String> nomsNormauxes = new ArrayList<>();
for (String nom : toutlesjoueurs) {
String nomNormalise = nom.trim().toLowerCase();
if (nomsNormauxes.contains(nomNormalise)) {
// Nom en double détecté
Context context = getApplicationContext();
CharSequence text = "Erreur : Le nom \"" + nom + "\" est utilisé plusieurs fois. Chaque joueur doit avoir un nom unique.";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
return; // Ne pas continuer
}
nomsNormauxes.add(nomNormalise);
}
//enregistrement des joueurs dans les shared preferences Joueurs
SharedPreferences sharedPreferences = getSharedPreferences("Joueurs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("J1", J1S != null ? J1S : "");
editor.putString("J2", J2S != null ? J2S : "");
editor.putString("J3", J3S != null ? J3S : "");
for (int i = 0; i < editTextList.size(); i++) {
TextInputEditText editText = editTextList.get(i);
if (editText != null && editText.getText() != null) {
String nom = editText.getText().toString();
editor.putString("J" + (i + 4), nom);
}
}
editor.apply();
//Lancement de l'activité (Jeux_parametres)
Intent intent = new Intent(this, JeuxParametres.class);
//Regarde si le pseudo est vide et envoie à l'activité jeux
if (toutlesjoueurs.isEmpty()){
Context context = getApplicationContext();
CharSequence text = "Merci de rentrer des joueurs";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
else {
if (toutlesjoueurs.size() >= 3) {
intent.putStringArrayListExtra("EXTRA_LIST_JOUEUR", (ArrayList<String>) toutlesjoueurs);
intent.putExtra("EXTRA_OFFSET", offset);
startActivity(intent);
} else {
Context context = getApplicationContext();
CharSequence text = "La partie ne peut pas commencer avec moins de 3 joueurs";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
}
}