From 95da08f1397d3d376f870bae9de072d82526f869 Mon Sep 17 00:00:00 2001 From: Mysaa Date: Fri, 27 Aug 2021 02:22:00 +0200 Subject: [PATCH] =?UTF-8?q?Premier=20commit,=20cr=C3=A9ation=20de=20l'appl?= =?UTF-8?q?ication=20avec=20connection=20au=20terminal=20ma=C3=AEtre.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 19 ++ app/.gitignore | 1 + app/build.gradle | 46 +++ app/src/main/AndroidManifest.xml | 35 +++ app/src/main/ic_launcher-playstore.png | Bin 0 -> 41296 bytes .../murderator/JoueurFragmentAdapter.java | 54 ++++ .../bernard/murderator/MurderApplication.java | 191 +++++++++++++ .../activities/ActionsJoueurFragment.java | 155 ++++++++++ .../activities/ChatJoueurFragment.java | 23 ++ .../ConnectionJoueurSelectionActivity.java | 81 ++++++ .../activities/ConnectionOpActivity.java | 17 ++ .../ConnectionSelectionActivity.java | 64 +++++ .../activities/InventaireJoueurFragment.java | 30 ++ .../murderator/activities/JoueurActivity.java | 42 +++ .../murderator/connection/PhoneServer.java | 265 ++++++++++++++++++ .../drawable-v24/ic_launcher_foreground.xml | 31 ++ .../res/drawable/ic_launcher_background.xml | 74 +++++ .../res/layout/action_list_item_layout.xml | 24 ++ .../activity_connection_joueur_selection.xml | 36 +++ .../res/layout/activity_connection_op.xml | 69 +++++ .../layout/activity_connection_selection.xml | 55 ++++ app/src/main/res/layout/activity_joueur.xml | 15 + app/src/main/res/layout/activity_main.xml | 18 ++ .../layout/activity_select_player_connect.xml | 14 + .../main/res/layout/ask_password_dialog.xml | 33 +++ .../res/layout/fragment_actions_joueur.xml | 13 + .../main/res/layout/fragment_chat_joueur.xml | 11 + .../res/layout/fragment_inventaire_joueur.xml | 13 + .../res/layout/player_selection_list_item.xml | 19 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3735 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5523 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2689 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3472 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5145 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7810 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 8263 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 12604 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 11238 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 17524 bytes app/src/main/res/values-land/dimens.xml | 3 + app/src/main/res/values-night/themes.xml | 16 ++ app/src/main/res/values-w1240dp/dimens.xml | 3 + app/src/main/res/values-w600dp/dimens.xml | 3 + app/src/main/res/values/colors.xml | 14 + app/src/main/res/values/dimens.xml | 3 + app/src/main/res/values/strings.xml | 36 +++ app/src/main/res/values/styles.xml | 10 + app/src/main/res/values/themes.xml | 25 ++ build.gradle | 17 ++ gradle.properties | 19 ++ settings.gradle | 10 + 53 files changed, 1617 insertions(+) create mode 100644 .gitignore create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/ic_launcher-playstore.png create mode 100644 app/src/main/java/com/bernard/murderator/JoueurFragmentAdapter.java create mode 100644 app/src/main/java/com/bernard/murderator/MurderApplication.java create mode 100644 app/src/main/java/com/bernard/murderator/activities/ActionsJoueurFragment.java create mode 100644 app/src/main/java/com/bernard/murderator/activities/ChatJoueurFragment.java create mode 100644 app/src/main/java/com/bernard/murderator/activities/ConnectionJoueurSelectionActivity.java create mode 100644 app/src/main/java/com/bernard/murderator/activities/ConnectionOpActivity.java create mode 100644 app/src/main/java/com/bernard/murderator/activities/ConnectionSelectionActivity.java create mode 100644 app/src/main/java/com/bernard/murderator/activities/InventaireJoueurFragment.java create mode 100644 app/src/main/java/com/bernard/murderator/activities/JoueurActivity.java create mode 100644 app/src/main/java/com/bernard/murderator/connection/PhoneServer.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/layout/action_list_item_layout.xml create mode 100644 app/src/main/res/layout/activity_connection_joueur_selection.xml create mode 100644 app/src/main/res/layout/activity_connection_op.xml create mode 100644 app/src/main/res/layout/activity_connection_selection.xml create mode 100644 app/src/main/res/layout/activity_joueur.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_select_player_connect.xml create mode 100644 app/src/main/res/layout/ask_password_dialog.xml create mode 100644 app/src/main/res/layout/fragment_actions_joueur.xml create mode 100644 app/src/main/res/layout/fragment_chat_joueur.xml create mode 100644 app/src/main/res/layout/fragment_inventaire_joueur.xml create mode 100644 app/src/main/res/layout/player_selection_list_item.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values-land/dimens.xml create mode 100644 app/src/main/res/values-night/themes.xml create mode 100644 app/src/main/res/values-w1240dp/dimens.xml create mode 100644 app/src/main/res/values-w600dp/dimens.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..352cf03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties +gradlew +gradlew.bat +gradle/ diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..60bb18a --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'com.android.application' +} + +android { + compileSdk 31 + + defaultConfig { + applicationId "com.bernard.murderator" + minSdk 21 + targetSdk 31 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } +} + +dependencies { + + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' + implementation 'androidx.navigation:navigation-fragment:2.3.5' + implementation 'androidx.navigation:navigation-ui:2.3.5' + implementation files('/home/mysaa/Documents/ProjetsGit/mysaa/Murderator.git/build/libs/MurderatorAPI.jar') + implementation files('/home/mysaa/Documents/ProjetsGit/bernard/BernardLibs.git/build/libs/BernardLibs.jar') + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0f7daec --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..55c35b139dc27c096f9d86f3989fb5bd5d40f8ab GIT binary patch literal 41296 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 literal 0 HcmV?d00001 diff --git a/app/src/main/java/com/bernard/murderator/JoueurFragmentAdapter.java b/app/src/main/java/com/bernard/murderator/JoueurFragmentAdapter.java new file mode 100644 index 0000000..50a5559 --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/JoueurFragmentAdapter.java @@ -0,0 +1,54 @@ +package com.bernard.murderator; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import com.bernard.murderator.activities.ActionsJoueurFragment; +import com.bernard.murderator.activities.ChatJoueurFragment; +import com.bernard.murderator.activities.InventaireJoueurFragment; +import com.bernard.murderator.activities.JoueurActivity; + +public class JoueurFragmentAdapter extends FragmentStateAdapter { + + public static final String PERSO_NAME_VAR = "com.bernard.murderator.activities.JoueurFragmentAdapter.persoName"; + + String playerName; + + InventaireJoueurFragment invFrag; + ActionsJoueurFragment actFrag; + ChatJoueurFragment chatFrag; + + public JoueurFragmentAdapter(@NonNull JoueurActivity fragmentActivity, String playerName) { + super(fragmentActivity); + this.playerName = playerName; + } + + @NonNull + @Override + public Fragment createFragment(int position) { + switch (position){ + case 0: + if(invFrag==null) + invFrag = new InventaireJoueurFragment(playerName); + return invFrag; + case 1: + if(actFrag==null) + actFrag = new ActionsJoueurFragment(playerName); + return actFrag; + case 2: + if(chatFrag==null) + chatFrag = new ChatJoueurFragment(); + return chatFrag; + } + throw new IllegalArgumentException("Cet adapteur ne fournis pas que 3 fragments, il n'y en a pas de "+position+"ème ..."); + } + + @Override + public int getItemCount() { + return 3; + } +} diff --git a/app/src/main/java/com/bernard/murderator/MurderApplication.java b/app/src/main/java/com/bernard/murderator/MurderApplication.java new file mode 100644 index 0000000..a558e06 --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/MurderApplication.java @@ -0,0 +1,191 @@ +package com.bernard.murderator; + +import android.app.Activity; +import android.app.Application; +import android.util.Log; + +import com.bernard.murder.model.Action; +import com.bernard.murder.model.Objet; +import com.bernard.murder.model.messages.Message; +import com.bernard.murder.model.messages.Thread; +import com.bernard.murderator.connection.PhoneServer; + +import java.net.SocketAddress; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class MurderApplication extends Application { + + private PhoneServer serveur; + + public Activity mainActivity; + + + final Map> playerActions = new HashMap<>(); // + final Map playerActionsLastUpdate = new HashMap<>(); + final Map> playerActionsUpdateListeners = new HashMap<>(); + + final Map> inventaireMap = new HashMap<>(); // + final Map inventaireMapLastUpdate = new HashMap<>(); // + final Map> inventaireUpdateListeners = new HashMap<>(); + + final Map> messages = new HashMap<>(); // + + Set joueurs = null; // + private final Object joueursTriggerer = new Object(); + + public boolean initServeur(SocketAddress address){ + if(serveur==null) { + PhoneServer serv = new PhoneServer(address, this); + boolean res = serv.checkMaster(); + if (res) + serveur = serv; + else + serv.close(); + return res; + }else + return serveur.checkMaster(); + } + + public PhoneServer getServeur(){ + if(serveur!=null) + return serveur; + throw new IllegalStateException("Le serveur de l'application n'a pas été initialisé."); + } + + public boolean initToken(boolean isOp, String name, String mdp){ + serveur.queryToken(name, mdp, isOp); + + while(!serveur.hasToken()){ + try { + synchronized (serveur) { + serveur.wait(dataWaitTimeout); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return true; + } + + private static final long dataWaitTimeout = 10_000; + + public Set getPersosNames() { + if(joueurs==null) { + serveur.queryPlayerList(); + while(joueurs==null){ + try { + synchronized (joueursTriggerer) { + joueursTriggerer.wait(dataWaitTimeout); + } + } catch (InterruptedException e) { + Log.e("MurderApplication","L'attente de la liste des joueurs a été interrompue.",e); + } + } + } + return joueurs; + } + + public Set getActions(String playerName) { + long askTime = System.currentTimeMillis(); + if(!(playerActionsLastUpdate.containsKey(playerName) && playerActionsLastUpdate.get(playerName)==null)) { + serveur.queryActions(playerName,false); + while(!playerActionsLastUpdate.containsKey(playerName) || + (playerActionsLastUpdate.get(playerName)!=null && + playerActionsLastUpdate.get(playerName) getInventaire(String invName) { + long askTime = System.currentTimeMillis(); + if(!(inventaireMapLastUpdate.containsKey(invName) && inventaireMapLastUpdate.get(invName)==null)) { + serveur.queryInventory(invName,false); + while(inventaireMapLastUpdate.containsKey(invName) && + !(inventaireMapLastUpdate.get(invName)!=null && + inventaireMapLastUpdate.get(invName) actions){ + playerActions.put(player,actions); + if(!(playerActionsLastUpdate.containsKey(player) && playerActionsLastUpdate.get(player)==null)) + playerActionsLastUpdate.put(player,System.currentTimeMillis()); + synchronized (playerActionsLastUpdate) { + playerActionsLastUpdate.notifyAll(); + } + if(playerActionsUpdateListeners.containsKey(player)) + for(Runnable r: playerActionsUpdateListeners.get(player)) + r.run(); + } + + public void updateInventaire(String invName, Set inventaire){ + inventaireMap.put(invName,inventaire); + if(!(inventaireMapLastUpdate.containsKey(invName) && inventaireMapLastUpdate.get(invName)==null)) + inventaireMapLastUpdate.put(invName,System.currentTimeMillis()); + synchronized (inventaireMapLastUpdate) { + inventaireMapLastUpdate.notifyAll(); + } + if(inventaireUpdateListeners.containsKey(invName)) + for(Runnable r: inventaireUpdateListeners.get(invName)) + r.run(); + } + + public void updateJoueurs(Set joueurs){ + if(this.joueurs==null) + this.joueurs = new HashSet<>(); + this.joueurs.clear(); + this.joueurs.addAll(joueurs); + synchronized (joueursTriggerer) { + joueursTriggerer.notifyAll(); + } + } + + + public void addPlayerActionsUpdateListener(String player,Runnable onUpdate){ + if(!playerActionsLastUpdate.containsKey(player) || playerActionsLastUpdate.get(player)!=null) + playerActionsLastUpdate.put(player,null); + if(!playerActionsUpdateListeners.containsKey(player)) + playerActionsUpdateListeners.put(player,new HashSet<>()); + playerActionsUpdateListeners.get(player).add(onUpdate); + } + public void addInventoryUpdateListener(String invName,Runnable onUpdate){ + if(!inventaireMapLastUpdate.containsKey(invName) || inventaireMapLastUpdate.get(invName)!=null) + inventaireMapLastUpdate.put(invName,null); + if(!inventaireUpdateListeners.containsKey(invName)) + inventaireUpdateListeners.put(invName,new HashSet<>()); + inventaireUpdateListeners.get(invName).add(onUpdate); + } + + public void receivedMessage(Message message, long threadId, int threadPos){ + + } + + public void openedThread(Thread tt){ + + } + + public void closedThread(long closedUid, long closeTimestamp) { + + } +} diff --git a/app/src/main/java/com/bernard/murderator/activities/ActionsJoueurFragment.java b/app/src/main/java/com/bernard/murderator/activities/ActionsJoueurFragment.java new file mode 100644 index 0000000..0430903 --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/activities/ActionsJoueurFragment.java @@ -0,0 +1,155 @@ +package com.bernard.murderator.activities; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.bernard.murder.model.Action; +import com.bernard.murderator.JoueurFragmentAdapter; +import com.bernard.murderator.MurderApplication; +import com.bernard.murderator.R; +import com.bernard.util.ParseUtils; + +import java.sql.Date; +import java.text.DateFormat; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +public class ActionsJoueurFragment extends Fragment { + + ListView actionListView; + + String persoName; + + // Si android re-crée le fragment + public ActionsJoueurFragment(){} + + public ActionsJoueurFragment(String persoName){ + this.persoName = persoName; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View fragView = inflater.inflate(R.layout.fragment_actions_joueur,container,false); + actionListView = fragView.findViewById(R.id.actions_list); + + if(getContext()!=null) { + MurderApplication theApp = ((MurderApplication) getContext().getApplicationContext()); + ActionAdapter ladapter = new ActionAdapter(getContext(), persoName); + actionListView.setAdapter(ladapter); + }else { + Log.e("ActionsJoueurFragment", "L'application n'a pas été créée !"); + } + + return fragView; + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + outState.putString(JoueurFragmentAdapter.PERSO_NAME_VAR, persoName); + super.onSaveInstanceState(outState); + } + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if(persoName ==null){ + // Alors on le récupères du bundle + persoName = savedInstanceState.getString(JoueurFragmentAdapter.PERSO_NAME_VAR); + } + } + + public class ActionAdapter extends ArrayAdapter{ + + Timer updateTimer; + + public ActionAdapter(@NonNull Context context, String persoName) { + super(context, 0); + Log.d("ActionAdapter","Création de l'adapteur"); + MurderApplication theApp = ((MurderApplication) context.getApplicationContext()); + Set actions = theApp.getActions(persoName); + updateElements(actions); + Log.d("ActionAdapter","Les éléments ont été mises à jour"); + + updateTimer = new Timer("Action-updater"); + updateTimer.schedule(new TimerTask() { + @Override + public void run() { + if(getActivity()!=null) + getActivity().runOnUiThread(ActionAdapter.this::updateTexts); + } + }, 100, 1000); + Log.d("ActionAdapter","le timer est lancé"); + } + + public void updateElements(Set acts){ + this.clear(); + List actz = new ArrayList<>(acts); + Collections.sort(actz,(a,b) -> a.getName().compareTo(b.getName())); + this.addAll(actz); + this.notifyDataSetChanged(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + Action act = getItem(position); + + if (convertView == null) { + convertView = LayoutInflater.from(getContext()).inflate(R.layout.action_list_item_layout, parent, false); + } + + TextView actionNameText = convertView.findViewById(R.id.action_name_text); + TextView actionTimeText = convertView.findViewById(R.id.action_time_text); + + toUpdate.put(position,actionTimeText); + + actionNameText.setText(act.getName()); + updateTexts(); + + return convertView; + } + Map toUpdate = new HashMap<>(); + public void updateTexts(){ + for (int i : toUpdate.keySet()) { + Action act = getItem(i); + String newText; + if(act.canBeLaunched()) + newText = getContext().getString(R.string.action_available_text); + else + newText = String.format( + getContext().getString(R.string.action_waiting_text), + ParseUtils.dumpTimeLength(act.timeToWaitLeft()), + DateFormat.getTimeInstance(DateFormat.MEDIUM).format(new Date(act.dateReset()))); + + toUpdate.get(i).setText(newText); + + } + } + } + +} diff --git a/app/src/main/java/com/bernard/murderator/activities/ChatJoueurFragment.java b/app/src/main/java/com/bernard/murderator/activities/ChatJoueurFragment.java new file mode 100644 index 0000000..0d6a813 --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/activities/ChatJoueurFragment.java @@ -0,0 +1,23 @@ +package com.bernard.murderator.activities; + + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.bernard.murderator.R; + +public class ChatJoueurFragment extends Fragment { + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_chat_joueur,container,false); + } + +} diff --git a/app/src/main/java/com/bernard/murderator/activities/ConnectionJoueurSelectionActivity.java b/app/src/main/java/com/bernard/murderator/activities/ConnectionJoueurSelectionActivity.java new file mode 100644 index 0000000..7f00587 --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/activities/ConnectionJoueurSelectionActivity.java @@ -0,0 +1,81 @@ +package com.bernard.murderator.activities; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import com.bernard.murder.model.Personnage; +import com.bernard.murderator.MurderApplication; +import com.google.android.material.snackbar.Snackbar; + +import androidx.appcompat.app.AppCompatActivity; + +import android.view.View; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.Toast; + + +import com.bernard.murderator.R; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class ConnectionJoueurSelectionActivity extends AppCompatActivity { + + Activity thisActivity; + MurderApplication thisApplication; + + ListView liste; + EditText mdp; + + EditText masterIP; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + thisActivity = this; + thisApplication = (MurderApplication) getApplicationContext(); + setContentView(R.layout.activity_connection_joueur_selection); + + liste = findViewById(R.id.player_select_list); + mdp = findViewById(R.id.player_mdp); + + + + List joueurs = new ArrayList(thisApplication.getPersosNames()); + Collections.sort(joueurs); + + liste.setAdapter( + new ArrayAdapter(this, android.R.layout.simple_list_item_1,joueurs) + ); + liste.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); + liste.setOnItemClickListener((parent,view,position,id)->{ + String playerName = (String) liste.getItemAtPosition(position); + if(playerName==null){ + Toast.makeText(thisActivity,R.string.no_player_selected,Toast.LENGTH_SHORT).show(); + return; + } + if(mdp.getText().toString().isEmpty()){ + Toast.makeText(thisActivity,R.string.no_password_given,Toast.LENGTH_SHORT).show(); + return; + } + if(thisApplication.initToken(false,playerName,mdp.getText().toString())){ + Intent intent = new Intent(thisActivity,JoueurActivity.class); + intent.putExtra(JoueurActivity.JOUEUR_NAME_INTENT,playerName); + + startActivity(intent); + }else{ + Toast.makeText(thisActivity,R.string.connection_failed,Toast.LENGTH_SHORT).show(); + } + }); + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/bernard/murderator/activities/ConnectionOpActivity.java b/app/src/main/java/com/bernard/murderator/activities/ConnectionOpActivity.java new file mode 100644 index 0000000..d46778a --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/activities/ConnectionOpActivity.java @@ -0,0 +1,17 @@ +package com.bernard.murderator.activities; + +import android.os.Bundle; + +import androidx.appcompat.app.AppCompatActivity; + +import com.bernard.murderator.R; + +public class ConnectionOpActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState) ; + setContentView(R.layout.activity_main); + } + +} diff --git a/app/src/main/java/com/bernard/murderator/activities/ConnectionSelectionActivity.java b/app/src/main/java/com/bernard/murderator/activities/ConnectionSelectionActivity.java new file mode 100644 index 0000000..1324f9c --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/activities/ConnectionSelectionActivity.java @@ -0,0 +1,64 @@ +package com.bernard.murderator.activities; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.bernard.murderator.MurderApplication; +import com.bernard.murderator.R; +import com.bernard.murderator.connection.PhoneServer; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +public class ConnectionSelectionActivity extends AppCompatActivity { + + Activity thisActivity; + MurderApplication thisApplication; + + Button joueurButton, operateurButton, qrCodeButton, micButton, enceinteButton; + EditText masterIP; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + thisActivity = this; + thisApplication = (MurderApplication) getApplicationContext(); + setContentView(R.layout.activity_connection_selection); + + joueurButton = findViewById(R.id.connect_as_player); + operateurButton = findViewById(R.id.connect_as_op); + micButton = findViewById(R.id.connect_as_mic); + enceinteButton = findViewById(R.id.connect_as_speaker); + qrCodeButton = findViewById(R.id.connect_with_qrcode); + + masterIP = findViewById(R.id.editTextMasterIP); + + + + joueurButton.setOnClickListener((v) -> { + //TODO fetch player list from remote + if(initServer(masterIP.getText().toString())) { + Intent intent = new Intent(thisActivity, ConnectionJoueurSelectionActivity.class); + startActivity(intent); + } + }); + } + + public boolean initServer(String address){ + SocketAddress addr = new InetSocketAddress(address, PhoneServer.communicationPort); + boolean result = thisApplication.initServeur(addr); + + if(!result) + Toast.makeText(this,R.string.master_not_found,Toast.LENGTH_SHORT).show(); + return result; + } + + //TODO Peut recevoir en intent une URL/qrcode correspondant à une URL contenant le type de connection, le mot de passe et le pseudo/nomDuJoueur + +} diff --git a/app/src/main/java/com/bernard/murderator/activities/InventaireJoueurFragment.java b/app/src/main/java/com/bernard/murderator/activities/InventaireJoueurFragment.java new file mode 100644 index 0000000..1b26eec --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/activities/InventaireJoueurFragment.java @@ -0,0 +1,30 @@ +package com.bernard.murderator.activities; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.bernard.murderator.R; + +public class InventaireJoueurFragment extends Fragment { + + String invName; + + public InventaireJoueurFragment(){} + + public InventaireJoueurFragment(String invName){ + this.invName = invName; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_inventaire_joueur,container,false); + } + +} diff --git a/app/src/main/java/com/bernard/murderator/activities/JoueurActivity.java b/app/src/main/java/com/bernard/murderator/activities/JoueurActivity.java new file mode 100644 index 0000000..7eff00c --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/activities/JoueurActivity.java @@ -0,0 +1,42 @@ +package com.bernard.murderator.activities; + +import android.content.Intent; +import android.os.Bundle; + +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.widget.ViewPager2; + +import com.bernard.murderator.JoueurFragmentAdapter; +import com.bernard.murderator.MurderApplication; +import com.bernard.murderator.R; + +public class JoueurActivity extends FragmentActivity { + + public static final String JOUEUR_NAME_INTENT = "com.bernard.murderator.JoueurActivity.joueurName"; + + String playerName; + + + ViewPager2 pager; + + JoueurFragmentAdapter adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_joueur); + + Intent intent = getIntent(); + playerName = intent.getStringExtra(JOUEUR_NAME_INTENT); + + ((MurderApplication)getApplication()).mainActivity = this; + pager = findViewById(R.id.view_pager); + + adapter = new JoueurFragmentAdapter(this, playerName); + pager.setAdapter(adapter); + } + + public String getPlayerName() { + return playerName; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bernard/murderator/connection/PhoneServer.java b/app/src/main/java/com/bernard/murderator/connection/PhoneServer.java new file mode 100644 index 0000000..d71f8b0 --- /dev/null +++ b/app/src/main/java/com/bernard/murderator/connection/PhoneServer.java @@ -0,0 +1,265 @@ +package com.bernard.murderator.connection; + +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import com.bernard.murder.audio.Codes; +import com.bernard.murder.audio.Serveur; +import com.bernard.murder.model.Action; +import com.bernard.murder.model.Objet; +import com.bernard.murder.model.messages.Message; +import com.bernard.murder.model.messages.Thread; +import com.bernard.murderator.MurderApplication; +import com.bernard.murderator.R; +import com.bernard.util.BytesUtils; + +import java.io.IOException; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class PhoneServer { + + public static int communicationPort = 35295; + + Serveur serv; + String token; + + SocketAddress masterAddress; + MurderApplication app; + + Set answeredUUIDs = new HashSet<>(); + + + public PhoneServer(SocketAddress address, MurderApplication app){ + this.masterAddress = address; + this.app = app; + + try { + initServer(); + } catch (SocketException | UnknownHostException e) { + Log.e("PhoneServer","Impossible d'initialiser le serveur",e); + } + } + + public void initServer() throws SocketException, UnknownHostException { + if(serv==null) { + serv = new Serveur(this::receiveCommand, PhoneServer.communicationPort); + serv.setNetworkOnSeparatedThread(true); + } + } + + public void receiveCommand(ByteBuffer data, SocketAddress senderAddress) { + byte commande = data.get(); + Log.d("PhoneServer","Commande reçue : " + commande + " de " + senderAddress + " de taille " + (data.limit() + 1)); + + switch (commande){ + case Codes.ACCES_PARTIE: + receivePartieCommand(data, senderAddress); + break; + case Codes.PONG: + synchronized (masterCheckMonitored) { + masterResponce = true; + masterCheckMonitored.notifyAll(); + } + break; + default: + Log.w("PhoneServer","Je ne sais pas recevoir les commandes "+commande); + } + } + + public void receivePartieCommand(ByteBuffer data, SocketAddress senderAddress) { + byte commandePartie = data.get(); + Log.d("PhoneServer","Partie-commande recue: "+commandePartie); + switch(commandePartie){ + case Codes.Partie.ACTIONS_STATUS: + Log.d("PhoneServer", Arrays.toString(data.array())); + String persoName = BytesUtils.readString(data); + int actCount = data.getInt(); + Set actions = new HashSet<>(); + Log.d("PhoneServer","J'ai reçu "+actCount+" actions"); + for (int i = 0; i < actCount; i++) { + Log.d("PhoneServer","Le numéro "+i+" ..."); + String actName = BytesUtils.readString(data); + long basetime = data.getLong(); + long triggertime = data.getLong(); + Action act = new Action(actName,basetime,triggertime); + actions.add(act); + } + app.updatePlayerActions(persoName,actions); + break; + case Codes.Partie.INVENTORY_CONTENT: + String invName = BytesUtils.readString(data); + int invCount = data.getInt(); + Set objets = new HashSet<>(); + for (int i = 0; i < invCount; i++) { + String objName = BytesUtils.readString(data); + Objet obj = new Objet(objName); + objets.add(obj); + } + + app.updateInventaire(invName,objets); + break; + case Codes.Partie.GIVE_PLAYER_LIST: + int nbrJoueurs = data.getInt(); + Set joueurs = new HashSet<>(); + for (int i = 0; i < nbrJoueurs; i++) { + String joueur = BytesUtils.readString(data); + joueurs.add(joueur); + } + + app.updateJoueurs(joueurs); + break; + + case Codes.Partie.GIVING_TOKEN: + String newToken = BytesUtils.readString(data); + Log.d("PhoneServer","On a reçu un token ! "+newToken); + if(!newToken.isEmpty()) + this.token = newToken; + else + authError(token); + synchronized (this) { + this.notifyAll(); + } + break; + + case Codes.Partie.AUTH_ERROR: + String erroredToken = BytesUtils.readString(data); + authError(erroredToken); + break; + + case Codes.Partie.CREATED_NEW_THREAD: + UUID requestId = new UUID(data.getLong(),data.getLong()); + String persoNameT = BytesUtils.readString(data); + long threadUid = data.getLong(); + long startTimestamp = data.getLong(); + + Thread tt = new Thread(persoNameT,startTimestamp,threadUid); + + app.openedThread(tt); + + answeredUUIDs.add(requestId); + break; + case Codes.Partie.CLOSED_THREAD: + long closedUid = data.getLong(); + long closeTimestamp = data.getLong(); + + app.closedThread(closedUid,closeTimestamp); + break; + case Codes.Partie.NEW_MESSAGE: + long sentTimestamp = data.getLong(); + long threadId = data.getLong(); + int threadPosition = data.getInt(); + String emmeteur = BytesUtils.readString(data); + String msgText = BytesUtils.readString(data); + + Message msg = new Message(emmeteur,msgText,sentTimestamp); + + app.receivedMessage(msg,threadId,threadPosition); + + break; + default: + Log.w("PhoneServer","Je ne sais pas recevoir les sous-commandes "+commandePartie); + } + } + + public void sendMessage(String text, String emmeteur, long threadUid){ + + } + + public void queryPlayerList(){ + ByteBuffer bb = ByteBuffer.allocate(Codes.packetMaxSize); + bb.put(Codes.ACCES_PARTIE); + bb.put(Codes.Partie.ASK_PLAYER_LIST); + + try { + serv.sendData(bb,masterAddress); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void queryInventory(String invName, boolean watch){ + ByteBuffer bb = ByteBuffer.allocate(Codes.packetMaxSize); + bb.put(Codes.ACCES_PARTIE); + bb.put(watch?Codes.Partie.ASK_INVENTORY_WATCH:Codes.Partie.ASK_INVENTORY); + BytesUtils.writeString(bb,token); + BytesUtils.writeString(bb,invName); + + try { + serv.sendData(bb,masterAddress); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void queryActions(String persoName, boolean watch){ + ByteBuffer bb = ByteBuffer.allocate(Codes.packetMaxSize); + bb.put(Codes.ACCES_PARTIE); + bb.put(watch?Codes.Partie.ASK_ACTIONS_WATCH:Codes.Partie.ASK_ACTIONS); + BytesUtils.writeString(bb,token); + BytesUtils.writeString(bb,persoName); + + try { + serv.sendData(bb,masterAddress); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void queryToken(String playerName, String mdp, boolean isOp){ + ByteBuffer bb = ByteBuffer.allocate(Codes.packetMaxSize); + bb.put(Codes.ACCES_PARTIE); + bb.put(isOp?Codes.Partie.ASK_OP_TOKEN:Codes.Partie.ASK_JOUEUR_TOKEN); + BytesUtils.writeString(bb,playerName); + BytesUtils.writeString(bb,mdp); + + try { + serv.sendData(bb,masterAddress); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void authError(String token){ + new java.lang.Thread(() -> { + Looper.prepare(); + if(app.mainActivity!=null && (app.mainActivity.isFinishing() || app.mainActivity.isDestroyed())) + app.mainActivity.finish(); + Toast.makeText(app, app.getResources().getString(R.string.auth_error,token),Toast.LENGTH_SHORT).show(); + }).start(); + } + + + + public static final long masterCheckTimeout = 10_000; + private final Lock masterCheckLock = new ReentrantLock(); + public final Object masterCheckMonitored = new Object(); + private boolean masterResponce = false; + public synchronized boolean checkMaster(){ + synchronized (masterCheckMonitored) { + masterResponce = false; + try { + serv.sendData(new byte[]{Codes.PING}, masterAddress); + masterCheckMonitored.wait(masterCheckTimeout); + } catch (InterruptedException | IOException ignored) {} + } + return masterResponce; + } + + public boolean hasToken(){ + return token==null; + } + + public void close() { + serv.close(); + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..da1dcd9 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..ca3826a --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/action_list_item_layout.xml b/app/src/main/res/layout/action_list_item_layout.xml new file mode 100644 index 0000000..621f38b --- /dev/null +++ b/app/src/main/res/layout/action_list_item_layout.xml @@ -0,0 +1,24 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_connection_joueur_selection.xml b/app/src/main/res/layout/activity_connection_joueur_selection.xml new file mode 100644 index 0000000..7d74d00 --- /dev/null +++ b/app/src/main/res/layout/activity_connection_joueur_selection.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_connection_op.xml b/app/src/main/res/layout/activity_connection_op.xml new file mode 100644 index 0000000..2b03212 --- /dev/null +++ b/app/src/main/res/layout/activity_connection_op.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + +