feat: Ajout du hub de jeux et nouveau mode 89++
Nouvelles fonctionnalités: - Hub de sélection de jeux avec cartes animées - Refonte complète de Boidelo Classic avec nouvelle architecture - Nouveau mode 89++ : assistant de jeu avec timer et défis - Système de joueurs dynamique avec ajout/suppression - Interface moderne et cohérente entre les jeux Améliorations: - Système de défis avec pause pendant l'affichage - Gestion des gorgées avec slider (1-8) - Statistiques de joueurs en temps réel - Bouton retour fonctionnel avec gestion de la notch 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,15 +15,48 @@
|
||||
android:theme="@style/Theme.BoideloV3"
|
||||
tools:targetApi="31">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<activity
|
||||
android:name=".hub.GameSelectionActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.BoideloV3">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Boidelo Classic Activities -->
|
||||
<activity
|
||||
android:name=".games.boideloclassic.BoideloClassicSetupActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".games.boideloclassic.BoideloClassicGameActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".games.boideloclassic.BoideloClassicParamsActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- Game 89++ Activities -->
|
||||
<activity
|
||||
android:name=".games.game89.Game89SetupActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".games.game89.Game89GameActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- Legacy Activities (to be removed) -->
|
||||
$1
|
||||
|
||||
<activity
|
||||
android:name="com.example.boidelov3.Jeux"
|
||||
android:configChanges="orientation|screenSize"
|
||||
|
||||
+914
@@ -0,0 +1,914 @@
|
||||
package com.example.boidelov3.games.boideloclassic;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.example.boidelov3.BoideloAnimationUtils;
|
||||
import com.example.boidelov3.EndGameActivity;
|
||||
import com.example.boidelov3.R;
|
||||
import com.example.boidelov3.data.PlayerStats;
|
||||
import com.example.boidelov3.data.QuestionCategory;
|
||||
import com.example.boidelov3.data.QuestionRepository;
|
||||
import com.example.boidelov3.Question;
|
||||
import com.example.boidelov3.Questions;
|
||||
import com.example.boidelov3.utils.ErrorHandler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* BoideloClassicGameActivity - Activité principale du jeu Boidelo Classic
|
||||
*
|
||||
* Cette activité gère le déroulement du jeu avec les questions, les défis,
|
||||
* les manches et les statistiques des joueurs.
|
||||
*
|
||||
* C'est une version refactorisée de l'ancienne Jeux.java
|
||||
*/
|
||||
public class BoideloClassicGameActivity extends AppCompatActivity {
|
||||
|
||||
// UI Components
|
||||
private TextView questionTextView;
|
||||
private TextView progressTextView;
|
||||
private TextView mancheCounterTextView;
|
||||
private TextView mancheQuestionText;
|
||||
private ProgressBar progressBar;
|
||||
private View suivantButton;
|
||||
private View skipButton;
|
||||
private View questionIndicator;
|
||||
private View indicatorIcon;
|
||||
private TextView indicatorText;
|
||||
private View rootLayout;
|
||||
|
||||
// Bulle pour les défis
|
||||
private PopupWindow defiBubble;
|
||||
|
||||
// Data
|
||||
private List<Question> questions;
|
||||
private ArrayList<String> toutlesjoueurs;
|
||||
private List<Question> questionsAvecManches;
|
||||
private Map<String, PlayerStats> playerStatsMap;
|
||||
|
||||
// Services
|
||||
// private SoundManager soundManager; // TODO: Fix SoundManager constructor
|
||||
// private GameEngine gameEngine; // TODO: Fix GameEngine
|
||||
private QuestionRepository questionRepository;
|
||||
|
||||
// Random
|
||||
private final Random random = new Random();
|
||||
|
||||
// Game Settings
|
||||
private int nombreQuestions = 20;
|
||||
private int ajoutGorgees = 1;
|
||||
private boolean openAI = false;
|
||||
private int ratiOpenai = 5;
|
||||
private String keyOpenai = "";
|
||||
private int durationDefis = 10;
|
||||
|
||||
// Game State
|
||||
private int currentQuestionIndex = 0;
|
||||
private int totalQuestionsAsked = 0;
|
||||
private String currentQuestionText = "";
|
||||
private boolean isMancheActive = false;
|
||||
private boolean isFinishingGame = false;
|
||||
private int questionsSinceLastAI = 0;
|
||||
|
||||
// Constants
|
||||
private static final int MIN_DEFI_ROUNDS = 3;
|
||||
private static final int MAX_DEFI_ROUNDS_RANDOM = 15;
|
||||
private static final int MIN_MANCHES_COUNT = 5;
|
||||
private static final int PREGENERATED_AI_QUESTIONS = 10;
|
||||
private static final int MIN_AI_QUESTION_STOCK = 3;
|
||||
private static final int MIN_AI_GORGEE = 1;
|
||||
private static final int MAX_AI_GORGEE_ADDITIONAL = 4;
|
||||
private static final int RANDOM_PLAYER_SELECTION_COUNT = 3;
|
||||
private static final int TWO_PLAYERS = 2;
|
||||
private static final int ONE_PLAYER = 1;
|
||||
private static final int ANIMATION_DURATION_SHORT_MS = 300;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_boidelo_classic_game);
|
||||
|
||||
// Configure la toolbar avec un bouton retour
|
||||
MaterialToolbar toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setNavigationOnClickListener(v -> finish());
|
||||
|
||||
// Récupère les joueurs depuis l'intent
|
||||
Intent intent = getIntent();
|
||||
toutlesjoueurs = intent.getStringArrayListExtra("PLAYERS");
|
||||
|
||||
initViews();
|
||||
initServices();
|
||||
loadQuestions();
|
||||
initializePlayerStats();
|
||||
setupProgressBar();
|
||||
setupButtonListeners();
|
||||
|
||||
// Affiche la première question
|
||||
displayNewQuestion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise les vues de l'activité
|
||||
*/
|
||||
private void initViews() {
|
||||
questionTextView = findViewById(R.id.questionTextView);
|
||||
progressTextView = findViewById(R.id.progressTextView);
|
||||
mancheCounterTextView = findViewById(R.id.mancheCounterTextView);
|
||||
mancheQuestionText = findViewById(R.id.mancheQuestionText);
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
suivantButton = findViewById(R.id.suivantButton);
|
||||
skipButton = findViewById(R.id.skipButton);
|
||||
questionIndicator = findViewById(R.id.questionIndicator);
|
||||
indicatorIcon = findViewById(R.id.indicatorIcon);
|
||||
indicatorText = findViewById(R.id.indicatorText);
|
||||
rootLayout = findViewById(R.id.rootLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise les services
|
||||
*/
|
||||
private void initServices() {
|
||||
// soundManager = new SoundManager(this); // TODO: Fix SoundManager
|
||||
// gameEngine = new GameEngine(); // TODO: Fix GameEngine
|
||||
questionRepository = new QuestionRepository(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les questions depuis le repository
|
||||
*/
|
||||
private void loadQuestions() {
|
||||
com.example.boidelov3.data.Result<Questions, ?> result = questionRepository.loadQuestions();
|
||||
if (result.isSuccess()) {
|
||||
Questions q = result.getData();
|
||||
questions = q != null && q.getQuestions() != null ? q.getQuestions() : new ArrayList<>();
|
||||
} else {
|
||||
questions = new ArrayList<>();
|
||||
}
|
||||
questionsAvecManches = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise les statistiques des joueurs
|
||||
*/
|
||||
private void initializePlayerStats() {
|
||||
playerStatsMap = new HashMap<>();
|
||||
for (String player : toutlesjoueurs) {
|
||||
playerStatsMap.put(player, new PlayerStats(player));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure la barre de progression
|
||||
*/
|
||||
private void setupProgressBar() {
|
||||
progressBar.setMax(nombreQuestions);
|
||||
progressBar.setProgress(0);
|
||||
updateProgressText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure les écouteurs de boutons
|
||||
*/
|
||||
private void setupButtonListeners() {
|
||||
suivantButton.setOnClickListener(v -> OnClickButton1(null));
|
||||
skipButton.setOnClickListener(v -> onSkipClick(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le texte de progression
|
||||
*/
|
||||
private void updateProgressText() {
|
||||
progressTextView.setText(String.format("%d / %d", currentQuestionIndex, nombreQuestions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour la barre de progression
|
||||
*/
|
||||
private void updateProgressBar() {
|
||||
progressBar.setProgress(currentQuestionIndex);
|
||||
updateProgressText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour la question affichée
|
||||
*/
|
||||
private void updateQuestion() {
|
||||
// Si un défi est en cours, diminuer le compteur
|
||||
if (!questionsAvecManches.isEmpty()) {
|
||||
boolean defiFinished = processActiveManches();
|
||||
if (defiFinished) {
|
||||
// Le défi vient de se terminer, ne pas afficher de nouvelle question
|
||||
return;
|
||||
}
|
||||
// Le défi continue, afficher une nouvelle question normalement
|
||||
}
|
||||
|
||||
// Sinon, vérifier si le jeu doit se terminer
|
||||
if (currentQuestionIndex >= nombreQuestions || shouldEndGame()) {
|
||||
handleGameEnd();
|
||||
} else {
|
||||
displayNewQuestion();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le jeu doit se terminer
|
||||
*/
|
||||
private boolean shouldEndGame() {
|
||||
return currentQuestionIndex >= nombreQuestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère la fin du jeu
|
||||
*/
|
||||
private void handleGameEnd() {
|
||||
isFinishingGame = true;
|
||||
|
||||
// Prépare les stats pour l'activité de fin
|
||||
Intent intent = new Intent(this, EndGameActivity.class);
|
||||
intent.putExtra("PLAYER_STATS", new ArrayList<>(playerStatsMap.values()));
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Traite les manches actives et retourne true si le défi vient de se terminer
|
||||
*/
|
||||
private boolean processActiveManches() {
|
||||
if (questionsAvecManches.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Question mancheQuestion = questionsAvecManches.get(0);
|
||||
int manchesRestantes = mancheQuestion.getManchesRestantes();
|
||||
|
||||
if (manchesRestantes > 0) {
|
||||
// Diminuer le compteur
|
||||
mancheQuestion.setManchesRestantes(manchesRestantes - 1);
|
||||
|
||||
if (manchesRestantes - 1 == 0) {
|
||||
// Fin du défi - sauvegarder la question avant de vider
|
||||
Question finishedDefi = mancheQuestion;
|
||||
questionsAvecManches.clear();
|
||||
|
||||
// Cacher le compteur de manches et le bouton skip
|
||||
mancheCounterTextView.setVisibility(View.GONE);
|
||||
mancheQuestionText.setVisibility(View.GONE);
|
||||
updateSkipButtonVisibility();
|
||||
|
||||
showFinalMancheEndMessage(finishedDefi);
|
||||
return true; // Le défi vient de se terminer
|
||||
} else {
|
||||
// Continuer le défi - juste mettre à jour le compteur
|
||||
updateMancheCounter(manchesRestantes - 1);
|
||||
return false; // Le défi continue, on affichera une nouvelle question
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche le message final de fin de manche
|
||||
*/
|
||||
private void showFinalMancheEndMessage(Question finishedDefi) {
|
||||
// Afficher la question complète du défi qui vient de se terminer
|
||||
String questionText = finishedDefi.getQuestion();
|
||||
String fullMessage = "<b>🏆 Fin du défi !</b><br><br>" + questionText;
|
||||
displayQuestionText(fullMessage);
|
||||
|
||||
// Masquer le compteur de manches
|
||||
mancheCounterTextView.setVisibility(View.GONE);
|
||||
|
||||
// Terminer après un délai plus long pour laisser le temps de lire
|
||||
rootLayout.postDelayed(() -> {
|
||||
// Continuer avec une nouvelle question ou finir le jeu
|
||||
updateQuestion();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche une nouvelle question
|
||||
*/
|
||||
private void displayNewQuestion() {
|
||||
if (questions == null || questions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Question question = selectRandomQuestion();
|
||||
currentQuestionText = question.getQuestion();
|
||||
currentQuestionIndex++;
|
||||
|
||||
// Traiter le texte de la question (remplace J1, variante, manches, etc.)
|
||||
processQuestionText(question);
|
||||
|
||||
// Afficher la question avec couleurs et emojis
|
||||
displayQuestion(question);
|
||||
updateProgressBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sélectionne une question aléatoire en évitant les doublons de défis
|
||||
*/
|
||||
private Question selectRandomQuestion() {
|
||||
boolean hasActiveDefi = !questionsAvecManches.isEmpty();
|
||||
int maxAttempts = questions.size(); // Éviter boucle infinie
|
||||
int attempts = 0;
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
Question question = questions.get(random.nextInt(questions.size()));
|
||||
|
||||
// Si un défi est en cours, éviter les questions avec <manches>
|
||||
if (hasActiveDefi && question.getQuestion().contains("<manches>")) {
|
||||
attempts++;
|
||||
continue;
|
||||
}
|
||||
|
||||
return question;
|
||||
}
|
||||
|
||||
// Si on ne trouve pas de question valide, retourner une question aléatoire
|
||||
return questions.get(random.nextInt(questions.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la notification de fin de manche
|
||||
*/
|
||||
private void showMancheEndNotification() {
|
||||
// TODO: Implémenter la notification de fin de manche
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche une question de manche en petit
|
||||
*/
|
||||
private void displayMancheQuestionSmall(String question) {
|
||||
mancheQuestionText.setText(question);
|
||||
mancheQuestionText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche une question de manche
|
||||
*/
|
||||
private void displayMancheQuestion(String question) {
|
||||
displayMancheQuestionSmall(question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le compteur de manches (affiché pendant un défi)
|
||||
*/
|
||||
private void updateMancheCounter(int manchesRestantes) {
|
||||
String tourWord = manchesRestantes <= 1 ? "tour" : "tours";
|
||||
String restantWord = manchesRestantes <= 1 ? "restant" : "restants";
|
||||
mancheCounterTextView.setText("Défis : " + manchesRestantes + " " + tourWord + " " + restantWord);
|
||||
mancheCounterTextView.setVisibility(View.VISIBLE);
|
||||
|
||||
// Afficher le bouton skip pendant un défi
|
||||
updateSkipButtonVisibility();
|
||||
|
||||
// Créer la bulle pour afficher le défi quand on maintient le clic
|
||||
mancheCounterTextView.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (questionsAvecManches.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Quand on appuie, afficher la bulle
|
||||
showDefiBubble(v);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
// Quand on relâche, cacher la bulle
|
||||
hideDefiBubble();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche la bulle avec la question du défi
|
||||
*/
|
||||
private void showDefiBubble(View anchorView) {
|
||||
if (questionsAvecManches.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Question defi = questionsAvecManches.get(0);
|
||||
|
||||
// Créer le contenu de la bulle
|
||||
LinearLayout bubbleContent = new LinearLayout(this);
|
||||
bubbleContent.setOrientation(LinearLayout.VERTICAL);
|
||||
bubbleContent.setPadding(24, 16, 24, 16);
|
||||
bubbleContent.setBackgroundResource(R.drawable.bg_card);
|
||||
|
||||
TextView bubbleText = new TextView(this);
|
||||
bubbleText.setText(Html.fromHtml(defi.getQuestion(), Html.FROM_HTML_MODE_LEGACY));
|
||||
bubbleText.setTextColor(getColor(R.color.text_primary));
|
||||
bubbleText.setTextSize(16);
|
||||
bubbleContent.addView(bubbleText);
|
||||
|
||||
// Créer la PopupWindow
|
||||
defiBubble = new PopupWindow(bubbleContent, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
defiBubble.setOutsideTouchable(true);
|
||||
defiBubble.setFocusable(true);
|
||||
|
||||
// Afficher la bulle au-dessus du compteur (plus haut que le doigt)
|
||||
defiBubble.showAsDropDown(anchorView, 0, -150, Gravity.CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache la bulle du défi
|
||||
*/
|
||||
private void hideDefiBubble() {
|
||||
if (defiBubble != null && defiBubble.isShowing()) {
|
||||
defiBubble.dismiss();
|
||||
defiBubble = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche une question
|
||||
*/
|
||||
private void displayQuestion(Question question) {
|
||||
displayQuestionText(question.getQuestion());
|
||||
handleMancheQuestionVisibility(question);
|
||||
applyCategoryStyle(question); // Applique la couleur de fond et l'emoji
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche le texte de la question (supporte le HTML pour le gras)
|
||||
*/
|
||||
private void displayQuestionText(String text) {
|
||||
questionTextView.setText(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère la visibilité de la question de manche
|
||||
*/
|
||||
private void handleMancheQuestionVisibility(Question question) {
|
||||
if (question.isManches()) {
|
||||
mancheQuestionText.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mancheQuestionText.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applique le style de catégorie (couleur de fond et emojis)
|
||||
*/
|
||||
private void applyCategoryStyle(Question question) {
|
||||
QuestionCategory.Category category = QuestionCategory.detectCategory(question);
|
||||
|
||||
// Réinitialiser les indicateurs
|
||||
questionIndicator.setVisibility(View.GONE);
|
||||
|
||||
// Appliquer la couleur de fond
|
||||
int categoryColor = QuestionCategory.getColorForCategory(category);
|
||||
BoideloAnimationUtils.animateBackgroundColor(rootLayout, categoryColor, 300);
|
||||
|
||||
// N'afficher l'indicateur que si un défi n'est PAS en cours
|
||||
if (questionsAvecManches.isEmpty()) {
|
||||
String indicatorText = getCategoryQuestionIndicator(category, question);
|
||||
if (!indicatorText.isEmpty()) {
|
||||
showQuestionIndicatorWithEmoji(indicatorText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'emoji associé à une catégorie
|
||||
*/
|
||||
private String getCategoryEmoji(QuestionCategory.Category category) {
|
||||
switch (category) {
|
||||
case CIBLAGE:
|
||||
return "🎯";
|
||||
case CLASSEMENT:
|
||||
return "👑";
|
||||
case JUGEMENT:
|
||||
return "⚖️";
|
||||
case DUEL:
|
||||
return "🤝";
|
||||
case INTERACTIF:
|
||||
return "🎮";
|
||||
case DEFI_MANCHES:
|
||||
return "🔥";
|
||||
case VARIANTE:
|
||||
return "❓";
|
||||
case CALIENTE:
|
||||
return "😈";
|
||||
case VOTE:
|
||||
return "🗳️";
|
||||
case CLASSIQUE:
|
||||
default:
|
||||
return "⚪";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine le texte de l'indicateur en fonction du nombre de joueurs et de la catégorie
|
||||
*/
|
||||
private String getCategoryQuestionIndicator(QuestionCategory.Category category, Question question) {
|
||||
String categoryEmoji = getCategoryEmoji(category);
|
||||
String categoryName = QuestionCategory.getNameForCategory(category);
|
||||
int playerCount = toutlesjoueurs.size();
|
||||
|
||||
// Pour les questions spéciales, on affiche juste l'emoji et la catégorie
|
||||
if (category == QuestionCategory.Category.CALIENTE ||
|
||||
category == QuestionCategory.Category.DEFI_MANCHES ||
|
||||
category == QuestionCategory.Category.INTERACTIF) {
|
||||
return categoryEmoji + " " + categoryName;
|
||||
}
|
||||
|
||||
// Pour les autres, on affiche l'emoji + nombre de joueurs
|
||||
return categoryEmoji + " " + playerCount + " joueurs";
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche l'indicateur avec le texte spécifié et animation
|
||||
*/
|
||||
private void showQuestionIndicatorWithEmoji(String text) {
|
||||
indicatorText.setText(text);
|
||||
questionIndicator.setVisibility(View.VISIBLE);
|
||||
BoideloAnimationUtils.fadeIn(questionIndicator, 300);
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine l'indicateur de nombre de joueurs
|
||||
*/
|
||||
private String determinePlayerCountIndicator(Question question) {
|
||||
return String.format("%d joueurs", toutlesjoueurs.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche l'indicateur de texte
|
||||
*/
|
||||
private void showIndicatorText(String text) {
|
||||
indicatorText.setText(text);
|
||||
questionIndicator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche l'indicateur de question
|
||||
*/
|
||||
private void showQuestionIndicator(Question question) {
|
||||
showIndicatorText("❓ " + determinePlayerCountIndicator(question));
|
||||
}
|
||||
|
||||
/**
|
||||
* Passe la question
|
||||
*/
|
||||
private void skipQuestion() {
|
||||
updateQuestion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Termine le jeu
|
||||
*/
|
||||
private void endGame() {
|
||||
handleGameEnd();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// TRAITEMENT DU TEXTE DES QUESTIONS
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Traite le texte de la question pour remplacer tous les placeholders
|
||||
*/
|
||||
private void processQuestionText(Question question) {
|
||||
String questionText = question.getQuestion();
|
||||
|
||||
// Remplacer les variantes
|
||||
questionText = processVariantes(question, questionText);
|
||||
|
||||
// Gérer les manches
|
||||
questionText = processManches(question, questionText);
|
||||
|
||||
// Remplacer les joueurs et récupérer le nom du joueur J1 pour les stats
|
||||
PlayerSelectionResult playerResult = replacePlayers(questionText);
|
||||
questionText = playerResult.questionText;
|
||||
|
||||
// Ajouter les gorgées et tracker les stats
|
||||
GorgeeResult gorgeeResult = processGorgees(question, questionText, playerResult.playerCount);
|
||||
questionText = gorgeeResult.questionText;
|
||||
|
||||
// Mettre à jour les statistiques du joueur J1
|
||||
if (playerResult.j1Name != null) {
|
||||
updatePlayerStats(playerResult.j1Name, gorgeeResult);
|
||||
}
|
||||
|
||||
question.setQuestion(questionText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remplace les variantes dans la question
|
||||
*/
|
||||
private String processVariantes(Question question, String questionText) {
|
||||
if (question.getVariante() != null && !question.getVariante().isEmpty()) {
|
||||
String chosenVariante = question.getVariante().get(random.nextInt(question.getVariante().size()));
|
||||
questionText = questionText.replace("<variante>", chosenVariante);
|
||||
}
|
||||
return questionText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère les manches pour les défis
|
||||
*/
|
||||
private String processManches(Question question, String questionText) {
|
||||
if (questionText.contains("<manches>")) {
|
||||
int nbaleatoiremanches = calculateManchesCount();
|
||||
questionText = questionText.replace("<manches>", String.valueOf(nbaleatoiremanches));
|
||||
question.setManchesRestantes(nbaleatoiremanches);
|
||||
|
||||
// Définir le message de fin de défi
|
||||
String stopMessage = "Fin de défi!\n" + question.getQuestion();
|
||||
question.setArretMessageManche(stopMessage);
|
||||
|
||||
questionsAvecManches.add(question);
|
||||
|
||||
// Afficher le compteur de manches initial
|
||||
updateMancheCounter(nbaleatoiremanches);
|
||||
}
|
||||
return questionText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le nombre de manches pour un défi
|
||||
*/
|
||||
private int calculateManchesCount() {
|
||||
int nbaleatoiremanches = random.nextInt(MAX_DEFI_ROUNDS_RANDOM) + MIN_DEFI_ROUNDS + durationDefis;
|
||||
return Math.max(nbaleatoiremanches, MIN_MANCHES_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Résultat du remplacement des joueurs
|
||||
*/
|
||||
private static class PlayerSelectionResult {
|
||||
String questionText;
|
||||
String j1Name;
|
||||
int playerCount;
|
||||
|
||||
PlayerSelectionResult(String questionText, String j1Name, int playerCount) {
|
||||
this.questionText = questionText;
|
||||
this.j1Name = j1Name;
|
||||
this.playerCount = playerCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remplace les placeholders de joueurs dans la question
|
||||
*/
|
||||
private PlayerSelectionResult replacePlayers(String questionText) {
|
||||
boolean isJoueurs1 = questionText.contains("<J1>");
|
||||
boolean isJoueurs2 = questionText.contains("<J2>");
|
||||
boolean isJoueurs3 = questionText.contains("<J3>");
|
||||
|
||||
String j1Name = null;
|
||||
int playerCount = 0;
|
||||
|
||||
if (isJoueurs1 || isJoueurs2 || isJoueurs3) {
|
||||
List<String> aleatoirejoueurs = TroisJoueurAleatoire();
|
||||
|
||||
if (isJoueurs1 && isJoueurs2 && isJoueurs3 && aleatoirejoueurs.size() >= RANDOM_PLAYER_SELECTION_COUNT) {
|
||||
playerCount = 3;
|
||||
j1Name = aleatoirejoueurs.get(0);
|
||||
questionText = questionText.replace("<J1>", ErrorHandler.escapeHtml(j1Name));
|
||||
questionText = questionText.replace("<J2>", ErrorHandler.escapeHtml(aleatoirejoueurs.get(1)));
|
||||
questionText = questionText.replace("<J3>", ErrorHandler.escapeHtml(aleatoirejoueurs.get(2)));
|
||||
} else if (isJoueurs1 && isJoueurs2 && aleatoirejoueurs.size() >= TWO_PLAYERS) {
|
||||
playerCount = 2;
|
||||
j1Name = aleatoirejoueurs.get(0);
|
||||
questionText = questionText.replace("<J1>", ErrorHandler.escapeHtml(j1Name));
|
||||
questionText = questionText.replace("<J2>", ErrorHandler.escapeHtml(aleatoirejoueurs.get(1)));
|
||||
} else if (isJoueurs1 && aleatoirejoueurs.size() >= ONE_PLAYER) {
|
||||
playerCount = 1;
|
||||
j1Name = aleatoirejoueurs.get(0);
|
||||
questionText = questionText.replace("<J1>", ErrorHandler.escapeHtml(j1Name));
|
||||
}
|
||||
}
|
||||
|
||||
return new PlayerSelectionResult(questionText, j1Name, playerCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Résultat du traitement des gorgées
|
||||
*/
|
||||
private static class GorgeeResult {
|
||||
String questionText;
|
||||
int totalGorgees;
|
||||
boolean isBois;
|
||||
boolean isDistribue;
|
||||
|
||||
GorgeeResult(String questionText, int totalGorgees, boolean isBois, boolean isDistribue) {
|
||||
this.questionText = questionText;
|
||||
this.totalGorgees = totalGorgees;
|
||||
this.isBois = isBois;
|
||||
this.isDistribue = isDistribue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Résultat du choix d'action (bois/distribue)
|
||||
*/
|
||||
private static class ActionChoiceResult {
|
||||
String questionText;
|
||||
boolean isBois;
|
||||
boolean isDistribue;
|
||||
|
||||
ActionChoiceResult(String questionText, boolean isBois, boolean isDistribue) {
|
||||
this.questionText = questionText;
|
||||
this.isBois = isBois;
|
||||
this.isDistribue = isDistribue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Traite les gorgées pour une question
|
||||
*/
|
||||
private GorgeeResult processGorgees(Question question, String questionText, int playerCount) {
|
||||
int totalGorgees = 0;
|
||||
boolean isBois = false;
|
||||
boolean isDistribue = false;
|
||||
|
||||
if (question.isDistribution() || question.isRecois()) {
|
||||
totalGorgees = question.getGorger() + ajoutGorgees;
|
||||
|
||||
ActionChoiceResult actionResult = determineActionChoice(question, questionText, playerCount);
|
||||
questionText = actionResult.questionText;
|
||||
isBois = actionResult.isBois;
|
||||
isDistribue = actionResult.isDistribue;
|
||||
|
||||
questionText = appendGorgeeCount(questionText, totalGorgees);
|
||||
}
|
||||
|
||||
return new GorgeeResult(questionText, totalGorgees, isBois, isDistribue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine l'action (boit/boivent ou distribue/distribuent) selon le nombre de joueurs
|
||||
*/
|
||||
private ActionChoiceResult determineActionChoice(Question question, String questionText, int playerCount) {
|
||||
boolean isBois = false;
|
||||
boolean isDistribue = false;
|
||||
|
||||
// Accord du verbe selon le nombre de joueurs
|
||||
String boisVerb = (playerCount > 1) ? "boivent" : "boit";
|
||||
String distribueVerb = (playerCount > 1) ? "distribuent" : "distribue";
|
||||
|
||||
if (question.isRecois() && question.isDistribution()) {
|
||||
boolean rand = random.nextBoolean();
|
||||
if (rand) {
|
||||
questionText = questionText + " <b>" + boisVerb + "</b>";
|
||||
isBois = true;
|
||||
} else {
|
||||
questionText = questionText + " <b>" + distribueVerb + "</b>";
|
||||
isDistribue = true;
|
||||
}
|
||||
} else if (question.isRecois()) {
|
||||
questionText = questionText + " <b>" + boisVerb + "</b>";
|
||||
isBois = true;
|
||||
} else if (question.isDistribution()) {
|
||||
questionText = questionText + " <b>" + distribueVerb + "</b>";
|
||||
isDistribue = true;
|
||||
}
|
||||
|
||||
return new ActionChoiceResult(questionText, isBois, isDistribue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute le nombre de gorgées au texte de la question
|
||||
*/
|
||||
private String appendGorgeeCount(String questionText, int totalGorgees) {
|
||||
String plural = totalGorgees > 1 ? "s" : "";
|
||||
return questionText + " " + totalGorgees + " gorgée" + plural + ".";
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour les statistiques du joueur J1
|
||||
*/
|
||||
private void updatePlayerStats(String j1Name, GorgeeResult gorgeeResult) {
|
||||
if (j1Name == null) return;
|
||||
|
||||
PlayerStats stats = playerStatsMap.get(j1Name);
|
||||
if (stats == null) {
|
||||
stats = new PlayerStats(j1Name);
|
||||
playerStatsMap.put(j1Name, stats);
|
||||
}
|
||||
|
||||
if (gorgeeResult.isBois) {
|
||||
stats.addGorgeesBuves(gorgeeResult.totalGorgees);
|
||||
}
|
||||
|
||||
if (gorgeeResult.isDistribue) {
|
||||
stats.addGorgeesDistribuees(gorgeeResult.totalGorgees);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde les stats du jeu
|
||||
*/
|
||||
private void saveGameStats() {
|
||||
// TODO: Implémenter la sauvegarde des stats
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialise les questions demandées
|
||||
*/
|
||||
private void resetAskedQuestions() {
|
||||
currentQuestionIndex = 0;
|
||||
totalQuestionsAsked = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sélectionne 3 joueurs aléatoires
|
||||
*/
|
||||
private ArrayList<String> TroisJoueurAleatoire() {
|
||||
ArrayList<String> selection = new ArrayList<>();
|
||||
if (toutlesjoueurs.size() <= 3) {
|
||||
return new ArrayList<>(toutlesjoueurs);
|
||||
}
|
||||
|
||||
while (selection.size() < 3) {
|
||||
String player = toutlesjoueurs.get(random.nextInt(toutlesjoueurs.size()));
|
||||
if (!selection.contains(player)) {
|
||||
selection.add(player);
|
||||
}
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère le clic sur le bouton suivant
|
||||
*/
|
||||
public void OnClickButton1(View view) {
|
||||
updateQuestion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère le clic sur le bouton skip (Abandonner le défi)
|
||||
*/
|
||||
public void onSkipClick(View view) {
|
||||
// Si un défi est en cours, l'abandonner complètement
|
||||
if (!questionsAvecManches.isEmpty()) {
|
||||
abandonDefi();
|
||||
}
|
||||
|
||||
// Continuer normalement
|
||||
skipQuestion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Abandonne complètement le défi en cours
|
||||
*/
|
||||
private void abandonDefi() {
|
||||
// Supprimer le défi en cours
|
||||
questionsAvecManches.clear();
|
||||
|
||||
// Cacher le compteur de manches
|
||||
mancheCounterTextView.setVisibility(View.GONE);
|
||||
mancheQuestionText.setVisibility(View.GONE);
|
||||
|
||||
// Cacher le bouton skip
|
||||
updateSkipButtonVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour la visibilité du bouton skip (affiché seulement pendant un défi)
|
||||
*/
|
||||
private void updateSkipButtonVisibility() {
|
||||
if (!questionsAvecManches.isEmpty()) {
|
||||
skipButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
skipButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
// Fermer la bulle si elle est ouverte
|
||||
hideDefiBubble();
|
||||
// if (soundManager != null) {
|
||||
// soundManager.release();
|
||||
// }
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.example.boidelov3.games.boideloclassic;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.example.boidelov3.R;
|
||||
|
||||
/**
|
||||
* BoideloClassicParamsActivity - Écran de paramètres pour Boidelo Classic
|
||||
*
|
||||
* Cette activité permet de configurer les paramètres du jeu :
|
||||
* - Nombre de questions
|
||||
* - Nombre de gorgées
|
||||
* - Activation/désactivation de l'IA
|
||||
* - Durée des défis
|
||||
*
|
||||
* C'est une version refactorisée de l'ancienne JeuxParametres.java
|
||||
*/
|
||||
public class BoideloClassicParamsActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_boidelo_classic_params);
|
||||
|
||||
// Configure la barre d'action avec un bouton retour
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle(R.string.parameters);
|
||||
}
|
||||
|
||||
initViews();
|
||||
setupListeners();
|
||||
loadCurrentSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise les vues de l'activité
|
||||
*/
|
||||
private void initViews() {
|
||||
// TODO: Initialiser les vues pour les paramètres
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure les écouteurs d'événements
|
||||
*/
|
||||
private void setupListeners() {
|
||||
// TODO: Configurer les listeners pour les changements de paramètres
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les paramètres actuels depuis les préférences
|
||||
*/
|
||||
private void loadCurrentSettings() {
|
||||
// TODO: Charger les paramètres depuis SharedPreferences
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde les paramètres
|
||||
*/
|
||||
private void saveSettings() {
|
||||
// TODO: Sauvegarder les paramètres dans SharedPreferences
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package com.example.boidelov3.games.boideloclassic;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.example.boidelov3.R;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BoideloClassicSetupActivity - Écran de configuration du jeu Boidelo Classic
|
||||
* Version simplifiée comme 89++
|
||||
*/
|
||||
public class BoideloClassicSetupActivity extends AppCompatActivity {
|
||||
|
||||
private static final int MIN_PLAYERS = 3;
|
||||
private static final int MAX_PLAYERS = 15;
|
||||
|
||||
private LinearLayout playersContainer;
|
||||
private MaterialButton addPlayerButton;
|
||||
private MaterialButton startGameButton;
|
||||
private TextView playerCountText;
|
||||
private MaterialToolbar toolbar;
|
||||
|
||||
private final List<String> playerNames = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_boidelo_classic_setup);
|
||||
|
||||
initViews();
|
||||
setupToolbar();
|
||||
setupListeners();
|
||||
|
||||
// Ajouter 3 joueurs par défaut
|
||||
addPlayerRow();
|
||||
addPlayerRow();
|
||||
addPlayerRow();
|
||||
|
||||
// Initialiser le compteur
|
||||
updatePlayerCountText();
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
playersContainer = findViewById(R.id.playersContainer);
|
||||
addPlayerButton = findViewById(R.id.addPlayerButton);
|
||||
startGameButton = findViewById(R.id.startGameButton);
|
||||
playerCountText = findViewById(R.id.playerCountText);
|
||||
}
|
||||
|
||||
private void setupToolbar() {
|
||||
toolbar.setNavigationOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
addPlayerButton.setOnClickListener(v -> {
|
||||
if (playersContainer.getChildCount() < MAX_PLAYERS) {
|
||||
addPlayerRow();
|
||||
} else {
|
||||
Toast.makeText(this, "Maximum " + MAX_PLAYERS + " joueurs", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
startGameButton.setOnClickListener(v -> startGame());
|
||||
}
|
||||
|
||||
private void addPlayerRow() {
|
||||
View playerRow = LayoutInflater.from(this).inflate(R.layout.item_player_row, playersContainer, false);
|
||||
|
||||
TextInputEditText playerNameEdit = playerRow.findViewById(R.id.playerName);
|
||||
MaterialButton removeButton = playerRow.findViewById(R.id.removePlayerButton);
|
||||
TextView playerNumber = playerRow.findViewById(R.id.playerNumber);
|
||||
|
||||
int position = playersContainer.getChildCount();
|
||||
playerNumber.setText(String.valueOf(position + 1));
|
||||
|
||||
// Cacher le bouton de suppression pour les 3 premiers joueurs (minimum requis)
|
||||
if (position < MIN_PLAYERS) {
|
||||
removeButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
removeButton.setOnClickListener(v -> {
|
||||
if (playersContainer.getChildCount() > MIN_PLAYERS) {
|
||||
playersContainer.removeView(playerRow);
|
||||
updatePlayerNumbers();
|
||||
updatePlayerNames();
|
||||
} else {
|
||||
Toast.makeText(this, "Minimum " + MIN_PLAYERS + " joueurs", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
playerNameEdit.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (!hasFocus) {
|
||||
updatePlayerNames();
|
||||
}
|
||||
});
|
||||
|
||||
playersContainer.addView(playerRow);
|
||||
updatePlayerCountText();
|
||||
updateStartButton();
|
||||
}
|
||||
|
||||
private void updatePlayerNumbers() {
|
||||
for (int i = 0; i < playersContainer.getChildCount(); i++) {
|
||||
View row = playersContainer.getChildAt(i);
|
||||
TextView playerNumber = row.findViewById(R.id.playerNumber);
|
||||
playerNumber.setText(String.valueOf(i + 1));
|
||||
|
||||
// Afficher le bouton de suppression uniquement au-delà du minimum
|
||||
MaterialButton removeButton = row.findViewById(R.id.removePlayerButton);
|
||||
if (i >= MIN_PLAYERS) {
|
||||
removeButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
removeButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
updatePlayerCountText();
|
||||
}
|
||||
|
||||
private void updatePlayerNames() {
|
||||
playerNames.clear();
|
||||
for (int i = 0; i < playersContainer.getChildCount(); i++) {
|
||||
View row = playersContainer.getChildAt(i);
|
||||
TextInputEditText edit = row.findViewById(R.id.playerName);
|
||||
String name = edit.getText().toString().trim();
|
||||
if (!TextUtils.isEmpty(name)) {
|
||||
playerNames.add(name);
|
||||
} else {
|
||||
playerNames.add("Joueur " + (i + 1));
|
||||
}
|
||||
}
|
||||
updateStartButton();
|
||||
}
|
||||
|
||||
private void updatePlayerCountText() {
|
||||
int count = playersContainer.getChildCount();
|
||||
playerCountText.setText("Joueurs: " + count + " / min. " + MIN_PLAYERS);
|
||||
}
|
||||
|
||||
private void updateStartButton() {
|
||||
int validPlayers = playersContainer.getChildCount();
|
||||
boolean canStart = validPlayers >= MIN_PLAYERS;
|
||||
startGameButton.setEnabled(canStart);
|
||||
startGameButton.setText(canStart ? "JOUER (" + validPlayers + ")" : "Ajoutez des joueurs");
|
||||
}
|
||||
|
||||
private void startGame() {
|
||||
// Vérifier que tous les champs minimums sont remplis
|
||||
ArrayList<String> validNames = new ArrayList<>();
|
||||
for (int i = 0; i < playersContainer.getChildCount(); i++) {
|
||||
View row = playersContainer.getChildAt(i);
|
||||
TextInputEditText edit = row.findViewById(R.id.playerName);
|
||||
String name = edit.getText().toString().trim();
|
||||
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
Toast.makeText(this, "Veuillez remplir le nom du joueur " + (i + 1), Toast.LENGTH_SHORT).show();
|
||||
edit.requestFocus();
|
||||
return;
|
||||
}
|
||||
validNames.add(name);
|
||||
}
|
||||
|
||||
if (validNames.size() < MIN_PLAYERS) {
|
||||
Toast.makeText(this, "Minimum " + MIN_PLAYERS + " joueurs requis", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(this, BoideloClassicGameActivity.class);
|
||||
intent.putStringArrayListExtra("PLAYERS", validNames);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.example.boidelov3.games.boideloclassic.manager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* BoideloPlayerManager - Gestionnaire des joueurs pour Boidelo Classic
|
||||
* Cette classe gère la liste des joueurs et leurs informations
|
||||
*/
|
||||
public class BoideloPlayerManager {
|
||||
|
||||
private ArrayList<String> players;
|
||||
|
||||
public BoideloPlayerManager() {
|
||||
this.players = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute un joueur à la liste
|
||||
* @param playerName Le nom du joueur à ajouter
|
||||
*/
|
||||
public void addPlayer(String playerName) {
|
||||
if (playerName != null && !playerName.trim().isEmpty()) {
|
||||
players.add(playerName.trim());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un joueur de la liste
|
||||
* @param index L'index du joueur à supprimer
|
||||
*/
|
||||
public void removePlayer(int index) {
|
||||
if (index >= 0 && index < players.size()) {
|
||||
players.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des joueurs
|
||||
* @return La liste des noms des joueurs
|
||||
*/
|
||||
public ArrayList<String> getPlayers() {
|
||||
return new ArrayList<>(players);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le nombre de joueurs
|
||||
* @return Le nombre de joueurs
|
||||
*/
|
||||
public int getPlayerCount() {
|
||||
return players.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vide la liste des joueurs
|
||||
*/
|
||||
public void clearPlayers() {
|
||||
players.clear();
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package com.example.boidelov3.games.boideloclassic.manager;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import com.example.boidelov3.R;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* BoideloPlayerRowManager - Gestionnaire des lignes de saisie de joueurs
|
||||
* Cette classe gère l'ajout et la suppression dynamique de champs de saisie
|
||||
* avec Material Design
|
||||
*/
|
||||
public class BoideloPlayerRowManager {
|
||||
|
||||
private Activity activity;
|
||||
private LinearLayout nameEntryLayout;
|
||||
private BoideloPlayerManager playerManager;
|
||||
private ArrayList<LinearLayout> playerRowList;
|
||||
private ArrayList<TextInputEditText> editTextList;
|
||||
|
||||
private int offset = 4; // Nombre initial de joueurs fixes (J1, J2, J3)
|
||||
|
||||
public BoideloPlayerRowManager(Activity activity, LinearLayout nameEntryLayout,
|
||||
BoideloPlayerManager playerManager) {
|
||||
this.activity = activity;
|
||||
this.nameEntryLayout = nameEntryLayout;
|
||||
this.playerManager = playerManager;
|
||||
this.playerRowList = new ArrayList<>();
|
||||
this.editTextList = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute une nouvelle ligne de saisie pour un joueur
|
||||
*/
|
||||
public void addPlayerRow() {
|
||||
// Inflate le layout Material Design
|
||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||
LinearLayout newRow = (LinearLayout) inflater.inflate(R.layout.item_player_row, nameEntryLayout, false);
|
||||
|
||||
// Configure le numéro du joueur
|
||||
TextView playerNumber = newRow.findViewById(R.id.playerNumber);
|
||||
playerNumber.setText(String.valueOf(offset));
|
||||
|
||||
// Récupère le champ de saisie
|
||||
TextInputEditText editText = newRow.findViewById(R.id.playerName);
|
||||
editText.setHint("Joueur " + offset);
|
||||
editTextList.add(editText);
|
||||
|
||||
// Configure le bouton de suppression
|
||||
MaterialButton removeButton = newRow.findViewById(R.id.removePlayerButton);
|
||||
removeButton.setOnClickListener(v -> removePlayerRow(newRow));
|
||||
|
||||
// Ajoute la ligne au conteneur
|
||||
nameEntryLayout.addView(newRow);
|
||||
playerRowList.add(newRow);
|
||||
offset++;
|
||||
|
||||
// Notifie le gestionnaire de joueurs
|
||||
playerManager.addPlayer("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime une ligne de joueur
|
||||
* @param row La ligne à supprimer
|
||||
*/
|
||||
public void removePlayerRow(LinearLayout row) {
|
||||
int index = playerRowList.indexOf(row);
|
||||
if (index >= 0) {
|
||||
nameEntryLayout.removeView(row);
|
||||
playerRowList.remove(index);
|
||||
if (index < editTextList.size()) {
|
||||
editTextList.remove(index);
|
||||
}
|
||||
offset--;
|
||||
|
||||
// Met à jour les numéros de joueurs
|
||||
updatePlayerNumbers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour les numéros affichés pour tous les joueurs
|
||||
*/
|
||||
private void updatePlayerNumbers() {
|
||||
for (int i = 0; i < playerRowList.size(); i++) {
|
||||
LinearLayout row = playerRowList.get(i);
|
||||
TextView playerNumber = row.findViewById(R.id.playerNumber);
|
||||
if (playerNumber != null) {
|
||||
playerNumber.setText(String.valueOf(4 + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne les noms des joueurs depuis les champs dynamiques
|
||||
* @return La liste des noms des joueurs
|
||||
*/
|
||||
public ArrayList<String> getPlayerNames() {
|
||||
ArrayList<String> names = new ArrayList<>();
|
||||
for (TextInputEditText editText : editTextList) {
|
||||
String name = editText.getText() != null ? editText.getText().toString().trim() : "";
|
||||
if (!name.isEmpty()) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le nombre total de lignes
|
||||
* @return Le nombre de lignes
|
||||
*/
|
||||
public int getRowCount() {
|
||||
return playerRowList.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.example.boidelov3.games.game89;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Gère les défis du jeu 89++
|
||||
*/
|
||||
public class Game89ChallengeManager {
|
||||
private final Random random;
|
||||
private final List<Challenge> availableChallenges;
|
||||
|
||||
public Game89ChallengeManager() {
|
||||
this.random = new Random();
|
||||
this.availableChallenges = new ArrayList<>();
|
||||
initializeChallenges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise la liste des défis disponibles
|
||||
*/
|
||||
private void initializeChallenges() {
|
||||
// Changer le sens
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.REVERSE_DIRECTION,
|
||||
"Changement de sens !",
|
||||
"Le sens du jeu est inversé !"
|
||||
));
|
||||
|
||||
// Immunité
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.IMMUNITY,
|
||||
"Immunité !",
|
||||
"Le joueur actuel est immunisé contre les gorgées pendant 5 minutes !"
|
||||
));
|
||||
|
||||
// Distribuer des gorgées
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.DRINK_GORGEE,
|
||||
"Gorgée surprise !",
|
||||
"Le joueur actuel boit 3 gorgées !"
|
||||
));
|
||||
|
||||
// Joker : passer son tour
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.SKIP_TURN,
|
||||
"Joker !",
|
||||
"Le joueur actuel passe son tour !"
|
||||
));
|
||||
|
||||
// Échange de main
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.SWAP_HAND,
|
||||
"Échange de mains !",
|
||||
"Le joueur actuel échange sa main avec le joueur de son choix !"
|
||||
));
|
||||
|
||||
// Double prochaine valeur
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.DOUBLE_NEXT,
|
||||
"Double !",
|
||||
"La prochaine carte jouée compte double !"
|
||||
));
|
||||
|
||||
// Compteur aléatoire
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.RANDOM_COUNT,
|
||||
"Compte mystère !",
|
||||
"Ajoutez un nombre aléatoire entre 1 et 10 au compteur !"
|
||||
));
|
||||
|
||||
// Tout le monde boit
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.EVERYONE_DRINKS,
|
||||
"Tour générale !",
|
||||
"Tout le monde boit 2 gorgées !"
|
||||
));
|
||||
|
||||
// Choisissez une victime
|
||||
availableChallenges.add(new Challenge(
|
||||
ChallengeType.PICK_VICTIM,
|
||||
"Victime !",
|
||||
"Le joueur actuel choisit quelqu'un qui boit 3 gorgées !"
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne un défi aléatoire
|
||||
*/
|
||||
public Challenge getRandomChallenge() {
|
||||
if (availableChallenges.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
int index = random.nextInt(availableChallenges.size());
|
||||
return availableChallenges.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la description d'un défi pour l'afficher
|
||||
*/
|
||||
public static String getChallengeDisplay(Challenge challenge) {
|
||||
if (challenge == null) {
|
||||
return "";
|
||||
}
|
||||
return challenge.getTitle() + "\n" + challenge.getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Classe représentant un défi
|
||||
*/
|
||||
public static class Challenge {
|
||||
private final ChallengeType type;
|
||||
private final String title;
|
||||
private final String description;
|
||||
|
||||
public Challenge(ChallengeType type, String title, String description) {
|
||||
this.type = type;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public ChallengeType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Types de défis disponibles
|
||||
*/
|
||||
public enum ChallengeType {
|
||||
REVERSE_DIRECTION,
|
||||
IMMUNITY,
|
||||
DRINK_GORGEE,
|
||||
SKIP_TURN,
|
||||
SWAP_HAND,
|
||||
DOUBLE_NEXT,
|
||||
RANDOM_COUNT,
|
||||
EVERYONE_DRINKS,
|
||||
PICK_VICTIM
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package com.example.boidelov3.games.game89;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.GridLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.example.boidelov3.R;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Assistant pour le jeu 89++ - Affiche les défis et gère le timer
|
||||
* Les joueurs jouent avec de vraies cartes, l'application est juste un assistant
|
||||
*/
|
||||
public class Game89GameActivity extends AppCompatActivity {
|
||||
|
||||
// UI Components
|
||||
private MaterialToolbar toolbar;
|
||||
private TextView timerTextView;
|
||||
private TextView challengeTitleTextView;
|
||||
private TextView challengeDescriptionTextView;
|
||||
private View challengeContainer;
|
||||
private MaterialButton recordDrinksButton;
|
||||
private MaterialButton showStatsButton;
|
||||
|
||||
// Game Data
|
||||
private List<Game89Player> players;
|
||||
private Game89ChallengeManager challengeManager;
|
||||
private int challengeTimerMinutes;
|
||||
private CountDownTimer challengeTimer;
|
||||
private long timeUntilNextChallenge;
|
||||
private Game89ChallengeManager.Challenge currentChallenge;
|
||||
private boolean challengeActive = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_game89_game);
|
||||
|
||||
// Get intent data
|
||||
ArrayList<String> playerNames = getIntent().getStringArrayListExtra("PLAYERS");
|
||||
challengeTimerMinutes = getIntent().getIntExtra("CHALLENGE_TIMER_MINUTES", 1);
|
||||
|
||||
if (playerNames == null || playerNames.isEmpty()) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
initViews();
|
||||
setupToolbar();
|
||||
setupGame(playerNames);
|
||||
setupListeners();
|
||||
startChallengeTimer();
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
timerTextView = findViewById(R.id.timerTextView);
|
||||
challengeTitleTextView = findViewById(R.id.challengeTitleTextView);
|
||||
challengeDescriptionTextView = findViewById(R.id.challengeDescriptionTextView);
|
||||
challengeContainer = findViewById(R.id.challengeContainer);
|
||||
recordDrinksButton = findViewById(R.id.recordDrinksButton);
|
||||
showStatsButton = findViewById(R.id.showStatsButton);
|
||||
}
|
||||
|
||||
private void setupToolbar() {
|
||||
toolbar.setNavigationOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
private void setupGame(ArrayList<String> playerNames) {
|
||||
players = new ArrayList<>();
|
||||
for (String name : playerNames) {
|
||||
players.add(new Game89Player(name));
|
||||
}
|
||||
|
||||
challengeManager = new Game89ChallengeManager();
|
||||
|
||||
// Show initial state
|
||||
challengeContainer.setVisibility(View.GONE);
|
||||
timerTextView.setText("En attente du premier défi...");
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
recordDrinksButton.setOnClickListener(v -> showRecordDrinksDialog());
|
||||
showStatsButton.setOnClickListener(v -> showStatsDialog());
|
||||
|
||||
// Click on challenge to dismiss it and resume timer
|
||||
challengeContainer.setOnClickListener(v -> dismissChallenge());
|
||||
}
|
||||
|
||||
private void startChallengeTimer() {
|
||||
// Ne pas démarrer si un défi est actif
|
||||
if (challengeActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
timeUntilNextChallenge = challengeTimerMinutes * 60 * 1000L;
|
||||
|
||||
challengeTimer = new CountDownTimer(timeUntilNextChallenge, 1000) {
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
// Arrêter le tick si un défi est devenu actif
|
||||
if (challengeActive) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
timeUntilNextChallenge = millisUntilFinished;
|
||||
long minutes = millisUntilFinished / 60000;
|
||||
long seconds = (millisUntilFinished % 60000) / 1000;
|
||||
timerTextView.setText(String.format(Locale.getDefault(),
|
||||
"Prochain défi dans: %d:%02d", minutes, seconds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
// Ne déclencher que si aucun défi n'est actif
|
||||
if (!challengeActive) {
|
||||
triggerChallenge();
|
||||
startChallengeTimer(); // Restart timer for next challenge
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void triggerChallenge() {
|
||||
currentChallenge = challengeManager.getRandomChallenge();
|
||||
if (currentChallenge == null) return;
|
||||
|
||||
challengeActive = true;
|
||||
|
||||
// Pause the timer
|
||||
if (challengeTimer != null) {
|
||||
challengeTimer.cancel();
|
||||
}
|
||||
|
||||
// Update UI - Hide timer text when challenge is active
|
||||
timerTextView.setVisibility(View.GONE);
|
||||
challengeContainer.setVisibility(View.VISIBLE);
|
||||
challengeTitleTextView.setText(currentChallenge.getTitle());
|
||||
challengeDescriptionTextView.setText(currentChallenge.getDescription());
|
||||
|
||||
// Vibrate to alert players
|
||||
try {
|
||||
android.os.Vibrator vibrator = (android.os.Vibrator) getSystemService(android.content.Context.VIBRATOR_SERVICE);
|
||||
if (vibrator != null) {
|
||||
vibrator.vibrate(new long[]{0, 300, 200, 300}, -1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore vibration errors
|
||||
}
|
||||
}
|
||||
|
||||
private void dismissChallenge() {
|
||||
challengeContainer.setVisibility(View.GONE);
|
||||
challengeActive = false;
|
||||
timerTextView.setVisibility(View.VISIBLE);
|
||||
|
||||
// Resume the timer
|
||||
startChallengeTimer();
|
||||
}
|
||||
|
||||
private void showRecordDrinksDialog() {
|
||||
if (players.isEmpty()) return;
|
||||
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
||||
builder.setTitle("Enregistrer des gorgées");
|
||||
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.setPadding(50, 40, 50, 10);
|
||||
|
||||
// Create player selection
|
||||
String[] playerNames = new String[players.size()];
|
||||
for (int i = 0; i < players.size(); i++) {
|
||||
playerNames[i] = players.get(i).getName();
|
||||
}
|
||||
|
||||
final int[] selectedPlayer = {0};
|
||||
|
||||
TextView label = new TextView(this);
|
||||
label.setText("Sélectionnez le joueur:");
|
||||
label.setPadding(0, 0, 0, 20);
|
||||
layout.addView(label);
|
||||
|
||||
// Create a grid of buttons for each player
|
||||
GridLayout playerGrid = new GridLayout(this);
|
||||
playerGrid.setColumnCount(2);
|
||||
|
||||
for (int i = 0; i < players.size(); i++) {
|
||||
final int playerIndex = i;
|
||||
MaterialButton playerButton = new MaterialButton(this);
|
||||
playerButton.setText(players.get(i).getName());
|
||||
playerButton.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
|
||||
GridLayout.LayoutParams params = new GridLayout.LayoutParams();
|
||||
params.setMargins(8, 8, 8, 8);
|
||||
playerButton.setLayoutParams(params);
|
||||
|
||||
playerButton.setOnClickListener(v -> {
|
||||
selectedPlayer[0] = playerIndex;
|
||||
showGorgeesCountDialog(playerIndex);
|
||||
});
|
||||
|
||||
playerGrid.addView(playerButton);
|
||||
}
|
||||
|
||||
layout.addView(playerGrid);
|
||||
|
||||
builder.setView(layout);
|
||||
builder.setNegativeButton("Fermer", null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void showGorgeesCountDialog(int playerIndex) {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
||||
builder.setTitle("Gorgées pour " + players.get(playerIndex).getName());
|
||||
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.setPadding(60, 50, 60, 20);
|
||||
|
||||
// Label pour afficher la valeur actuelle
|
||||
TextView valueLabel = new TextView(this);
|
||||
valueLabel.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
valueLabel.setTextSize(24);
|
||||
valueLabel.setText("1 gorgée");
|
||||
valueLabel.setPadding(0, 0, 0, 20);
|
||||
layout.addView(valueLabel);
|
||||
|
||||
// SeekBar de 1 à 8
|
||||
SeekBar seekBar = new SeekBar(this);
|
||||
seekBar.setMax(7); // 0-7, donc 1-8 avec le +1
|
||||
seekBar.setProgress(0); // Commence à 1 (0 + 1)
|
||||
seekBar.setPadding(0, 0, 0, 20);
|
||||
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
int value = progress + 1; // 1-8
|
||||
valueLabel.setText(value + " gorgée" + (value > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
|
||||
layout.addView(seekBar);
|
||||
|
||||
builder.setView(layout);
|
||||
|
||||
builder.setPositiveButton("Valider", (dialog, which) -> {
|
||||
int count = seekBar.getProgress() + 1; // 1-8
|
||||
players.get(playerIndex).addGorgees(count);
|
||||
Toast.makeText(this,
|
||||
players.get(playerIndex).getName() + " boit " + count + " gorgée(s)!",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
|
||||
builder.setNegativeButton("Annuler", null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void showStatsDialog() {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
||||
builder.setTitle("Statistiques des gorgées");
|
||||
|
||||
StringBuilder stats = new StringBuilder();
|
||||
for (Game89Player player : players) {
|
||||
stats.append(player.getName())
|
||||
.append(": ")
|
||||
.append(player.getTotalGorgees())
|
||||
.append(" gorgée(s)\n\n");
|
||||
}
|
||||
|
||||
builder.setMessage(stats.toString());
|
||||
builder.setPositiveButton("Fermer", null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (challengeTimer != null) {
|
||||
challengeTimer.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.example.boidelov3.games.game89;
|
||||
|
||||
/**
|
||||
* Représente un joueur du jeu 89++ (version simplifiée pour assistant)
|
||||
*/
|
||||
public class Game89Player {
|
||||
private final String name;
|
||||
private int totalGorgees;
|
||||
|
||||
public Game89Player(String name) {
|
||||
this.name = name;
|
||||
this.totalGorgees = 0;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute des gorgées aux statistiques du joueur
|
||||
*/
|
||||
public void addGorgees(int count) {
|
||||
this.totalGorgees += count;
|
||||
}
|
||||
|
||||
public int getTotalGorgees() {
|
||||
return totalGorgees;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (" + totalGorgees + " gorgées)";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package com.example.boidelov3.games.game89;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.example.boidelov3.R;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity de configuration pour le jeu 89++
|
||||
*/
|
||||
public class Game89SetupActivity extends AppCompatActivity {
|
||||
|
||||
private static final int MIN_PLAYERS = 2;
|
||||
private static final int MAX_PLAYERS = 10;
|
||||
|
||||
private LinearLayout playersContainer;
|
||||
private MaterialButton addPlayerButton;
|
||||
private MaterialButton startGameButton;
|
||||
private SeekBar timerSeekBar;
|
||||
private TextView timerText;
|
||||
private MaterialToolbar toolbar;
|
||||
|
||||
private final List<String> playerNames = new ArrayList<>();
|
||||
private int challengeTimerMinutes = 1;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_game89_setup);
|
||||
|
||||
initViews();
|
||||
setupToolbar();
|
||||
setupListeners();
|
||||
|
||||
// Ajouter 2 joueurs par défaut
|
||||
addPlayerRow();
|
||||
addPlayerRow();
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
playersContainer = findViewById(R.id.playersContainer);
|
||||
addPlayerButton = findViewById(R.id.addPlayerButton);
|
||||
startGameButton = findViewById(R.id.startGameButton);
|
||||
timerSeekBar = findViewById(R.id.timerSeekBar);
|
||||
timerText = findViewById(R.id.timerText);
|
||||
}
|
||||
|
||||
private void setupToolbar() {
|
||||
toolbar.setNavigationOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
addPlayerButton.setOnClickListener(v -> {
|
||||
if (playerNames.size() < MAX_PLAYERS) {
|
||||
addPlayerRow();
|
||||
} else {
|
||||
Toast.makeText(this, "Maximum " + MAX_PLAYERS + " joueurs", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
startGameButton.setOnClickListener(v -> startGame());
|
||||
|
||||
timerSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
challengeTimerMinutes = progress;
|
||||
updateTimerText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void addPlayerRow() {
|
||||
View playerRow = LayoutInflater.from(this).inflate(R.layout.item_player_row, playersContainer, false);
|
||||
|
||||
TextInputEditText playerNameEdit = playerRow.findViewById(R.id.playerName);
|
||||
MaterialButton removeButton = playerRow.findViewById(R.id.removePlayerButton);
|
||||
TextView playerNumber = playerRow.findViewById(R.id.playerNumber);
|
||||
|
||||
int position = playersContainer.getChildCount();
|
||||
playerNumber.setText(String.valueOf(position + 1));
|
||||
|
||||
// Cacher le bouton de suppression pour les 2 premiers joueurs (minimum requis)
|
||||
if (position < MIN_PLAYERS) {
|
||||
removeButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
removeButton.setOnClickListener(v -> {
|
||||
if (playersContainer.getChildCount() > MIN_PLAYERS) {
|
||||
playersContainer.removeView(playerRow);
|
||||
updatePlayerNumbers();
|
||||
updatePlayerNames();
|
||||
} else {
|
||||
Toast.makeText(this, "Minimum " + MIN_PLAYERS + " joueurs", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
playerNameEdit.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (!hasFocus) {
|
||||
updatePlayerNames();
|
||||
}
|
||||
});
|
||||
|
||||
playersContainer.addView(playerRow);
|
||||
}
|
||||
|
||||
private void updatePlayerNumbers() {
|
||||
for (int i = 0; i < playersContainer.getChildCount(); i++) {
|
||||
View row = playersContainer.getChildAt(i);
|
||||
TextView playerNumber = row.findViewById(R.id.playerNumber);
|
||||
playerNumber.setText(String.valueOf(i + 1));
|
||||
|
||||
// Afficher le bouton de suppression uniquement au-delà du minimum
|
||||
MaterialButton removeButton = row.findViewById(R.id.removePlayerButton);
|
||||
if (i >= MIN_PLAYERS) {
|
||||
removeButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
removeButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePlayerNames() {
|
||||
playerNames.clear();
|
||||
for (int i = 0; i < playersContainer.getChildCount(); i++) {
|
||||
View row = playersContainer.getChildAt(i);
|
||||
TextInputEditText edit = row.findViewById(R.id.playerName);
|
||||
String name = edit.getText().toString().trim();
|
||||
if (!TextUtils.isEmpty(name)) {
|
||||
playerNames.add(name);
|
||||
} else {
|
||||
playerNames.add("Joueur " + (i + 1));
|
||||
}
|
||||
}
|
||||
updateStartButton();
|
||||
}
|
||||
|
||||
private void updateStartButton() {
|
||||
int validPlayers = playerNames.size();
|
||||
boolean canStart = validPlayers >= MIN_PLAYERS;
|
||||
startGameButton.setEnabled(canStart);
|
||||
startGameButton.setText(canStart ? "JOUER (" + validPlayers + ")" : "Ajoutez des joueurs");
|
||||
}
|
||||
|
||||
private void updateTimerText() {
|
||||
timerText.setText(challengeTimerMinutes + " minute" + (challengeTimerMinutes > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
private void startGame() {
|
||||
updatePlayerNames();
|
||||
|
||||
if (playerNames.size() < MIN_PLAYERS) {
|
||||
Toast.makeText(this, "Minimum " + MIN_PLAYERS + " joueurs requis", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(this, Game89GameActivity.class);
|
||||
intent.putStringArrayListExtra("PLAYERS", new ArrayList<>(playerNames));
|
||||
intent.putExtra("CHALLENGE_TIMER_MINUTES", challengeTimerMinutes);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.example.boidelov3.hub;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.example.boidelov3.R;
|
||||
import com.example.boidelov3.games.boideloclassic.BoideloClassicSetupActivity;
|
||||
import com.example.boidelov3.hub.adapter.GameAdapter;
|
||||
import com.example.boidelov3.hub.model.GameInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* GameSelectionActivity - Hub principal de sélection des jeux
|
||||
* Cette activité remplace l'ancienne MainActivity et sert de point d'entrée
|
||||
* pour tous les jeux disponibles dans Boidelo.
|
||||
*/
|
||||
public class GameSelectionActivity extends AppCompatActivity implements GameAdapter.OnItemClickListener {
|
||||
|
||||
private RecyclerView gamesRecyclerView;
|
||||
private GameAdapter gameAdapter;
|
||||
private List<GameInfo> gamesList;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_game_selection);
|
||||
|
||||
initViews();
|
||||
setupGamesList();
|
||||
setupRecyclerView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise les vues de l'activité
|
||||
*/
|
||||
private void initViews() {
|
||||
gamesRecyclerView = findViewById(R.id.gamesRecyclerView);
|
||||
gamesRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure la liste des jeux disponibles
|
||||
*/
|
||||
private void setupGamesList() {
|
||||
gamesList = new ArrayList<>();
|
||||
|
||||
// Boidelo Classic - Le jeu original
|
||||
gamesList.add(new GameInfo(
|
||||
"Boidelo Classic",
|
||||
"Le jeu original de questions et défis",
|
||||
R.drawable.ic_boidelo_classic,
|
||||
GameInfo.GameType.BOIDELO_CLASSIC,
|
||||
true
|
||||
));
|
||||
|
||||
// 89++ - Jeu de cartes
|
||||
gamesList.add(new GameInfo(
|
||||
"89++",
|
||||
"Jeu de cartes avec timer et défis",
|
||||
R.drawable.ic_game_89,
|
||||
GameInfo.GameType.GAME_89,
|
||||
true // Available now
|
||||
));
|
||||
|
||||
// Undercover - Jeu de déduction
|
||||
gamesList.add(new GameInfo(
|
||||
"Undercover",
|
||||
"Trouvez l'undercover avant qu'il ne soit trop tard!",
|
||||
R.drawable.ic_undercover,
|
||||
GameInfo.GameType.UNDERCOVER,
|
||||
false // Coming soon
|
||||
));
|
||||
|
||||
// Jeux de règles
|
||||
gamesList.add(new GameInfo(
|
||||
"Règles de jeux",
|
||||
"Découvrez les règles des jeux d'ambiance populaires",
|
||||
R.drawable.ic_rules,
|
||||
GameInfo.GameType.RULES,
|
||||
false // Coming soon
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure le RecyclerView avec l'adaptateur
|
||||
*/
|
||||
private void setupRecyclerView() {
|
||||
gameAdapter = new GameAdapter(gamesList, this);
|
||||
gamesRecyclerView.setAdapter(gameAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère le clic sur un jeu de la liste
|
||||
* @param gameInfo Le jeu sélectionné
|
||||
*/
|
||||
@Override
|
||||
public void onItemClick(GameInfo gameInfo) {
|
||||
if (!gameInfo.isAvailable()) {
|
||||
// Afficher un message "Coming soon"
|
||||
return;
|
||||
}
|
||||
|
||||
switch (gameInfo.getGameType()) {
|
||||
case BOIDELO_CLASSIC:
|
||||
startActivity(new Intent(this, BoideloClassicSetupActivity.class));
|
||||
break;
|
||||
case GAME_89:
|
||||
startActivity(new Intent(this, com.example.boidelov3.games.game89.Game89SetupActivity.class));
|
||||
break;
|
||||
case UNDERCOVER:
|
||||
// TODO: Implémenter UndercoverSetupActivity
|
||||
break;
|
||||
case RULES:
|
||||
// TODO: Implémenter RulesListActivity
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.example.boidelov3.hub.adapter;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.example.boidelov3.R;
|
||||
import com.example.boidelov3.hub.model.GameInfo;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* GameAdapter - Adaptateur pour afficher la liste des jeux dans le RecyclerView
|
||||
*/
|
||||
public class GameAdapter extends RecyclerView.Adapter<GameAdapter.GameViewHolder> {
|
||||
|
||||
private List<GameInfo> gamesList;
|
||||
private OnItemClickListener listener;
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(GameInfo gameInfo);
|
||||
}
|
||||
|
||||
public GameAdapter(List<GameInfo> gamesList, OnItemClickListener listener) {
|
||||
this.gamesList = gamesList;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GameViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_game_card, parent, false);
|
||||
return new GameViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull GameViewHolder holder, int position) {
|
||||
GameInfo gameInfo = gamesList.get(position);
|
||||
holder.bind(gameInfo, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return gamesList.size();
|
||||
}
|
||||
|
||||
static class GameViewHolder extends RecyclerView.ViewHolder {
|
||||
private ImageView gameIcon;
|
||||
private TextView gameName;
|
||||
private TextView gameDescription;
|
||||
private View statusText;
|
||||
|
||||
public GameViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
gameIcon = itemView.findViewById(R.id.gameIcon);
|
||||
gameName = itemView.findViewById(R.id.gameName);
|
||||
gameDescription = itemView.findViewById(R.id.gameDescription);
|
||||
statusText = itemView.findViewById(R.id.statusText);
|
||||
}
|
||||
|
||||
public void bind(GameInfo gameInfo, OnItemClickListener listener) {
|
||||
gameName.setText(gameInfo.getName());
|
||||
gameDescription.setText(gameInfo.getDescription());
|
||||
gameIcon.setImageResource(gameInfo.getIconResId());
|
||||
|
||||
if (gameInfo.isAvailable()) {
|
||||
statusText.setVisibility(View.GONE);
|
||||
itemView.setEnabled(true);
|
||||
itemView.setAlpha(1.0f);
|
||||
itemView.setOnClickListener(v -> listener.onItemClick(gameInfo));
|
||||
} else {
|
||||
statusText.setVisibility(View.VISIBLE);
|
||||
itemView.setEnabled(false);
|
||||
itemView.setAlpha(0.6f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.example.boidelov3.hub.model;
|
||||
|
||||
/**
|
||||
* GameInfo - Modèle représentant un jeu dans le hub
|
||||
* Contient les informations de base pour afficher et lancer un jeu
|
||||
*/
|
||||
public class GameInfo {
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
private int iconResId;
|
||||
private GameType gameType;
|
||||
private boolean available;
|
||||
|
||||
public enum GameType {
|
||||
BOIDELO_CLASSIC,
|
||||
GAME_89,
|
||||
UNDERCOVER,
|
||||
RULES
|
||||
}
|
||||
|
||||
public GameInfo(String name, String description, int iconResId, GameType gameType, boolean available) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.iconResId = iconResId;
|
||||
this.gameType = gameType;
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public String getName() { return name; }
|
||||
public String getDescription() { return description; }
|
||||
public int getIconResId() { return iconResId; }
|
||||
public GameType getGameType() { return gameType; }
|
||||
public boolean isAvailable() { return available; }
|
||||
|
||||
// Setters
|
||||
public void setAvailable(boolean available) { this.available = available; }
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/white"/>
|
||||
<solid android:color="@color/card_background"/>
|
||||
<corners android:radius="16dp"/>
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/primary"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/accent"
|
||||
android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2zM7,7h2v2H7V7zM11,7h2v2h-2V7zM15,7h2v2h-2V7zM7,11h2v2H7v-2zM11,11h2v2h-2v-2zM15,11h2v2h-2v-2zM7,15h10v2H7v-2z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/accent"
|
||||
android:pathData="M18,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zM6,4h5v8l-2.5,-1.5L6,12V4z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/primary"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,213 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".games.boideloclassic.BoideloClassicGameActivity">
|
||||
|
||||
<!-- App Bar -->
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/primary"
|
||||
app:navigationIcon="@android:drawable/ic_menu_revert"
|
||||
app:title="Boidelo Classic"
|
||||
app:titleTextColor="@color/text_on_primary" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<!-- Main Content -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<!-- Progress Bar -->
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="8dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:max="100"
|
||||
android:progress="0"
|
||||
android:progressTint="@color/accent"
|
||||
android:progressBackgroundTint="@color/surface_variant"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<!-- Progress Text -->
|
||||
<TextView
|
||||
android:id="@+id/progressTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Question 1 / 50"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/progressBar" />
|
||||
|
||||
<!-- Question Type Indicator -->
|
||||
<LinearLayout
|
||||
android:id="@+id/questionIndicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/progressTextView">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/indicatorIcon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/ic_player_one"
|
||||
app:tint="@color/text_secondary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/indicatorText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="1 joueur"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Main Question Container -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/questionCard"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardElevation="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/buttonContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/questionIndicator">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<!-- Manche Counter -->
|
||||
<TextView
|
||||
android:id="@+id/mancheCounterTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/bg_card"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:text="Manches: 5"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!-- Manche Question Text (petit) -->
|
||||
<TextView
|
||||
android:id="@+id/mancheQuestionText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:gravity="center"
|
||||
android:text="Défi en cours"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="italic"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Question Text -->
|
||||
<TextView
|
||||
android:id="@+id/questionTextView"
|
||||
style="@style/BoideloQuestionText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Question"
|
||||
android:textSize="26sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Button Container -->
|
||||
<LinearLayout
|
||||
android:id="@+id/buttonContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<!-- Skip Button -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/skipButton"
|
||||
style="@style/BoideloButton"
|
||||
android:layout_width="229dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:onClick="onSkipClick"
|
||||
android:text="Abandonner le défi"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/error"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="@color/surface_variant"
|
||||
app:cornerRadius="28dp" />
|
||||
|
||||
<!-- Next Button -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/suivantButton"
|
||||
style="@style/BoideloButton.Primary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_weight="2"
|
||||
android:onClick="OnClickButton1"
|
||||
android:text="Suivant"
|
||||
android:textSize="18sp"
|
||||
app:cornerRadius="28dp"
|
||||
app:icon="@android:drawable/ic_media_play"
|
||||
app:iconGravity="textEnd" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/surface"
|
||||
tools:context=".games.boideloclassic.BoideloClassicParamsActivity">
|
||||
|
||||
<!-- App Bar -->
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/primary"
|
||||
app:navigationIcon="@android:drawable/ic_menu_revert"
|
||||
app:title="@string/parameters"
|
||||
app:titleTextColor="@color/text_on_primary" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<!-- Main Content -->
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Title -->
|
||||
<TextView
|
||||
style="@style/BoideloTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/game_settings" />
|
||||
|
||||
<!-- Game Settings Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Number of Questions -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/number_of_questions"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/questionsSeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:max="50"
|
||||
android:min="10"
|
||||
android:progress="20" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/questionsCountText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/accent"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="20 questions" />
|
||||
|
||||
<!-- Number of Gorgées -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/number_of_gorgees"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/gorgeesSeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:max="5"
|
||||
android:min="1"
|
||||
android:progress="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gorgeesCountText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/accent"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="+1 gorgée" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- AI Settings Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/artificial_intelligence"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/aiSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/enable_ai_questions"
|
||||
android:textColor="@color/text_hint"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Save Button -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/saveButton"
|
||||
style="@style/BoideloButton.Primary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,147 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".games.boideloclassic.BoideloClassicSetupActivity">
|
||||
|
||||
<!-- App Bar -->
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/primary"
|
||||
app:navigationIcon="@android:drawable/ic_menu_revert"
|
||||
app:title="Boidelo Classic"
|
||||
app:titleTextColor="@android:color/white" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<!-- Main Content -->
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Title -->
|
||||
<TextView
|
||||
style="@style/BoideloTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/boidelo_classic_setup_title"
|
||||
android:textColor="@color/primary" />
|
||||
|
||||
<!-- Game Description Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Le jeu original de questions et défis"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp"
|
||||
android:gravity="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Players Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/players"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playerCountText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/min_players_required"
|
||||
android:textColor="@color/accent"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/playersContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/addPlayerButton"
|
||||
style="@style/BoideloButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/add_player"
|
||||
app:icon="@android:drawable/ic_input_add" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Start Button -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/startGameButton"
|
||||
style="@style/BoideloButton.Primary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/start_game"
|
||||
android:textSize="18sp"
|
||||
app:icon="@android:drawable/ic_media_play" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,240 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background"
|
||||
tools:context=".games.game89.Game89GameActivity">
|
||||
|
||||
<!-- App Bar -->
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/primary"
|
||||
app:navigationIcon="@android:drawable/ic_menu_revert"
|
||||
app:title="89++ - Assistant"
|
||||
app:titleTextColor="@android:color/white" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<!-- Main Content -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<!-- Timer Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/timerCard"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/primary"
|
||||
app:cardCornerRadius="24dp"
|
||||
app:cardElevation="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="32dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Assistant 89++"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timerTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Prochain défi dans: 2:00"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Jouez avec vos cartes physiques !"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="14sp"
|
||||
android:alpha="0.9" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Challenge Display -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/challengeContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardBackgroundColor="@color/accent"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardElevation="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/timerCard"
|
||||
tools:visibility="visible">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="⚠️ DÉFI !"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/challengeTitleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Changement de sens !"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/challengeDescriptionTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Le sens du jeu est inversé !"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="👆 Tapez pour continuer"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:alpha="0.7"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<LinearLayout
|
||||
android:id="@+id/actionButtons"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/challengeContainer">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/recordDrinksButton"
|
||||
style="@style/BoideloButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="🍺 Enregistrer\ngorgées"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp"
|
||||
app:backgroundTint="@android:color/white"
|
||||
app:cornerRadius="20dp"
|
||||
app:strokeColor="@color/primary"
|
||||
app:strokeWidth="2dp"
|
||||
android:elevation="2dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/showStatsButton"
|
||||
style="@style/BoideloButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="📊 Voir\nstatistiques"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp"
|
||||
app:backgroundTint="@android:color/white"
|
||||
app:cornerRadius="20dp"
|
||||
app:strokeColor="@color/primary"
|
||||
app:strokeWidth="2dp"
|
||||
android:elevation="2dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Info Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:cardBackgroundColor="@android:color/white"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/actionButtons">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="💡 Rappel des règles"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="• Valet = -10\n• Dame = Change sens\n• Roi = Choisissez la valeur\n• Dizaine (10, 20...) = distribuez des gorgées\n• 70 = DOUBLE (14 gorgées!)"
|
||||
android:textColor="@color/text_hint"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,191 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/surface"
|
||||
tools:context=".games.game89.Game89SetupActivity">
|
||||
|
||||
<!-- App Bar -->
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/primary"
|
||||
app:navigationIcon="@android:drawable/ic_menu_revert"
|
||||
app:title="89++ - Configuration"
|
||||
app:titleTextColor="@color/text_on_primary" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<!-- Main Content -->
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Title -->
|
||||
<TextView
|
||||
style="@style/BoideloTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/game_89_title"
|
||||
android:textColor="@color/primary" />
|
||||
|
||||
<!-- Game Rules Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/game_rules"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/game_89_rules_summary"
|
||||
android:textColor="@color/text_hint"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Players Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/players"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/playersContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/addPlayerButton"
|
||||
style="@style/BoideloButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/add_player"
|
||||
app:icon="@android:drawable/ic_input_add" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Challenge Timer Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/challenge_timer"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/timerSeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:max="2"
|
||||
android:min="1"
|
||||
android:progress="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timerText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:text="1 minute"
|
||||
android:textColor="@color/accent"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Start Button -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/startGameButton"
|
||||
style="@style/BoideloButton.Primary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/start_game"
|
||||
android:textSize="18sp"
|
||||
app:icon="@android:drawable/ic_media_play" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".hub.GameSelectionActivity">
|
||||
|
||||
<!-- App Bar -->
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/primary"
|
||||
app:title="@string/app_name"
|
||||
app:titleTextColor="@color/text_on_primary"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<!-- Main Content -->
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Welcome Title -->
|
||||
<TextView
|
||||
style="@style/BoideloTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/welcome_to_hub" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/select_game_subtitle"
|
||||
android:textColor="@color/text_hint"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<!-- Games RecyclerView -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/gamesRecyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_game_card" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="2dp"
|
||||
app:strokeColor="@color/card_stroke"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Game Icon Container -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:cardBackgroundColor="@color/accent"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/gameIcon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/game_icon"
|
||||
android:src="@drawable/ic_player_three"
|
||||
app:tint="@color/text_primary" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Game Info -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gameName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
tools:text="Boidelo Classic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gameDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:textColor="@color/text_hint"
|
||||
android:textSize="14sp"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
tools:text="Le jeu original de questions et défis" />
|
||||
|
||||
<!-- Coming Soon Badge -->
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/statusText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/coming_soon"
|
||||
android:textColor="@color/text_hint"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone"
|
||||
app:chipBackgroundColor="@color/surface_variant"
|
||||
app:chipCornerRadius="4dp"
|
||||
app:chipMinHeight="24dp"
|
||||
style="@style/Widget.Material3.Chip.Assist.Elevated" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Play Indicator -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:cardBackgroundColor="@color/primary"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/play_game"
|
||||
android:src="@android:drawable/ic_media_play"
|
||||
app:tint="@color/text_on_primary" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp"
|
||||
app:strokeColor="@color/card_stroke"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<!-- Player Number Indicator -->
|
||||
<TextView
|
||||
android:id="@+id/playerNumber"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:background="@drawable/bg_button_secondary"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:text="4" />
|
||||
|
||||
<!-- Player Name Input -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:hint="@string/player_name_hint"
|
||||
app:boxBackgroundColor="@color/white"
|
||||
app:boxStrokeColor="@color/primary"
|
||||
app:boxStrokeWidth="1dp"
|
||||
app:endIconMode="clear_text"
|
||||
app:hintTextColor="@color/text_hint"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/playerName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPersonName"
|
||||
android:maxLines="1"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Remove Button with Material Design -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/removePlayerButton"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:contentDescription="@string/remove_player"
|
||||
app:icon="@android:drawable/ic_delete"
|
||||
app:iconTint="@color/error"
|
||||
app:backgroundTint="@color/surface"
|
||||
app:iconSize="20dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -1,50 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Mode SOMBRE - Amélioré pour lisibilité -->
|
||||
<!-- Mode SOMBRE - Nouvelle palette adaptée -->
|
||||
|
||||
<!-- Fond - gris moyen pour meilleur contraste -->
|
||||
<color name="background">#1E1E1E</color>
|
||||
<color name="surface">#2D2D2D</color>
|
||||
<color name="surface_variant">#3A3A3A</color>
|
||||
<color name="card_background">#2D2D2D</color>
|
||||
<!-- Arrière-plans - fond sombre avec la nouvelle palette -->
|
||||
<color name="background">#000807</color>
|
||||
<color name="surface">#0D0D1A</color>
|
||||
<color name="surface_variant">#1A1A2E</color>
|
||||
<color name="card_background">#141428</color>
|
||||
|
||||
<!-- Texte - blanc pour contraste maximal -->
|
||||
<color name="text_primary">#FFFFFF</color>
|
||||
<color name="text_secondary">#E0E0E0</color>
|
||||
<color name="text_hint">#9E9E9E</color>
|
||||
<!-- Texte - blanc et variantes de la nouvelle palette -->
|
||||
<color name="text_primary">#FBF9FF</color>
|
||||
<color name="text_secondary">#B3B7EE</color>
|
||||
<color name="text_hint">#9395D3</color>
|
||||
<color name="text_on_primary">#000807</color>
|
||||
|
||||
<!-- Couleur principale - violet clair sur fond sombre -->
|
||||
<color name="primary">#B388FF</color>
|
||||
<color name="primary_dark">#7C4DFF</color>
|
||||
<color name="primary_light">#D1C4E9</color>
|
||||
<!-- Couleur principale - adaptée du mode clair -->
|
||||
<color name="primary">#B3B7EE</color>
|
||||
<color name="primary_dark">#9395D3</color>
|
||||
<color name="accent">#B3B7EE</color>
|
||||
|
||||
<!-- Couleurs de jeu - plus claires pour être visibles -->
|
||||
<color name="game_normal">#2D2D2D</color>
|
||||
<color name="game_background">#1E1E1E</color>
|
||||
<color name="game_question_standard">#2D2D2D</color>
|
||||
<color name="game_question_1player">#372E45</color>
|
||||
<color name="game_question_2players">#413E5A</color>
|
||||
<color name="game_question_3players">#4B4E6F</color>
|
||||
<color name="game_question_manche">#2E3E5A</color>
|
||||
<color name="game_manche_end">#5A4E2E</color>
|
||||
<color name="game_finished">#5A3E2E</color>
|
||||
<!-- Couleurs de jeu - adaptées pour mode sombre -->
|
||||
<color name="game_normal">#0D0D1A</color>
|
||||
<color name="game_background">#000807</color>
|
||||
<color name="game_question_standard">#141428</color>
|
||||
<color name="game_question_1player">#1E1E35</color>
|
||||
<color name="game_question_2players">#2A2A45</color>
|
||||
<color name="game_question_3players">#373755</color>
|
||||
<color name="game_question_manche">#2A2A45</color>
|
||||
<color name="game_manche_end">#3A3520</color>
|
||||
<color name="game_finished">#3A2520</color>
|
||||
|
||||
<!-- États -->
|
||||
<color name="success">#81C784</color>
|
||||
<color name="error">#EF5350</color>
|
||||
<color name="warning">#FFB74D</color>
|
||||
|
||||
<!-- Pour compatibilité -->
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="black">#000000</color>
|
||||
<color name="accent">#B388FF</color>
|
||||
<color name="accent_dark">#E0E0E0</color>
|
||||
<color name="primary_container">#4A3A69</color>
|
||||
<color name="on_primary_container">#EDE7F6</color>
|
||||
<color name="card_stroke">#404040</color>
|
||||
<color name="divider">#404040</color>
|
||||
<color name="text_on_game_primary">#FFFFFF</color>
|
||||
<color name="text_on_colored_dark">#FFFFFF</color>
|
||||
<!-- Conteneurs -->
|
||||
<color name="primary_container">#2A2A45</color>
|
||||
<color name="on_primary_container">#FBF9FF</color>
|
||||
<color name="card_stroke">#2A2A45</color>
|
||||
<color name="divider">#2A2A45</color>
|
||||
|
||||
<!-- Overlays -->
|
||||
<color name="overlay_dark">#80000000</color>
|
||||
<color name="overlay_light">#80FFFFFF</color>
|
||||
|
||||
<!-- Pour compatibilité -->
|
||||
<color name="white">#FBF9FF</color>
|
||||
<color name="black">#000807</color>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -1,50 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- REFACTORING COMPLET - Palette Simple et Contrastée -->
|
||||
|
||||
<!-- Mode CLAIR -->
|
||||
<color name="background">#FFFFFF</color>
|
||||
<color name="surface">#FFFFFF</color>
|
||||
<color name="surface_variant">#F0F0F0</color>
|
||||
<!-- NOUVELLE PALETTE - Design cohérent et accessible -->
|
||||
|
||||
<!-- Couleurs principales -->
|
||||
<color name="primary">#9395D3</color>
|
||||
<color name="primary_dark">#000807</color>
|
||||
<color name="accent">#B3B7EE</color>
|
||||
|
||||
<!-- Arrière-plans -->
|
||||
<color name="background">#FBF9FF</color>
|
||||
<color name="surface">#FBF9FF</color>
|
||||
<color name="surface_variant">#FBF9FF</color>
|
||||
<color name="card_background">#FFFFFF</color>
|
||||
|
||||
<!-- Texte - contraste maximal -->
|
||||
<color name="text_primary">#000000</color>
|
||||
<color name="text_secondary">#333333</color>
|
||||
<color name="text_hint">#999999</color>
|
||||
|
||||
<!-- Couleur principale - violet visible -->
|
||||
<color name="primary">#7C4DFF</color>
|
||||
<color name="primary_dark">#6200EA</color>
|
||||
<color name="primary_light">#B388FF</color>
|
||||
|
||||
<!-- Couleurs de jeu - très subtiles, lisibles -->
|
||||
<color name="game_normal">#FFFFFF</color>
|
||||
<color name="game_background">#FFFFFF</color>
|
||||
|
||||
<!-- Texte - contraste optimal -->
|
||||
<color name="text_primary">#000807</color>
|
||||
<color name="text_secondary">#A2A3BB</color>
|
||||
<color name="text_hint">#9395D3</color>
|
||||
<color name="text_on_primary">#FBF9FF</color>
|
||||
|
||||
<!-- Couleurs de jeu -->
|
||||
<color name="game_normal">#FBF9FF</color>
|
||||
<color name="game_background">#FBF9FF</color>
|
||||
<color name="game_question_standard">#FFFFFF</color>
|
||||
<color name="game_question_1player">#F3E5F5</color>
|
||||
<color name="game_question_2players">#E1BEE7</color>
|
||||
<color name="game_question_3players">#CE93D8</color>
|
||||
<color name="game_question_manche">#E8EAF6</color>
|
||||
<color name="game_question_1player">#E8EAF6</color>
|
||||
<color name="game_question_2players">#D1C4E9</color>
|
||||
<color name="game_question_3players">#B3B7EE</color>
|
||||
<color name="game_question_manche">#C5CAE9</color>
|
||||
<color name="game_manche_end">#FFF59D</color>
|
||||
<color name="game_finished">#FFCCBC</color>
|
||||
|
||||
|
||||
<!-- États -->
|
||||
<color name="success">#4CAF50</color>
|
||||
<color name="error">#F44336</color>
|
||||
<color name="warning">#FF9800</color>
|
||||
|
||||
<!-- Pour compatibilité -->
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="black">#000000</color>
|
||||
<color name="accent">#7C4DFF</color>
|
||||
<color name="accent_dark">#333333</color>
|
||||
<color name="primary_container">#EDE7F6</color>
|
||||
<color name="on_primary_container">#1A0033</color>
|
||||
|
||||
<!-- Conteneurs -->
|
||||
<color name="primary_container">#E8EAF6</color>
|
||||
<color name="on_primary_container">#000807</color>
|
||||
<color name="card_stroke">#E0E0E0</color>
|
||||
<color name="divider">#E0E0E0</color>
|
||||
<color name="text_on_game_primary">#000000</color>
|
||||
<color name="text_on_colored_dark">#FFFFFF</color>
|
||||
<color name="divider">#B3B7EE</color>
|
||||
|
||||
<!-- Overlays -->
|
||||
<color name="overlay_dark">#80000000</color>
|
||||
<color name="overlay_light">#80FFFFFF</color>
|
||||
|
||||
<!-- Pour compatibilité -->
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="black">#000807</color>
|
||||
</resources>
|
||||
|
||||
@@ -20,5 +20,61 @@
|
||||
<string name="activer_les_questions_par_chatgpt">Activer les questions par IA</string>
|
||||
<string name="cl_api_openai">Clé API</string>
|
||||
<string name="openai">Intelligence Artificielle</string>
|
||||
<!-- Hub Strings -->
|
||||
<string name="welcome_to_hub">Bienvenue sur Boidelo Hub</string>
|
||||
<string name="select_game_subtitle">Choisissez un jeu pour commencer</string>
|
||||
<string name="game_icon">Icône du jeu</string>
|
||||
<string name="play_game">Jouer</string>
|
||||
<string name="coming_soon">Bientôt disponible</string>
|
||||
<string name="boidelo_classic_description">Le jeu original de questions et défis</string>
|
||||
<string name="game_89_description">Jeu de cartes avec timer et défis</string>
|
||||
<string name="undercover_description">Trouvez l\'undercover avant qu\'il ne soit trop tard!</string>
|
||||
<string name="rules_description">Découvrez les règles des jeux d\'ambiance populaires</string>
|
||||
<!-- Boidelo Classic Strings -->
|
||||
<string name="boidelo_classic_title">Boidelo Classic</string>
|
||||
<string name="boidelo_classic_setup_title">Configuration de la partie</string>
|
||||
<string name="player_name_hint">Nom du joueur</string>
|
||||
<string name="min_players_required">Joueurs: 0 / min. 3</string>
|
||||
<string name="player_setup_instructions">Pour commencer, entrez les noms des joueurs (minimum 3)</string>
|
||||
<string name="add_player">Ajouter un joueur</string>
|
||||
<string name="start_game">JOUER</string>
|
||||
<string name="settings">Paramètres</string>
|
||||
<string name="parameters">Paramètres</string>
|
||||
<string name="game_settings">Paramètres du jeu</string>
|
||||
<string name="number_of_questions">Nombre de questions</string>
|
||||
<string name="number_of_gorgees">Nombre de gorgées</string>
|
||||
<string name="artificial_intelligence">Intelligence Artificielle</string>
|
||||
<string name="enable_ai_questions">Activer les questions par IA</string>
|
||||
<string name="save">Enregistrer</string>
|
||||
<string name="skip">Passer</string>
|
||||
<string name="next">Suivant</string>
|
||||
<string name="remove_player">Supprimer ce joueur</string>
|
||||
|
||||
<!-- Game 89++ Strings -->
|
||||
<string name="game_89_title">89++</string>
|
||||
<string name="game_89_rules_summary">Le but est d\'arriver à un compte de 89 ou de le dépasser. Le joueur qui arrive/dépasse 89 perd!\n\nValet = -10 | Dame = Change sens | Roi = Choisissez la valeur\n\nÀ chaque dizaine (10, 20, 30…), distribuez des gorgées égales à la dizaine (sauf 70 = double)!</string>
|
||||
<string name="game_rules">Règles du jeu</string>
|
||||
<string name="players">Joueurs</string>
|
||||
<string name="challenge_timer">Timer des défis</string>
|
||||
<string name="game_89_play_card">Jouer une carte</string>
|
||||
<string name="game_89_mistake">Erreur de calcul</string>
|
||||
<string name="game_89_counter">Compteur</string>
|
||||
<string name="game_89_clockwise">↻ Sens horaire</string>
|
||||
<string name="game_89_counterclockwise">↺ Sens anti-horaire</string>
|
||||
<string name="game_89_current_player">Joueur actuel</string>
|
||||
<string name="game_89_your_cards">Vos cartes</string>
|
||||
<string name="game_89_next_challenge">Prochain défi dans:</string>
|
||||
<string name="game_89_challenge_title">DÉFI!</string>
|
||||
<string name="game_89_select_value">Sélectionnez la valeur (1-10):</string>
|
||||
<string name="game_89_announce_count">Annoncez le compte:</string>
|
||||
<string name="game_89_actual_count">Compte actuel:</string>
|
||||
<string name="game_89_ten_multiplier">DIZAINE! %d gorgées à distribuer!</string>
|
||||
<string name="game_89_seventy_bonus">70 = DOUBLE! 14 gorgées!</string>
|
||||
<string name="game_89_game_over">Le jeu est terminé!</string>
|
||||
<string name="game_89_winner">%s a gagné!</string>
|
||||
<string name="game_89_loser">%s a dépassé 89 et perd!</string>
|
||||
<string name="game_89_final_stats">Statistiques finales:</string>
|
||||
|
||||
<!-- Legacy strings (to be removed after refactor) -->
|
||||
<string name="test_de_connectivit_openai">Tester la connexion</string>
|
||||
</resources>
|
||||
@@ -19,27 +19,27 @@
|
||||
<!-- Bouton primaire -->
|
||||
<style name="BoideloButton.Primary">
|
||||
<item name="backgroundTint">@color/primary</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
<item name="rippleColor">@color/primary_light</item>
|
||||
<item name="android:textColor">@color/text_on_primary</item>
|
||||
<item name="rippleColor">@color/primary_dark</item>
|
||||
</style>
|
||||
|
||||
<!-- Bouton secondaire -->
|
||||
<style name="BoideloButton.Secondary">
|
||||
<item name="backgroundTint">@color/accent</item>
|
||||
<item name="android:textColor">@color/text_primary</item>
|
||||
<item name="rippleColor">@color/accent_dark</item>
|
||||
<item name="rippleColor">@color/primary</item>
|
||||
</style>
|
||||
|
||||
<!-- Bouton danger -->
|
||||
<style name="BoideloButton.Danger">
|
||||
<item name="backgroundTint">@color/error</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
<item name="android:textColor">@color/text_on_primary</item>
|
||||
</style>
|
||||
|
||||
<!-- Bouton succès -->
|
||||
<style name="BoideloButton.Success">
|
||||
<item name="backgroundTint">@color/success</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
<item name="android:textColor">@color/text_on_primary</item>
|
||||
</style>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
@@ -98,17 +98,17 @@
|
||||
<!-- ============================================================ -->
|
||||
|
||||
<style name="BoideloCard" parent="Widget.Material3.CardView.Elevated">
|
||||
<item name="cardBackgroundColor">@color/white</item>
|
||||
<item name="cardBackgroundColor">@color/card_background</item>
|
||||
<item name="cardCornerRadius">16dp</item>
|
||||
<item name="cardElevation">4dp</item>
|
||||
<item name="contentPadding">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="BoideloCard.Outlined">
|
||||
<item name="cardBackgroundColor">@color/white</item>
|
||||
<item name="cardBackgroundColor">@color/card_background</item>
|
||||
<item name="cardCornerRadius">16dp</item>
|
||||
<item name="cardElevation">0dp</item>
|
||||
<item name="strokeColor">@color/surface_variant</item>
|
||||
<item name="strokeColor">@color/card_stroke</item>
|
||||
<item name="strokeWidth">1dp</item>
|
||||
</style>
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
<style name="BoideloSeekBar" parent="Widget.AppCompat.SeekBar">
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="android:progressTint">@color/accent</item>
|
||||
<item name="android:progressBackgroundTint">@color/surface_variant</item>
|
||||
<item name="android:progressBackgroundTint">@color/divider</item>
|
||||
</style>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
<style name="BoideloProgressBar" parent="Widget.AppCompat.ProgressBar.Horizontal">
|
||||
<item name="android:progressTint">@color/accent</item>
|
||||
<item name="android:progressBackgroundTint">@color/surface_variant</item>
|
||||
<item name="android:progressBackgroundTint">@color/divider</item>
|
||||
</style>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
@@ -137,7 +137,7 @@
|
||||
|
||||
<style name="BoideloToolbar" parent="Widget.Material3.Toolbar">
|
||||
<item name="android:background">@color/primary</item>
|
||||
<item name="titleTextColor">@color/white</item>
|
||||
<item name="titleTextColor">@color/text_on_primary</item>
|
||||
<item name="android:elevation">4dp</item>
|
||||
</style>
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
|
||||
<style name="BoideloChip" parent="Widget.Material3.Chip.Suggestion">
|
||||
<item name="chipBackgroundColor">@color/accent</item>
|
||||
<item name="chipStrokeColor">@color/accent_dark</item>
|
||||
<item name="chipStrokeColor">@color/primary</item>
|
||||
<item name="android:textColor">@color/text_primary</item>
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user