diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacerSelectionFragment.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacerSelectionFragment.java new file mode 100644 index 0000000..cc541cb --- /dev/null +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacerSelectionFragment.java @@ -0,0 +1,33 @@ +package com.example.cis.mazeminotaurs; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; + +/** + * Created by jsmith on 10/18/17. + */ + +public class CharacerSelectionFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater li, ViewGroup vg, Bundle b) { + super.onCreateView(li, vg, b); + View view = li.inflate(R.layout.fragment_character_selection, vg, false); + + ListView charListView = (ListView) view.findViewById(R.id.character_list_view); + charListView.setAdapter(new CharacterAdapter(getContext())); + + charListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + Portfolio.get().setActiveCharacterIndex(i); + } + }); + + return view; + } +} diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterAdapter.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterAdapter.java new file mode 100644 index 0000000..864471a --- /dev/null +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterAdapter.java @@ -0,0 +1,62 @@ +package com.example.cis.mazeminotaurs; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.example.cis.mazeminotaurs.character.PlayerCharacter; + +import java.util.ArrayList; + +/** + * Created by jsmith on 10/18/17. + */ + +public class CharacterAdapter extends BaseAdapter { + private Portfolio mPortfolio = Portfolio.get(); + private Context mContext; + + public CharacterAdapter(Context context) { + mContext = context; + } + + public void removeCharacter(int i) { + mPortfolio.deletePlayerCharacter(mPortfolio.getPlayerCharacter(i)); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mPortfolio.getPortfolio().size(); + } + + @Override + public PlayerCharacter getItem(int i) { + return mPortfolio.getPlayerCharacter(i); + } + + @Override + public long getItemId(int i) { + return getItem(i).getCharClass().getResId(); + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + if (view == null) { + view = LayoutInflater.from(mContext) + .inflate(R.layout.spinner_item_character, viewGroup, false); + } + + TextView nameView = (TextView) view.findViewById(R.id.character_name_view); + TextView classView = (TextView) view.findViewById(R.id.character_class_view); + TextView levelView = (TextView) view.findViewById(R.id.character_level_view); + + nameView.setText(getItem(i).getName()); + classView.setText(getItem(i).getCharClass().getResId()); + levelView.setText(String.valueOf(getItem(i).getCharClass().getLevel())); + return view; + } +} diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterDeletionFragment.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterDeletionFragment.java new file mode 100644 index 0000000..d7057bf --- /dev/null +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterDeletionFragment.java @@ -0,0 +1,38 @@ +package com.example.cis.mazeminotaurs; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.Toast; + +/** + * Created by jsmith on 10/19/17. + */ + +public class CharacterDeletionFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater li, ViewGroup vg, Bundle b) { + super.onCreateView(li, vg, b); + View view = li.inflate(R.layout.fragment_character_selection, vg, false); + + final ListView charListView = (ListView) view.findViewById(R.id.character_list_view); + charListView.setAdapter(new CharacterAdapter(getContext())); + + charListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (charListView.getAdapter().getCount() > 1) { + ((CharacterAdapter) charListView.getAdapter()).removeCharacter(i); + } else { + Toast.makeText(getContext(), R.string.error_delete_character, Toast.LENGTH_SHORT).show(); + } + } + }); + + return view; + } +} diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterSheetFragment.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterSheetFragment.java index bfb63fe..176e7c3 100644 --- a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterSheetFragment.java +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/CharacterSheetFragment.java @@ -3,6 +3,7 @@ import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -77,6 +78,7 @@ public View onCreateView(LayoutInflater li, ViewGroup vg, Bundle b){ View rootView = li.inflate(R.layout.fragment_character_sheet, vg, false); mCurrentCharacterIndex = mPortfolio.getActiveCharacterIndex(); + Log.d(TAG, String.valueOf(mPortfolio.getActiveCharacterIndex())); mSheetPlayerCharacter = mPortfolio.getPlayerCharacter(mCurrentCharacterIndex); mCharacterLevelView = (TextView) rootView.findViewById(R.id.character_level_view); @@ -208,6 +210,7 @@ public void onClick(View v){ }); mEquippedWeaponSpinner = (Spinner) rootView.findViewById(R.id.equipped_weapon_spinner); + System.out.println(mSheetPlayerCharacter.getInventory()); DetailedWeaponAdapter weaponAdapter = new DetailedWeaponAdapter(getContext(), mSheetPlayerCharacter.getWeapons()); mEquippedWeaponSpinner.setAdapter(weaponAdapter); //Get equipped weapon from character Class diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/MainMazes.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/MainMazes.java index 23999a9..aa5eebb 100644 --- a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/MainMazes.java +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/MainMazes.java @@ -1,5 +1,6 @@ package com.example.cis.mazeminotaurs; +import android.content.Context; import android.os.Bundle; import android.support.design.widget.NavigationView; import android.support.v4.app.Fragment; @@ -12,13 +13,25 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; +import android.widget.Toast; import com.example.cis.mazeminotaurs.NewCharacter.CharacterCreationFragment; import com.example.cis.mazeminotaurs.character.PlayerCharacter; +import com.example.cis.mazeminotaurs.character.SaveAndLoadPerformer; +import com.example.cis.mazeminotaurs.util.Util; import com.example.cis.mazeminotaurs.web_resources.CompanionFragment; import com.example.cis.mazeminotaurs.web_resources.PlayerManualFragment; import com.example.cis.mazeminotaurs.web_resources.WebsiteFragment; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + public class MainMazes extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { @@ -28,8 +41,27 @@ public class MainMazes extends AppCompatActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + try { + String basePath = getApplicationContext().getFilesDir().getPath() + "/"; + FileInputStream fis = new FileInputStream(basePath + Portfolio.FILENAME); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(fis))); + + StringBuilder builder = new StringBuilder(); + String line = bufferedReader.readLine(); + while (line != null && !line.equals("")) { + builder.append(line); + line = bufferedReader.readLine(); + } + SaveAndLoadPerformer.loadPortfolio(builder.toString()); + } catch (IOException e) { + e.printStackTrace(); + } mPortfolio = Portfolio.get(); + if (mPortfolio.getPortfolio() == null) { + mPortfolio.resetPortfolio(); + mPortfolio.addPlayerCharacter(Util.createDummyCharacter()); + } mEquipment = EquipmentDB.getInstance(); try{ @@ -85,6 +117,17 @@ public boolean onOptionsItemSelected(MenuItem item) { //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; + } else if (id == R.id.action_save_portfolio) { + try { + FileOutputStream fos = getApplicationContext().openFileOutput(Portfolio.FILENAME, Context.MODE_PRIVATE); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fos); + outputStreamWriter.write(SaveAndLoadPerformer.savePortfolio()); + outputStreamWriter.close(); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return true; } return super.onOptionsItemSelected(item); @@ -105,8 +148,10 @@ public boolean onNavigationItemSelected(MenuItem item) { contentFragment = new CharacterCreationFragment(); } else if (id == R.id.play_character) { contentFragment = new CharacterSheetFragment(); + } else if (id == R.id.select_character) { + contentFragment = new CharacerSelectionFragment(); } else if (id == R.id.delete_character) { - + contentFragment = new CharacterDeletionFragment(); } else if (id == R.id.player_manual) { contentFragment = new PlayerManualFragment(); } else if (id == R.id.player_comapanion) { diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/Portfolio.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/Portfolio.java index a92cecb..13ff308 100644 --- a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/Portfolio.java +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/Portfolio.java @@ -10,6 +10,8 @@ */ public class Portfolio { + public static final String FILENAME = "SavedPortfolio"; + private static final String TAG = Portfolio.class.getName(); private ArrayList portfolio; private static Portfolio sPortfolio; diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/CharacterSerializer.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/CharacterSerializer.java new file mode 100644 index 0000000..69b577c --- /dev/null +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/CharacterSerializer.java @@ -0,0 +1,114 @@ +package com.example.cis.mazeminotaurs.character; + +/** + * Created by jsmith on 10/17/17. + */ + +import com.example.cis.mazeminotaurs.Armor; +import com.example.cis.mazeminotaurs.Equipment; +import com.example.cis.mazeminotaurs.Mythics; +import com.example.cis.mazeminotaurs.Weapon; +import com.example.cis.mazeminotaurs.character.Gender; +import com.example.cis.mazeminotaurs.character.Money; +import com.example.cis.mazeminotaurs.character.PlayerCharacter; +import com.example.cis.mazeminotaurs.character.classes.BaseClass; +import com.example.cis.mazeminotaurs.character.stats.Score; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.reflect.TypeToken; +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Custom serializer for transforming the PlayerCharacter class into json. + */ +public class CharacterSerializer implements JsonSerializer, JsonDeserializer { + + private static Gson sGson = null; + + private static Gson getGson() { + if (sGson == null) { + GsonBuilder builder = new GsonBuilder(); + RuntimeTypeAdapterFactory adapter = RuntimeTypeAdapterFactory + .of(Equipment.class) + .registerSubtype(Equipment.class) + .registerSubtype(Weapon.class) + .registerSubtype(Armor.class) + .registerSubtype(Mythics.class); + builder.registerTypeAdapterFactory(adapter); + builder.setPrettyPrinting(); + sGson = builder.create(); + } + return sGson; + } + + @Override + public JsonElement serialize(PlayerCharacter src, Type typeOfSrc, JsonSerializationContext context) { + BaseClass characterClass = src.getCharClass(); + characterClass.setCharacter(null); + + Type equipListType = new TypeToken>() { + }.getType(); + Type moneyMapType = new TypeToken>() { + }.getType(); + + JsonObject rootObject = new JsonObject(); + rootObject.add("mScores", context.serialize(src.getScores())); + rootObject.add("mCharClass", context.serialize(src.getCharClass(), BaseClass.class)); + rootObject.add("mGender", context.serialize(src.getGender())); + rootObject.add("mMoney", context.serialize(src.getMoney(), moneyMapType)); + rootObject.add("mAge", context.serialize(src.getAge())); + rootObject.add("mName", context.serialize(src.getName())); + System.out.println(getGson().toJsonTree(src.getInventory(), equipListType)); + rootObject.add("mInventory", getGson().toJsonTree(src.getInventory(), equipListType)); + rootObject.add("mCurrentWeapon", context.serialize(src.getCurrentWeapon())); + rootObject.add("mHelmet", context.serialize(src.getHelmet())); + rootObject.add("mBreastplate", context.serialize(src.getBreastplate())); + rootObject.add("mShield", context.serialize(src.getShield())); + + JsonElement classJson = context.serialize(characterClass); + rootObject.add("mCharClass", classJson); + + characterClass.setCharacter(src); + return rootObject; + } + + @Override + public PlayerCharacter deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + final PlayerCharacter newCharacter = new PlayerCharacter(); + JsonObject loadedData = json.getAsJsonObject(); + for (Score score : Score.values()) { + int loadedScore = loadedData.getAsJsonObject("mScores").getAsJsonObject(score.toString()).get("mScore").getAsInt(); + newCharacter.getScore(score).setScore(loadedScore); + } + + Type equipListType = new TypeToken>() { + }.getType(); + Type moneyMapType = new TypeToken>() { + }.getType(); + + newCharacter.setAge((int) context.deserialize(loadedData.get("mAge"), Integer.class)); + newCharacter.setBreastplate((Armor) context.deserialize(loadedData.get("mBreastplate"), Armor.class)); + newCharacter.setCharClass((BaseClass) context.deserialize(loadedData.get("mCharClass"), BaseClass.class)); + newCharacter.setCurrentWeapon((Weapon) context.deserialize(loadedData.get("mCurrentWeapon"), Weapon.class)); + newCharacter.setGender((Gender) context.deserialize(loadedData.get("mGender"), Gender.class)); + newCharacter.setHelmet((Armor) context.deserialize(loadedData.get("mHelmet"), Armor.class)); + newCharacter.setMoney((HashMap) context.deserialize(loadedData.get("mMoney"), moneyMapType)); + newCharacter.setName(loadedData.get("mName").getAsString()); + newCharacter.setInventory((ArrayList) getGson().fromJson(loadedData.get("mInventory"), equipListType)); + newCharacter.setShield((Armor) context.deserialize(loadedData.get("mShield"), Armor.class)); + + return newCharacter; + } +} diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadDialog.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadDialog.java index f68982f..5b1dc51 100644 --- a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadDialog.java +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadDialog.java @@ -24,6 +24,7 @@ import java.io.OutputStreamWriter; /** + * @deprecated * Created by jusmith on 4/26/17. */ diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadPerformer.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadPerformer.java index b2d5754..fb13dd9 100644 --- a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadPerformer.java +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/character/SaveAndLoadPerformer.java @@ -1,17 +1,30 @@ package com.example.cis.mazeminotaurs.character; import com.example.cis.mazeminotaurs.Armor; +import com.example.cis.mazeminotaurs.Equipment; import com.example.cis.mazeminotaurs.Portfolio; import com.example.cis.mazeminotaurs.Weapon; +import com.example.cis.mazeminotaurs.character.classes.Amazon; import com.example.cis.mazeminotaurs.character.classes.Barbarian; import com.example.cis.mazeminotaurs.character.classes.BaseClass; +import com.example.cis.mazeminotaurs.character.classes.Centaur; +import com.example.cis.mazeminotaurs.character.classes.Elementalist; +import com.example.cis.mazeminotaurs.character.classes.Hunter; +import com.example.cis.mazeminotaurs.character.classes.Lyrist; +import com.example.cis.mazeminotaurs.character.classes.Magician; +import com.example.cis.mazeminotaurs.character.classes.Noble; +import com.example.cis.mazeminotaurs.character.classes.Nymph; +import com.example.cis.mazeminotaurs.character.classes.Priest; +import com.example.cis.mazeminotaurs.character.classes.Sorcerer; +import com.example.cis.mazeminotaurs.character.classes.Spearman; +import com.example.cis.mazeminotaurs.character.classes.Thief; import com.example.cis.mazeminotaurs.character.stats.Score; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; +import com.google.gson.reflect.TypeToken; +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; import java.lang.reflect.Type; import java.util.ArrayList; @@ -23,6 +36,39 @@ */ public class SaveAndLoadPerformer { + + private static Gson sGson = null; + + /** + * Generates a gson that has all of the common features loaded in. + * @return a gson object + */ + private static Gson getGson() { + if (sGson == null) { + GsonBuilder builder = new GsonBuilder(); + RuntimeTypeAdapterFactory adapter = RuntimeTypeAdapterFactory + .of(BaseClass.class) + .registerSubtype(Amazon.class) + .registerSubtype(Barbarian.class) + .registerSubtype(Centaur.class) + .registerSubtype(Elementalist.class) + .registerSubtype(Hunter.class) + .registerSubtype(Lyrist.class) + .registerSubtype(Magician.class) + .registerSubtype(Noble.class) + .registerSubtype(Nymph.class) + .registerSubtype(Priest.class) + .registerSubtype(Sorcerer.class) + .registerSubtype(Spearman.class) + .registerSubtype(Thief.class); + builder.registerTypeAdapter(PlayerCharacter.class, new CharacterSerializer()); + builder.registerTypeAdapterFactory(adapter); + builder.setPrettyPrinting(); + sGson = builder.create(); + } + return sGson; + } + /** * Takes the player character parameter and transforms it into a json string. * @param playerCharacter the player character that needs to be serialized. @@ -40,13 +86,12 @@ public static String save(PlayerCharacter playerCharacter){ * @return json string of playerCharacter */ public static String save(int characterIndex) { - GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(PlayerCharacter.class, new CharacterSerializer()); - return gson.create().toJson(Portfolio.get().getPlayerCharacter(characterIndex)); + return getGson().toJson(Portfolio.get().getPlayerCharacter(characterIndex)); } /** * Returns a playerCharacter based on the json string given. + * @deprecated * @param jsonString the playerCharacter in json * @return the generated playerCharacter */ @@ -54,11 +99,16 @@ public static PlayerCharacter load(String jsonString){ PlayerCharacter returnCharacter = new PlayerCharacter(); JsonObject loadedData = (JsonObject) new Gson().fromJson(jsonString, JsonElement.class); - for (Score score: Score.values()) { + for (Score score : Score.values()) { int loadedScore = loadedData.getAsJsonObject("mScores").getAsJsonObject(score.toString()).get("mScore").getAsInt(); returnCharacter.getScore(score).setScore(loadedScore); } - Gson gson = new Gson(); + Gson gson = getGson(); + + Type equipListType = new TypeToken>() { + }.getType(); + Type moneyMapType = new TypeToken>() { + }.getType(); returnCharacter.setAge(gson.fromJson(loadedData.get("mAge"), Integer.class)); returnCharacter.setBreastplate(gson.fromJson(loadedData.get("mBreastplate"), Armor.class)); @@ -66,41 +116,24 @@ public static PlayerCharacter load(String jsonString){ returnCharacter.setCurrentWeapon(gson.fromJson(loadedData.get("mCurrentWeapon"), Weapon.class)); returnCharacter.setGender(gson.fromJson(loadedData.get("mGender"), Gender.class)); returnCharacter.setHelmet(gson.fromJson(loadedData.get("mHelmet"), Armor.class)); - returnCharacter.setMoney(gson.fromJson(loadedData.get("mMoney"), HashMap.class)); + returnCharacter.setMoney((HashMap) gson.fromJson(loadedData.get("mMoney"), moneyMapType)); returnCharacter.setName(loadedData.get("mName").getAsString()); - returnCharacter.setInventory(gson.fromJson(loadedData.get("mInventory"), ArrayList.class)); + returnCharacter.setInventory((ArrayList) gson.fromJson(loadedData.get("mInventory"), equipListType)); returnCharacter.setShield(gson.fromJson(loadedData.get("mShield"), Armor.class)); return returnCharacter; } -} -/** - * Custom serializer for transforming the PlayerCharacter class into json. - */ -class CharacterSerializer implements JsonSerializer { - @Override - public JsonElement serialize(PlayerCharacter src, Type typeOfSrc, JsonSerializationContext context) { - BaseClass characterClass = src.getCharClass(); - characterClass.setCharacter(null); - - JsonObject rootObject = new JsonObject(); - rootObject.add("mScores", context.serialize(src.getScores())); - rootObject.add("mCharClass", context.serialize(src.getCharClass())); - rootObject.add("mGender", context.serialize(src.getGender())); - rootObject.add("mMoney", context.serialize(src.getMoney())); - rootObject.add("mAge", context.serialize(src.getAge())); - rootObject.add("mName",context.serialize(src.getName())); - rootObject.add("mInventory", context.serialize(src.getInventory())); - rootObject.add("mCurrentWeapon", context.serialize(src.getCurrentWeapon())); - rootObject.add("mHelmet", context.serialize(src.getHelmet())); - rootObject.add("mBreastplate", context.serialize(src.getBreastplate())); - rootObject.add("mShield",context.serialize(src.getShield())); - - JsonElement classJson = context.serialize(characterClass); - rootObject.add("mCharClass", classJson); + public static String savePortfolio() { + Type listType = new TypeToken>() { + }.getType(); + return getGson().toJson(Portfolio.get().getPortfolio(), listType); + } - characterClass.setCharacter(src); - return rootObject; + public static void loadPortfolio(String jsonString) { + Type listType = new TypeToken>() { + }.getType(); + ArrayList newPort = getGson().fromJson(jsonString, listType); + Portfolio.get().setPortfolio(newPort); } } diff --git a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/util/Util.java b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/util/Util.java index 5a7ebeb..ab874b7 100644 --- a/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/util/Util.java +++ b/MazesAndMinotaurs/app/src/main/java/com/example/cis/mazeminotaurs/util/Util.java @@ -3,12 +3,24 @@ import com.example.cis.mazeminotaurs.EquipmentDB; import com.example.cis.mazeminotaurs.R; import com.example.cis.mazeminotaurs.Weapon; +import com.example.cis.mazeminotaurs.character.PlayerCharacter; +import com.example.cis.mazeminotaurs.character.classes.Barbarian; /** * Created by jusmith on 9/28/2017. */ public class Util { + public static PlayerCharacter createDummyCharacter() { + PlayerCharacter pc = new PlayerCharacter(); + Barbarian barbarian = new Barbarian(pc, EquipmentDB.getInstance().getWeapon(R.string.barb_axe), + EquipmentDB.getInstance().getWeapon(R.string.barb_axe)); + pc.setCharClass(barbarian); + pc.initializeClass(); + + return pc; + } + /** * Returns the ammo used for a specified missile weapon. */ diff --git a/MazesAndMinotaurs/app/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java b/MazesAndMinotaurs/app/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000..c4d8202 --- /dev/null +++ b/MazesAndMinotaurs/app/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.gson.typeadapters; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + *

+ *

Registering Types

+ * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapter.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapter.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapter.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap>(); + private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory(baseType, "type"); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + public TypeAdapter create(Gson gson, TypeToken type) { + if (null == type || !baseType.isAssignableFrom(type.getRawType())) { + return null; + } + + final Map> labelToDelegate + = new LinkedHashMap>(); + final Map, TypeAdapter> subtypeToDelegate + = new LinkedHashMap, TypeAdapter>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override + public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override + public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + JsonObject clone = new JsonObject(); + clone.add(typeFieldName, new JsonPrimitive(label)); + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} \ No newline at end of file diff --git a/MazesAndMinotaurs/app/src/main/res/drawable-hdpi/ic_save.png b/MazesAndMinotaurs/app/src/main/res/drawable-hdpi/ic_save.png new file mode 100644 index 0000000..897d252 Binary files /dev/null and b/MazesAndMinotaurs/app/src/main/res/drawable-hdpi/ic_save.png differ diff --git a/MazesAndMinotaurs/app/src/main/res/drawable-mdpi/ic_save.png b/MazesAndMinotaurs/app/src/main/res/drawable-mdpi/ic_save.png new file mode 100644 index 0000000..028e92f Binary files /dev/null and b/MazesAndMinotaurs/app/src/main/res/drawable-mdpi/ic_save.png differ diff --git a/MazesAndMinotaurs/app/src/main/res/drawable-xhdpi/ic_save.png b/MazesAndMinotaurs/app/src/main/res/drawable-xhdpi/ic_save.png new file mode 100644 index 0000000..fe006e4 Binary files /dev/null and b/MazesAndMinotaurs/app/src/main/res/drawable-xhdpi/ic_save.png differ diff --git a/MazesAndMinotaurs/app/src/main/res/drawable-xxhdpi/ic_save.png b/MazesAndMinotaurs/app/src/main/res/drawable-xxhdpi/ic_save.png new file mode 100644 index 0000000..13a8a56 Binary files /dev/null and b/MazesAndMinotaurs/app/src/main/res/drawable-xxhdpi/ic_save.png differ diff --git a/MazesAndMinotaurs/app/src/main/res/layout/fragment_character_selection.xml b/MazesAndMinotaurs/app/src/main/res/layout/fragment_character_selection.xml new file mode 100644 index 0000000..d70dca8 --- /dev/null +++ b/MazesAndMinotaurs/app/src/main/res/layout/fragment_character_selection.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/MazesAndMinotaurs/app/src/main/res/layout/spinner_item_character.xml b/MazesAndMinotaurs/app/src/main/res/layout/spinner_item_character.xml new file mode 100644 index 0000000..0a55923 --- /dev/null +++ b/MazesAndMinotaurs/app/src/main/res/layout/spinner_item_character.xml @@ -0,0 +1,29 @@ + + + + + + + + + \ No newline at end of file diff --git a/MazesAndMinotaurs/app/src/main/res/layout/spinner_weapon_item.xml b/MazesAndMinotaurs/app/src/main/res/layout/spinner_item_weapon.xml similarity index 100% rename from MazesAndMinotaurs/app/src/main/res/layout/spinner_weapon_item.xml rename to MazesAndMinotaurs/app/src/main/res/layout/spinner_item_weapon.xml diff --git a/MazesAndMinotaurs/app/src/main/res/menu/activity_main_drawer.xml b/MazesAndMinotaurs/app/src/main/res/menu/activity_main_drawer.xml index db240ee..62363a3 100644 --- a/MazesAndMinotaurs/app/src/main/res/menu/activity_main_drawer.xml +++ b/MazesAndMinotaurs/app/src/main/res/menu/activity_main_drawer.xml @@ -10,6 +10,10 @@ android:id="@+id/play_character" android:icon="@drawable/ic_people_black_24dp" android:title="@string/play_character"/> + + + diff --git a/MazesAndMinotaurs/app/src/main/res/values/strings.xml b/MazesAndMinotaurs/app/src/main/res/values/strings.xml index e6d8cec..0f6216f 100644 --- a/MazesAndMinotaurs/app/src/main/res/values/strings.xml +++ b/MazesAndMinotaurs/app/src/main/res/values/strings.xml @@ -8,6 +8,9 @@ Create New Character Play Existing Character Delete A Character + Must have one character at all times! + Select Active Character + Save Portfolio Web Resources @@ -66,4 +69,9 @@ %s Old Value\n%2d New Value Enter a number + + + Name: %s + Class: %s + Level: %s diff --git a/MazesAndMinotaurs/instapk.log b/MazesAndMinotaurs/instapk.log index 6b941f2..3c19f9e 100644 --- a/MazesAndMinotaurs/instapk.log +++ b/MazesAndMinotaurs/instapk.log @@ -1,2 +1,14 @@ -Oct 12, 2017 12:14:59 PM com.pytenlabs.instapk.helpers.LogHelper init -INFO: Windows 7, 6.1, amd64, Android Studio AI-162.2228.14 +Oct 19, 2017 11:11:42 AM com.pytenlabs.instapk.helpers.LogHelper init +INFO: Linux, 4.9.0-3-amd64, amd64, Android Studio AI-162.2228.14 +Oct 19, 2017 11:20:31 AM com.pytenlabs.instapk.helpers.ApiHelper uploadApk +INFO: versionCode : 1 +Oct 19, 2017 11:20:31 AM com.pytenlabs.instapk.helpers.ApiHelper uploadApk +INFO: versionName : 1.0 +Oct 19, 2017 11:20:31 AM com.pytenlabs.instapk.helpers.ApiHelper uploadApk +INFO: packageName : com.example.cis.mazeminotaurs +Oct 19, 2017 11:20:31 AM com.pytenlabs.instapk.helpers.ApiHelper uploadApk +INFO: release_note : Prototype of character saving +Oct 19, 2017 11:20:40 AM com.pytenlabs.instapk.helpers.ApiHelper$1 run +INFO: RES CODE: 201 +Oct 19, 2017 11:20:40 AM com.pytenlabs.instapk.helpers.ApiHelper$1 run +INFO: RES: {"id":3776,"release_note":"Prototype of character saving","created_time":"2017-10-19T16:22:26.845507Z"}