Commit 1f5ee615 authored by Adrien Oliva's avatar Adrien Oliva

Merge branch '2-character-creation' into 'master'

Resolve "Character creation"

Closes #2

See merge request !2
parents 8a29caf5 c5c79909
Pipeline #478 passed with stage
in 0 seconds
......@@ -23,7 +23,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/opt/android-studio/plugins/android/lib/android.jar!/images/material_design_icons/alert/ic_error_black_24dp.xml" />
<entry key="url" value="jar:file:/opt/android-studio/plugins/android/lib/android.jar!/images/material_design_icons/image/ic_portrait_black_24dp.xml" />
</map>
</option>
</PersistentState>
......@@ -34,7 +34,7 @@
<option name="values">
<map>
<entry key="imageAsset" value="$USER_HOME$/Downloads/icons8-ok-48.png" />
<entry key="outputName" value="ic_failure" />
<entry key="outputName" value="ic_default_avatar" />
</map>
</option>
</PersistentState>
......@@ -51,6 +51,32 @@
</PersistentState>
</value>
</entry>
<entry key="launcherLegacy">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="clipartAsset">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/opt/android-studio/plugins/android/lib/android.jar!/images/material_design_icons/social/ic_person_black_24dp.xml" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="outputName" value="ic_default_avatar" />
</map>
</option>
</PersistentState>
</value>
</entry>
<entry key="notification">
<value>
<PersistentState>
......@@ -76,7 +102,7 @@
</option>
<option name="values">
<map>
<entry key="outputIconType" value="ACTIONBAR" />
<entry key="outputIconType" value="LAUNCHER_LEGACY" />
</map>
</option>
</PersistentState>
......
......@@ -10,6 +10,10 @@ android {
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'GoogleAppIndexingWarning'
disable 'Autofill'
}
buildTypes {
release {
minifyEnabled false
......
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Disable string not used in files strings_*.xml since -->
<!-- strings are only accessed using reflection -->
<issue id="UnusedResources">
<ignore path="res/values/race.xml" />
<ignore path="res/values/strings_mainquest.xml" />
</issue>
</lint>
......@@ -2,8 +2,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fr.yapbreak.skyrimquest">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
......@@ -19,6 +23,14 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".CharacterCreation"
android:label="@string/title_activity_character_creation"
android:theme="@style/AppTheme.NoActionBar" />
<meta-data
android:name="com.google.android.actions"
android:resource="@xml/backup_rules" />
</application>
</manifest>
\ No newline at end of file
package fr.yapbreak.skyrimquest;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import fr.yapbreak.skyrimquest.character.CharacterSaver;
public class CharacterCreation extends AppCompatActivity {
private ImageView avatarView;
private EditText nameView;
private Spinner raceSpinner;
private EditText levelView;
ArrayList<String> raceIdArray;
private final static int LOAD_AVATAR = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_character_creation);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
avatarView = findViewById(R.id.iv_avatar);
nameView = findViewById(R.id.et_name);
raceSpinner = findViewById(R.id.sp_race);
levelView = findViewById(R.id.et_level);
Button levelMinus = findViewById(R.id.bt_level_minus);
Button levelPlus = findViewById(R.id.bt_level_plus);
Button create = findViewById(R.id.bt_character_create);
levelView.setText("1");
levelMinus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int level = Integer.parseInt(levelView.getText().toString());
if (level > 1)
level--;
levelView.setText(String.format("%s", level));
}
});
levelPlus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int level = Integer.parseInt(levelView.getText().toString());
level++;
levelView.setText(String.format("%s", level));
}
});
Cursor raceCursor = QuestList.getDataHandler().getAllRaces();
ArrayList<String> raceSelection = new ArrayList<>();
raceIdArray = new ArrayList<>();
raceCursor.moveToFirst();
do {
String resId = raceCursor.getString(1);
String race;
try {
Field translatedRace = R.string.class.getDeclaredField(resId);
race = getString(translatedRace.getInt(translatedRace));
} catch (Exception e) {
race = resId;
}
raceSelection.add(race);
raceIdArray.add(resId);
raceCursor.moveToNext();
} while (!raceCursor.isAfterLast());
ArrayAdapter<String> raceSpinnerAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, raceSelection);
raceSpinner.setAdapter(raceSpinnerAdapter);
avatarView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, LOAD_AVATAR);
}
});
create.setOnClickListener(new CharacterSaver(this));
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case LOAD_AVATAR:
Uri selectedAvatar = data.getData();
if (selectedAvatar == null) {
return;
}
try {
int width = avatarView.getWidth();
int height = avatarView.getHeight();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedAvatar);
Bitmap myAvatar = Bitmap.createScaledBitmap(bitmap, width, height, false);
avatarView.setImageBitmap(myAvatar);
} catch (IOException e) {
Log.i("SKYRIM", selectedAvatar.toString() + " not found");
}
break;
}
}
}
public String getName()
{
return nameView.getText().toString();
}
public String getRaceId()
{
return raceIdArray.get(raceSpinner.getSelectedItemPosition());
}
public int getLevel()
{
return Integer.parseInt(levelView.getText().toString());
}
public Bitmap getAvatar()
{
BitmapDrawable d = (BitmapDrawable) avatarView.getDrawable();
return d.getBitmap();
}
}
package fr.yapbreak.skyrimquest;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import fr.yapbreak.skyrimquest.data.DataHelper;
import fr.yapbreak.skyrimquest.quests.SkyrimCursorAdapter;
import fr.yapbreak.skyrimquest.character.Character;
public class QuestList extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
protected static DataHelper instance;
protected static Context context;
private DataHelper quest_data;
private Character activeCharacter;
private static final int EXTERNAL_CODE = 570;
private String[] permission = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE};
ListView mainListView;
NavigationView navigationView;
public static DataHelper getDataHandler()
{
return instance;
}
public static Context getContext() {
return context;
}
private void updateCharacterInfo()
{
/*******************************************************************************************
Retrieve active character
******************************************************************************************/
activeCharacter = quest_data.getActiveCharacter();
if (activeCharacter != null) {
View header = navigationView.getHeaderView(0);
ImageView navigation_avatar = header.findViewById(R.id.navigation_avatar);
TextView navigation_name = header.findViewById(R.id.navigation_character_name);
TextView navigation_details = header.findViewById(R.id.navigation_character_details);
navigation_name.setText(activeCharacter.getName());
String details = activeCharacter.getRace()
+ " - "
+ getString(R.string.level_label)
+ " "
+ activeCharacter.getLevel();
navigation_details.setText(details);
navigation_avatar.setImageBitmap(BitmapFactory.decodeFile(activeCharacter.getAvatarFileName()));
}
}
@Override
protected void onResume() {
super.onResume();
updateCharacterInfo();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TODO: remove this line when database is ready
this.deleteDatabase("quest_database");
quest_data = new DataHelper(this);
quest_data.populate();
QuestList.context = getApplicationContext();
setContentView(R.layout.activity_quest_list);
Toolbar toolbar = findViewById(R.id.toolbar);
......@@ -34,17 +99,49 @@ public class QuestList extends AppCompatActivity
DrawerLayout drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
public void onDrawerOpened(View view) {
super.onDrawerOpened(view);
updateCharacterInfo();
}
};
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
/**
* Set up navigation view
*/
mainListView = findViewById(R.id.quests_listview);
/*******************************************************************************************
Set up database
******************************************************************************************/
quest_data = new DataHelper(this);
quest_data.populate();
instance = quest_data;
SkyrimCursorAdapter adapter = new SkyrimCursorAdapter(this, quest_data.getAllQuests());
mainListView.setAdapter(adapter);
}
ListView lv = findViewById(R.id.quests_listview);
lv.setAdapter(adapter);
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case EXTERNAL_CODE:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
copyDatabaseOnExternalData();
}
}
}
@Override
......@@ -74,11 +171,67 @@ public class QuestList extends AppCompatActivity
//noinspection SimplifiableIfStatement
if (id == R.id.action_character_switch) {
return true;
} else if (id == R.id.action_character_create) {
Intent i = new Intent(this, CharacterCreation.class);
startActivity(i);
return true;
} else if (id == R.id.action_debug_grab_database) {
if (checkSelfPermission(permission[0]) == PackageManager.PERMISSION_GRANTED
&& checkSelfPermission(permission[1]) == PackageManager.PERMISSION_GRANTED) {
copyDatabaseOnExternalData();
} else {
requestPermissions(permission, EXTERNAL_CODE);
}
}
return super.onOptionsItemSelected(item);
}
void copyDatabaseOnExternalData()
{
String path = quest_data.getFilename();
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(path);
String outputBase = Environment.getExternalStorageDirectory() + "/quest_data.db";
out = new FileOutputStream(outputBase);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
String toast = getString(R.string.action_debug_grab_database_result);
Toast.makeText(this, toast + outputBase, Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e("SKYRIM", e.getMessage());
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
Log.e("SKYRIM", e.getMessage());
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
Log.e("SKYRIM", e.getMessage());
}
}
}
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
......@@ -101,6 +254,8 @@ public class QuestList extends AppCompatActivity
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
updateCharacterInfo();
return true;
}
}
package fr.yapbreak.skyrimquest.character;
import java.lang.reflect.Field;
import fr.yapbreak.skyrimquest.QuestList;
import fr.yapbreak.skyrimquest.R;
import fr.yapbreak.skyrimquest.data.DataHelper;
public class Character {
private String name;
private String avatarFileName;
private int level;
private int id;
private int raceId;
public Character(int id) throws DataHelper.DataNotFound
{
this.id = id;
QuestList.getDataHandler().FillCharacter(id, this);
}
public Character(String name,
String raceId,
int level,
String avatarFileName)
{
this.name = name;
this.avatarFileName = avatarFileName;
this.level = level;
try {
this.raceId = QuestList.getDataHandler().getRaceId(raceId);
} catch (DataHelper.DataNotFound e) {
this.raceId = -1;
}
this.id = QuestList.getDataHandler().getCharacterId(this);
}
public String getName()
{
return name;
}
public String getAvatarFileName()
{
return avatarFileName;
}
public int getLevel()
{
return level;
}
public int getRaceId()
{
return raceId;
}
public String getRace()
{
String raceIdString;
try {
raceIdString = QuestList.getDataHandler().getRaceIdString(raceId);
} catch (DataHelper.DataNotFound e) {
return Integer.toString(raceId);
}
String race;
try {
Field translatedRace = R.string.class.getDeclaredField(raceIdString);
race = QuestList.getContext().getString(translatedRace.getInt(translatedRace));
} catch (Exception e) {
race = raceIdString;
}
return race;
}
public int getId()
{
return id;
}
void store()
{
this.id = QuestList.getDataHandler().storeCharacter(this);
}
public void setName(String name)
{
this.name = name;
}
public void setLevel(int level)
{
this.level = level;
}
public void setAvatarFileName(String avatarFileName)
{
this.avatarFileName = avatarFileName;
}
public void setRaceId(int raceId)
{
this.raceId = raceId;
}
}
package fr.yapbreak.skyrimquest.character;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.View;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.UUID;
import fr.yapbreak.skyrimquest.CharacterCreation;
public class CharacterSaver implements View.OnClickListener {
private CharacterCreation activity;
public CharacterSaver(CharacterCreation activity) {
this.activity = activity;
}
@Override
public void onClick(View view) {
String name = activity.getName();
String race = activity.getRaceId();
int level = activity.getLevel();
Bitmap avatar = Bitmap.createBitmap(activity.getAvatar());
File avatarFile = new File(view.getContext().getFilesDir(), UUID.randomUUID().toString() + ".png");
try {
FileOutputStream avatarStream = new FileOutputStream(avatarFile);
avatar.compress(Bitmap.CompressFormat.PNG, 95, avatarStream);
avatarStream.flush();
avatarStream.close();
} catch (IOException e) {
Log.e("SKYRIM", "Fail to create avatar image");
e.printStackTrace();
}
Character c = new Character(name, race, level, avatarFile.getAbsolutePath());
c.store();
activity.finish();
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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"
tools:context=".CharacterCreation">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_character_creation" />
</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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/activity_character_creation"
android:layout_width="match_parent"