This commit is contained in:
danijoo
2015-11-05 16:00:48 +01:00
commit c3f35caa6b
221 changed files with 5931 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
package it.jaschke.alexandria;
import android.test.suitebuilder.TestSuiteBuilder;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* Created by saj on 23/12/14.
*/
public class FullTestSuite extends TestSuite {
public static Test suite() {
return new TestSuiteBuilder(FullTestSuite.class)
.includeAllPackagesUnderHere().build();
}
public FullTestSuite() {
super();
}
}

View File

@@ -0,0 +1,180 @@
package it.jaschke.alexandria;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.test.AndroidTestCase;
import java.util.Map;
import java.util.Set;
import it.jaschke.alexandria.data.AlexandriaContract;
import it.jaschke.alexandria.data.DbHelper;
/**
* Created by saj on 23/12/14.
*/
public class TestDb extends AndroidTestCase {
public static final String LOG_TAG = TestDb.class.getSimpleName();
public final static long ean = 9780137903955L;
public final static String title = "Artificial Intelligence";
public final static String subtitle = "A Modern Approach";
public final static String imgUrl = "http://books.google.com/books/content?id=KI2WQgAACAAJ&printsec=frontcover&img=1&zoom=1";
public final static String desc = "Presents a guide to artificial intelligence, covering such topics as intelligent agents, problem-solving, logical agents, planning, uncertainty, learning, and robotics.";
public final static String author = "Stuart Jonathan Russell";
public final static String category = "Computers";
public void testCreateDb() throws Throwable {
mContext.deleteDatabase(DbHelper.DATABASE_NAME);
SQLiteDatabase db = new DbHelper(
this.mContext).getWritableDatabase();
assertEquals(true, db.isOpen());
db.close();
}
public void testInsertReadDb() {
DbHelper dbHelper = new DbHelper(mContext);
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = getBookValues();
long retEan = db.insert(AlexandriaContract.BookEntry.TABLE_NAME, null, values);
assertEquals(ean, retEan);
String[] columns = {
AlexandriaContract.BookEntry._ID,
AlexandriaContract.BookEntry.TITLE,
AlexandriaContract.BookEntry.IMAGE_URL,
AlexandriaContract.BookEntry.SUBTITLE,
AlexandriaContract.BookEntry.DESC
};
// A cursor is your primary interface to the query results.
Cursor cursor = db.query(
AlexandriaContract.BookEntry.TABLE_NAME, // Table to Query
columns,
null, // Columns for the "where" clause
null, // Values for the "where" clause
null, // columns to group by
null, // columns to filter by row groups
null // sort order
);
validateCursor(cursor, values);
values = getAuthorValues();
retEan = db.insert(AlexandriaContract.AuthorEntry.TABLE_NAME, null, values);
columns = new String[]{
AlexandriaContract.AuthorEntry._ID,
AlexandriaContract.AuthorEntry.AUTHOR
};
cursor = db.query(
AlexandriaContract.AuthorEntry.TABLE_NAME, // Table to Query
columns,
null, // Columns for the "where" clause
null, // Values for the "where" clause
null, // columns to group by
null, // columns to filter by row groups
null // sort order
);
validateCursor(cursor, values);
// test category table
values = getCategoryValues();
retEan = db.insert(AlexandriaContract.CategoryEntry.TABLE_NAME, null, values);
columns = new String[]{
AlexandriaContract.CategoryEntry._ID,
AlexandriaContract.CategoryEntry.CATEGORY
};
cursor = db.query(
AlexandriaContract.CategoryEntry.TABLE_NAME, // Table to Query
columns,
null, // Columns for the "where" clause
null, // Values for the "where" clause
null, // columns to group by
null, // columns to filter by row groups
null // sort order
);
validateCursor(cursor, values);
dbHelper.close();
}
static void validateCursor(Cursor valueCursor, ContentValues expectedValues) {
assertTrue(valueCursor.moveToFirst());
Set<Map.Entry<String, Object>> valueSet = expectedValues.valueSet();
for (Map.Entry<String, Object> entry : valueSet) {
String columnName = entry.getKey();
int idx = valueCursor.getColumnIndex(columnName);
assertFalse(columnName,idx == -1);
String expectedValue = entry.getValue().toString();
assertEquals(expectedValue, valueCursor.getString(idx));
}
valueCursor.close();
}
public static ContentValues getBookValues() {
final ContentValues values = new ContentValues();
values.put(AlexandriaContract.BookEntry._ID, ean);
values.put(AlexandriaContract.BookEntry.TITLE, title);
values.put(AlexandriaContract.BookEntry.IMAGE_URL, imgUrl);
values.put(AlexandriaContract.BookEntry.SUBTITLE, subtitle);
values.put(AlexandriaContract.BookEntry.DESC, desc);
return values;
}
public static ContentValues getAuthorValues() {
final ContentValues values= new ContentValues();
values.put(AlexandriaContract.AuthorEntry._ID, ean);
values.put(AlexandriaContract.AuthorEntry.AUTHOR, author);
return values;
}
public static ContentValues getCategoryValues() {
final ContentValues values= new ContentValues();
values.put(AlexandriaContract.CategoryEntry._ID, ean);
values.put(AlexandriaContract.CategoryEntry.CATEGORY, category);
return values;
}
public static ContentValues getFullDetailValues() {
final ContentValues values= new ContentValues();
values.put(AlexandriaContract.BookEntry.TITLE, title);
values.put(AlexandriaContract.BookEntry.IMAGE_URL, imgUrl);
values.put(AlexandriaContract.BookEntry.SUBTITLE, subtitle);
values.put(AlexandriaContract.BookEntry.DESC, desc);
values.put(AlexandriaContract.AuthorEntry.AUTHOR, author);
values.put(AlexandriaContract.CategoryEntry.CATEGORY, category);
return values;
}
public static ContentValues getFullListValues() {
final ContentValues values= new ContentValues();
values.put(AlexandriaContract.BookEntry.TITLE, title);
values.put(AlexandriaContract.BookEntry.IMAGE_URL, imgUrl);
values.put(AlexandriaContract.AuthorEntry.AUTHOR, author);
values.put(AlexandriaContract.CategoryEntry.CATEGORY, category);
return values;
}
}

View File

@@ -0,0 +1,225 @@
package it.jaschke.alexandria;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;
import it.jaschke.alexandria.data.AlexandriaContract;
import it.jaschke.alexandria.data.DbHelper;
/**
* Created by saj on 23/12/14.
*/
public class TestProvider extends AndroidTestCase {
public static final String LOG_TAG = TestProvider.class.getSimpleName();
public void setUp() {
deleteAllRecords();
}
public void deleteAllRecords() {
mContext.getContentResolver().delete(
AlexandriaContract.BookEntry.CONTENT_URI,
null,
null
);
mContext.getContentResolver().delete(
AlexandriaContract.CategoryEntry.CONTENT_URI,
null,
null
);
mContext.getContentResolver().delete(
AlexandriaContract.AuthorEntry.CONTENT_URI,
null,
null
);
Cursor cursor = mContext.getContentResolver().query(
AlexandriaContract.BookEntry.CONTENT_URI,
null,
null,
null,
null
);
assertEquals(0, cursor.getCount());
cursor.close();
cursor = mContext.getContentResolver().query(
AlexandriaContract.AuthorEntry.CONTENT_URI,
null,
null,
null,
null
);
assertEquals(0, cursor.getCount());
cursor.close();
cursor = mContext.getContentResolver().query(
AlexandriaContract.CategoryEntry.CONTENT_URI,
null,
null,
null,
null
);
assertEquals(0, cursor.getCount());
cursor.close();
}
public void testGetType() {
String type = mContext.getContentResolver().getType(AlexandriaContract.BookEntry.CONTENT_URI);
assertEquals(AlexandriaContract.BookEntry.CONTENT_TYPE, type);
type = mContext.getContentResolver().getType(AlexandriaContract.AuthorEntry.CONTENT_URI);
assertEquals(AlexandriaContract.AuthorEntry.CONTENT_TYPE, type);
type = mContext.getContentResolver().getType(AlexandriaContract.CategoryEntry.CONTENT_URI);
assertEquals(AlexandriaContract.CategoryEntry.CONTENT_TYPE, type);
long id = 9780137903955L;
type = mContext.getContentResolver().getType(AlexandriaContract.BookEntry.buildBookUri(id));
assertEquals(AlexandriaContract.BookEntry.CONTENT_ITEM_TYPE, type);
type = mContext.getContentResolver().getType(AlexandriaContract.BookEntry.buildFullBookUri(id));
assertEquals(AlexandriaContract.BookEntry.CONTENT_ITEM_TYPE, type);
type = mContext.getContentResolver().getType(AlexandriaContract.AuthorEntry.buildAuthorUri(id));
assertEquals(AlexandriaContract.AuthorEntry.CONTENT_ITEM_TYPE, type);
type = mContext.getContentResolver().getType(AlexandriaContract.CategoryEntry.buildCategoryUri(id));
assertEquals(AlexandriaContract.CategoryEntry.CONTENT_ITEM_TYPE, type);
}
public void testInsertRead(){
insertReadBook();
insertReadAuthor();
insertReadCategory();
readFullBook();
readFullList();
}
public void insertReadBook(){
ContentValues bookValues = TestDb.getBookValues();
Uri bookUri = mContext.getContentResolver().insert(AlexandriaContract.BookEntry.CONTENT_URI, bookValues);
long bookRowId = ContentUris.parseId(bookUri);
assertTrue(bookRowId != -1);
Cursor cursor = mContext.getContentResolver().query(
AlexandriaContract.BookEntry.CONTENT_URI,
null, // leaving "columns" null just returns all the columns.
null, // cols for "where" clause
null, // values for "where" clause
null // sort order
);
TestDb.validateCursor(cursor, bookValues);
cursor = mContext.getContentResolver().query(
AlexandriaContract.BookEntry.buildBookUri(bookRowId),
null, // leaving "columns" null just returns all the columns.
null, // cols for "where" clause
null, // values for "where" clause
null // sort order
);
TestDb.validateCursor(cursor, bookValues);
}
public void insertReadAuthor(){
ContentValues authorValues = TestDb.getAuthorValues();
Uri authorUri = mContext.getContentResolver().insert(AlexandriaContract.AuthorEntry.CONTENT_URI, authorValues);
long authorRowId = ContentUris.parseId(authorUri);
assertTrue(authorRowId != -1);
assertEquals(authorRowId,TestDb.ean);
Cursor cursor = mContext.getContentResolver().query(
AlexandriaContract.AuthorEntry.CONTENT_URI,
null, // leaving "columns" null just returns all the columns.
null, // cols for "where" clause
null, // values for "where" clause
null // sort order
);
TestDb.validateCursor(cursor, authorValues);
cursor = mContext.getContentResolver().query(
AlexandriaContract.AuthorEntry.buildAuthorUri(authorRowId),
null, // leaving "columns" null just returns all the columns.
null, // cols for "where" clause
null, // values for "where" clause
null // sort order
);
TestDb.validateCursor(cursor, authorValues);
}
public void insertReadCategory(){
ContentValues categoryValues = TestDb.getCategoryValues();
Uri categoryUri = mContext.getContentResolver().insert(AlexandriaContract.CategoryEntry.CONTENT_URI, categoryValues);
long categoryRowId = ContentUris.parseId(categoryUri);
assertTrue(categoryRowId != -1);
assertEquals(categoryRowId,TestDb.ean);
Cursor cursor = mContext.getContentResolver().query(
AlexandriaContract.CategoryEntry.CONTENT_URI,
null, // projection
null, // selection
null, // selection args
null // sort order
);
TestDb.validateCursor(cursor, categoryValues);
cursor = mContext.getContentResolver().query(
AlexandriaContract.CategoryEntry.buildCategoryUri(categoryRowId),
null, // projection
null, // selection
null, // selection args
null // sort order
);
TestDb.validateCursor(cursor, categoryValues);
}
public void readFullBook(){
Cursor cursor = mContext.getContentResolver().query(
AlexandriaContract.BookEntry.buildFullBookUri(TestDb.ean),
null, // projection
null, // selection
null, // selection args
null // sort order
);
TestDb.validateCursor(cursor, TestDb.getFullDetailValues());
}
public void readFullList(){
Cursor cursor = mContext.getContentResolver().query(
AlexandriaContract.BookEntry.FULL_CONTENT_URI,
null, // projection
null, // selection
null, // selection args
null // sort order
);
TestDb.validateCursor(cursor, TestDb.getFullListValues());
}
}

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.jaschke.alexandria" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:configChanges="orientation"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:label="@string/title_activity_settings"
android:name=".SettingsActivity"
android:parentActivityName=".MainActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
<activity android:name=".BarcodeActivity" />
<provider
android:name=".data.BookProvider"
android:authorities="it.jaschke.alexandria"
android:exported="false" />
<service
android:name=".services.BookService"
android:exported="false" >
</service>
</application>
</manifest>

View File

@@ -0,0 +1,25 @@
package it.jaschke.alexandria;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class About extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_about, container, false);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
activity.setTitle(R.string.about);
}
}

View File

@@ -0,0 +1,208 @@
package it.jaschke.alexandria;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import it.jaschke.alexandria.data.AlexandriaContract;
import it.jaschke.alexandria.services.BookService;
import it.jaschke.alexandria.services.DownloadImage;
public class AddBook extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String TAG = "INTENT_TO_SCAN_ACTIVITY";
private static final int SCAN_INTENT_REQUEST_CODE = 12643;
private EditText ean;
private final int LOADER_ID = 1;
private View rootView;
private final String EAN_CONTENT="eanContent";
private static final String SCAN_FORMAT = "scanFormat";
private static final String SCAN_CONTENTS = "scanContents";
private String mScanFormat = "Format:";
private String mScanContents = "Contents:";
public static final String EAN_13_PREFIX = "978";
public AddBook(){
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(ean!=null) {
outState.putString(EAN_CONTENT, ean.getText().toString());
}
}
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_add_book, container, false);
ean = (EditText) rootView.findViewById(R.id.ean);
ean.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//no need
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//no need
}
@Override
public void afterTextChanged(Editable s) {
String ean =s.toString();
//catch isbn10 numbers
if(ean.length()==10 && !ean.startsWith(EAN_13_PREFIX)){
ean=EAN_13_PREFIX+ean;
}
if(ean.length()<13){
clearFields();
return;
}
//Once we have an ISBN, start a book intent
Intent bookIntent = new Intent(getActivity(), BookService.class);
bookIntent.putExtra(BookService.EAN, ean);
bookIntent.setAction(BookService.FETCH_BOOK);
getActivity().startService(bookIntent);
AddBook.this.restartLoader();
}
});
rootView.findViewById(R.id.scan_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(getActivity(), BarcodeActivity.class);
startActivityForResult(i, SCAN_INTENT_REQUEST_CODE);
}
});
rootView.findViewById(R.id.save_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ean.setText("");
}
});
rootView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent bookIntent = new Intent(getActivity(), BookService.class);
bookIntent.putExtra(BookService.EAN, ean.getText().toString());
bookIntent.setAction(BookService.DELETE_BOOK);
getActivity().startService(bookIntent);
ean.setText("");
}
});
if(savedInstanceState!=null){
ean.setText(savedInstanceState.getString(EAN_CONTENT));
ean.setHint("");
}
return rootView;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == Activity.RESULT_OK && requestCode == SCAN_INTENT_REQUEST_CODE && data.hasExtra("isbn")) {
ean.setText(data.getStringExtra("isbn"));
}
}
private void restartLoader(){
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
@Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
if(ean.getText().length()==0){
return null;
}
String eanStr= ean.getText().toString();
if(eanStr.length()==10 && !eanStr.startsWith(EAN_13_PREFIX)){
eanStr=EAN_13_PREFIX+eanStr;
}
return new CursorLoader(
getActivity(),
AlexandriaContract.BookEntry.buildFullBookUri(Long.parseLong(eanStr)),
null,
null,
null,
null
);
}
@Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
if (!data.moveToFirst()) {
return;
}
String bookTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.TITLE));
((TextView) rootView.findViewById(R.id.bookTitle)).setText(bookTitle);
String bookSubTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.SUBTITLE));
((TextView) rootView.findViewById(R.id.bookSubTitle)).setText(bookSubTitle);
String authors = data.getString(data.getColumnIndex(AlexandriaContract.AuthorEntry.AUTHOR));
String[] authorsArr = authors.split(",");
((TextView) rootView.findViewById(R.id.authors)).setLines(authorsArr.length);
((TextView) rootView.findViewById(R.id.authors)).setText(authors.replace(",","\n"));
String imgUrl = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.IMAGE_URL));
if(Patterns.WEB_URL.matcher(imgUrl).matches()){
new DownloadImage((ImageView) rootView.findViewById(R.id.bookCover)).execute(imgUrl);
rootView.findViewById(R.id.bookCover).setVisibility(View.VISIBLE);
}
String categories = data.getString(data.getColumnIndex(AlexandriaContract.CategoryEntry.CATEGORY));
((TextView) rootView.findViewById(R.id.categories)).setText(categories);
rootView.findViewById(R.id.save_button).setVisibility(View.VISIBLE);
rootView.findViewById(R.id.delete_button).setVisibility(View.VISIBLE);
}
@Override
public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {
}
private void clearFields(){
((TextView) rootView.findViewById(R.id.bookTitle)).setText("");
((TextView) rootView.findViewById(R.id.bookSubTitle)).setText("");
((TextView) rootView.findViewById(R.id.authors)).setText("");
((TextView) rootView.findViewById(R.id.categories)).setText("");
rootView.findViewById(R.id.bookCover).setVisibility(View.INVISIBLE);
rootView.findViewById(R.id.save_button).setVisibility(View.INVISIBLE);
rootView.findViewById(R.id.delete_button).setVisibility(View.INVISIBLE);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
activity.setTitle(R.string.scan);
}
}

View File

@@ -0,0 +1,60 @@
package it.jaschke.alexandria;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import com.google.zxing.Result;
import me.dm7.barcodescanner.zxing.ZXingScannerView;
/**
* Activity for reading barcodes
*/
public class BarcodeActivity extends ActionBarActivity implements ZXingScannerView.ResultHandler {
public static final String TAG = BarcodeActivity.class.getSimpleName();
private ZXingScannerView mScannerView;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
mScannerView = new ZXingScannerView(this);
setContentView(mScannerView);
}
@Override
public void onResume() {
super.onResume();
mScannerView.setResultHandler(this);
mScannerView.startCamera();
}
@Override
public void onPause() {
super.onPause();
mScannerView.stopCamera();
}
@Override
public void onBackPressed() {
Intent result = new Intent();
setResult(Activity.RESULT_CANCELED, result);
finish();
super.onBackPressed();
}
@Override
public void handleResult(Result rawResult) {
Log.v(TAG, rawResult.getText());
Log.v(TAG, rawResult.getBarcodeFormat().toString());
Intent result = new Intent();
result.putExtra("isbn", rawResult.getText());
setResult(Activity.RESULT_OK, result);
finish();
}
}

View File

@@ -0,0 +1,143 @@
package it.jaschke.alexandria;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.ShareActionProvider;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import it.jaschke.alexandria.data.AlexandriaContract;
import it.jaschke.alexandria.services.BookService;
import it.jaschke.alexandria.services.DownloadImage;
public class BookDetail extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
public static final String EAN_KEY = "EAN";
private final int LOADER_ID = 10;
private View rootView;
private String ean;
private String bookTitle;
private ShareActionProvider shareActionProvider;
public BookDetail(){
}
@Override
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle arguments = getArguments();
if (arguments != null) {
ean = arguments.getString(BookDetail.EAN_KEY);
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
rootView = inflater.inflate(R.layout.fragment_full_book, container, false);
rootView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent bookIntent = new Intent(getActivity(), BookService.class);
bookIntent.putExtra(BookService.EAN, ean);
bookIntent.setAction(BookService.DELETE_BOOK);
getActivity().startService(bookIntent);
getActivity().getSupportFragmentManager().popBackStack();
}
});
return rootView;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.book_detail, menu);
MenuItem menuItem = menu.findItem(R.id.action_share);
shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);
}
@Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(
getActivity(),
AlexandriaContract.BookEntry.buildFullBookUri(Long.parseLong(ean)),
null,
null,
null,
null
);
}
@Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
if (!data.moveToFirst()) {
return;
}
bookTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.TITLE));
((TextView) rootView.findViewById(R.id.fullBookTitle)).setText(bookTitle);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text)+bookTitle);
shareActionProvider.setShareIntent(shareIntent);
String bookSubTitle = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.SUBTITLE));
((TextView) rootView.findViewById(R.id.fullBookSubTitle)).setText(bookSubTitle);
String desc = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.DESC));
((TextView) rootView.findViewById(R.id.fullBookDesc)).setText(desc);
String authors = data.getString(data.getColumnIndex(AlexandriaContract.AuthorEntry.AUTHOR));
String[] authorsArr = authors.split(",");
((TextView) rootView.findViewById(R.id.authors)).setLines(authorsArr.length);
((TextView) rootView.findViewById(R.id.authors)).setText(authors.replace(",","\n"));
String imgUrl = data.getString(data.getColumnIndex(AlexandriaContract.BookEntry.IMAGE_URL));
if(Patterns.WEB_URL.matcher(imgUrl).matches()){
new DownloadImage((ImageView) rootView.findViewById(R.id.fullBookCover)).execute(imgUrl);
rootView.findViewById(R.id.fullBookCover).setVisibility(View.VISIBLE);
}
String categories = data.getString(data.getColumnIndex(AlexandriaContract.CategoryEntry.CATEGORY));
((TextView) rootView.findViewById(R.id.categories)).setText(categories);
if(rootView.findViewById(R.id.right_container)!=null){
rootView.findViewById(R.id.backButton).setVisibility(View.INVISIBLE);
}
}
@Override
public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {
}
@Override
public void onPause() {
super.onDestroyView();
if(MainActivity.IS_TABLET && rootView.findViewById(R.id.right_container)==null){
getActivity().getSupportFragmentManager().popBackStack();
}
}
}

View File

@@ -0,0 +1,132 @@
package it.jaschke.alexandria;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import it.jaschke.alexandria.api.BookListAdapter;
import it.jaschke.alexandria.api.Callback;
import it.jaschke.alexandria.data.AlexandriaContract;
public class ListOfBooks extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private BookListAdapter bookListAdapter;
private ListView bookList;
private int position = ListView.INVALID_POSITION;
private EditText searchText;
private final int LOADER_ID = 10;
public ListOfBooks() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Cursor cursor = getActivity().getContentResolver().query(
AlexandriaContract.BookEntry.CONTENT_URI,
null, // leaving "columns" null just returns all the columns.
null, // cols for "where" clause
null, // values for "where" clause
null // sort order
);
bookListAdapter = new BookListAdapter(getActivity(), cursor, 0);
View rootView = inflater.inflate(R.layout.fragment_list_of_books, container, false);
searchText = (EditText) rootView.findViewById(R.id.searchText);
rootView.findViewById(R.id.searchButton).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
ListOfBooks.this.restartLoader();
}
}
);
bookList = (ListView) rootView.findViewById(R.id.listOfBooks);
bookList.setAdapter(bookListAdapter);
bookList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Cursor cursor = bookListAdapter.getCursor();
if (cursor != null && cursor.moveToPosition(position)) {
((Callback)getActivity())
.onItemSelected(cursor.getString(cursor.getColumnIndex(AlexandriaContract.BookEntry._ID)));
}
}
});
return rootView;
}
private void restartLoader(){
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
final String selection = AlexandriaContract.BookEntry.TITLE +" LIKE ? OR " + AlexandriaContract.BookEntry.SUBTITLE + " LIKE ? ";
String searchString =searchText.getText().toString();
if(searchString.length()>0){
searchString = "%"+searchString+"%";
return new CursorLoader(
getActivity(),
AlexandriaContract.BookEntry.CONTENT_URI,
null,
selection,
new String[]{searchString,searchString},
null
);
}
return new CursorLoader(
getActivity(),
AlexandriaContract.BookEntry.CONTENT_URI,
null,
null,
null,
null
);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
bookListAdapter.swapCursor(data);
if (position != ListView.INVALID_POSITION) {
bookList.smoothScrollToPosition(position);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
bookListAdapter.swapCursor(null);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
activity.setTitle(R.string.books);
}
}

View File

@@ -0,0 +1,182 @@
package it.jaschke.alexandria;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import it.jaschke.alexandria.api.Callback;
public class MainActivity extends ActionBarActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks, Callback {
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment navigationDrawerFragment;
/**
* Used to store the last screen title. For use in {@link #restoreActionBar()}.
*/
private CharSequence title;
public static boolean IS_TABLET = false;
private BroadcastReceiver messageReciever;
public static final String MESSAGE_EVENT = "MESSAGE_EVENT";
public static final String MESSAGE_KEY = "MESSAGE_EXTRA";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IS_TABLET = isTablet();
if(IS_TABLET){
setContentView(R.layout.activity_main_tablet);
}else {
setContentView(R.layout.activity_main);
}
messageReciever = new MessageReciever();
IntentFilter filter = new IntentFilter(MESSAGE_EVENT);
LocalBroadcastManager.getInstance(this).registerReceiver(messageReciever,filter);
navigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
title = getTitle();
// Set up the drawer.
navigationDrawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
@Override
public void onNavigationDrawerItemSelected(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment nextFragment;
switch (position){
default:
case 0:
nextFragment = new ListOfBooks();
break;
case 1:
nextFragment = new AddBook();
break;
case 2:
nextFragment = new About();
break;
}
fragmentManager.beginTransaction()
.replace(R.id.container, nextFragment)
.addToBackStack((String) title)
.commit();
}
public void setTitle(int titleId) {
title = getString(titleId);
}
public void restoreActionBar() {
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(title);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!navigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.main, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReciever);
super.onDestroy();
}
@Override
public void onItemSelected(String ean) {
Bundle args = new Bundle();
args.putString(BookDetail.EAN_KEY, ean);
BookDetail fragment = new BookDetail();
fragment.setArguments(args);
int id = R.id.container;
if(findViewById(R.id.right_container) != null){
id = R.id.right_container;
}
getSupportFragmentManager().beginTransaction()
.replace(id, fragment)
.addToBackStack("Book Detail")
.commit();
}
private class MessageReciever extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getStringExtra(MESSAGE_KEY)!=null){
Toast.makeText(MainActivity.this, intent.getStringExtra(MESSAGE_KEY), Toast.LENGTH_LONG).show();
}
}
}
public void goBack(View view){
getSupportFragmentManager().popBackStack();
}
private boolean isTablet() {
return (getApplicationContext().getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
@Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount()<2){
finish();
}
super.onBackPressed();
}
}

View File

@@ -0,0 +1,282 @@
package it.jaschke.alexandria;
import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
/**
* Fragment used for managing interactions for and presentation of a navigation drawer.
* See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
* design guidelines</a> for a complete explanation of the behaviors implemented here.
*/
public class NavigationDrawerFragment extends Fragment {
/**
* Remember the position of the selected item.
*/
private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
/**
* Per the design guidelines, you should show the drawer on launch until the user manually
* expands it. This shared preference tracks this.
*/
private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
/**
* A pointer to the current callbacks instance (the Activity).
*/
private NavigationDrawerCallbacks mCallbacks;
/**
* Helper component that ties the action bar to the navigation drawer.
*/
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private ListView mDrawerListView;
private View mFragmentContainerView;
private int mCurrentSelectedPosition = 0;
private boolean mFromSavedInstanceState;
private boolean mUserLearnedDrawer;
public NavigationDrawerFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Read in the flag indicating whether or not the user has demonstrated awareness of the
// drawer. See PREF_USER_LEARNED_DRAWER for details.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
if (savedInstanceState != null) {
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
mFromSavedInstanceState = true;
}else{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
mCurrentSelectedPosition = Integer.parseInt(prefs.getString("pref_startFragment","0"));
selectItem(mCurrentSelectedPosition);
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Indicate that this fragment would like to influence the set of actions in the action bar.
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mDrawerListView = (ListView) inflater.inflate(
R.layout.fragment_navigation_drawer, container, false);
mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
});
mDrawerListView.setAdapter(new ArrayAdapter<String>(
getActionBar().getThemedContext(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
new String[]{
getString(R.string.books),
getString(R.string.scan),
getString(R.string.about),
}));
mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
return mDrawerListView;
}
public boolean isDrawerOpen() {
return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
}
/**
* Users of this fragment must call this method to set up the navigation drawer interactions.
*
* @param fragmentId The android:id of this fragment in its activity's layout.
* @param drawerLayout The DrawerLayout containing this fragment's UI.
*/
public void setUp(int fragmentId, DrawerLayout drawerLayout) {
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
// set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// set up the drawer's list view with items and click listener
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the navigation drawer and the action bar app icon.
mDrawerToggle = new ActionBarDrawerToggle(
getActivity(), /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.navigation_drawer_open, /* "open drawer" description for accessibility */
R.string.navigation_drawer_close /* "close drawer" description for accessibility */
) {
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
}
getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
}
if (!mUserLearnedDrawer) {
// The user manually opened the drawer; store this flag to prevent auto-showing
// the navigation drawer automatically in the future.
mUserLearnedDrawer = true;
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
}
getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
};
// If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
// per the navigation drawer design guidelines.
if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
mDrawerLayout.openDrawer(mFragmentContainerView);
}
// Defer code dependent on restoration of previous instance state.
mDrawerLayout.post(new Runnable() {
@Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
private void selectItem(int position) {
mCurrentSelectedPosition = position;
if (mDrawerListView != null) {
mDrawerListView.setItemChecked(position, true);
}
if (mDrawerLayout != null) {
mDrawerLayout.closeDrawer(mFragmentContainerView);
}
if (mCallbacks != null) {
mCallbacks.onNavigationDrawerItemSelected(position);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallbacks = (NavigationDrawerCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
}
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Forward the new configuration the drawer toggle component.
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// If the drawer is open, show the global app actions in the action bar. See also
// showGlobalContextActionBar, which controls the top-left area of the action bar.
if (mDrawerLayout != null && isDrawerOpen()) {
inflater.inflate(R.menu.main, menu);
showGlobalContextActionBar();
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Per the navigation drawer design guidelines, updates the action bar to show the global app
* 'context', rather than just what's in the current screen.
*/
private void showGlobalContextActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(R.string.app_name);
}
private ActionBar getActionBar() {
return ((ActionBarActivity) getActivity()).getSupportActionBar();
}
/**
* Callbacks interface that all activities using this fragment must implement.
*/
public static interface NavigationDrawerCallbacks {
/**
* Called when an item in the navigation drawer is selected.
*/
void onNavigationDrawerItemSelected(int position);
}
}

View File

@@ -0,0 +1,18 @@
package it.jaschke.alexandria;
import android.os.Bundle;
import android.preference.PreferenceActivity;
/**
* Created by saj on 27/01/15.
*/
public class SettingsActivity extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}

View File

@@ -0,0 +1,63 @@
package it.jaschke.alexandria.api;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import it.jaschke.alexandria.R;
import it.jaschke.alexandria.data.AlexandriaContract;
import it.jaschke.alexandria.services.DownloadImage;
/**
* Created by saj on 11/01/15.
*/
public class BookListAdapter extends CursorAdapter {
public static class ViewHolder {
public final ImageView bookCover;
public final TextView bookTitle;
public final TextView bookSubTitle;
public ViewHolder(View view) {
bookCover = (ImageView) view.findViewById(R.id.fullBookCover);
bookTitle = (TextView) view.findViewById(R.id.listBookTitle);
bookSubTitle = (TextView) view.findViewById(R.id.listBookSubTitle);
}
}
public BookListAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
String imgUrl = cursor.getString(cursor.getColumnIndex(AlexandriaContract.BookEntry.IMAGE_URL));
new DownloadImage(viewHolder.bookCover).execute(imgUrl);
String bookTitle = cursor.getString(cursor.getColumnIndex(AlexandriaContract.BookEntry.TITLE));
viewHolder.bookTitle.setText(bookTitle);
String bookSubTitle = cursor.getString(cursor.getColumnIndex(AlexandriaContract.BookEntry.SUBTITLE));
viewHolder.bookSubTitle.setText(bookSubTitle);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.book_list_item, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
}

View File

@@ -0,0 +1,8 @@
package it.jaschke.alexandria.api;
/**
* Created by saj on 25/01/15.
*/
public interface Callback {
void onItemSelected(String ean);
}

View File

@@ -0,0 +1,88 @@
package it.jaschke.alexandria.data;
/**
* Created by saj on 22/12/14.
*/
import android.content.ContentUris;
import android.net.Uri;
import android.provider.BaseColumns;
import android.util.Log;
public class AlexandriaContract{
public static final String CONTENT_AUTHORITY = "it.jaschke.alexandria";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final String PATH_BOOKS = "books";
public static final String PATH_AUTHORS = "authors";
public static final String PATH_CATEGORIES = "categories";
public static final String PATH_FULLBOOK = "fullbook";
public static final class BookEntry implements BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_BOOKS).build();
public static final Uri FULL_CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_FULLBOOK).build();
public static final String CONTENT_TYPE =
"vnd.android.cursor.dir/" + CONTENT_AUTHORITY + "/" + PATH_BOOKS;
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/" + CONTENT_AUTHORITY + "/" + PATH_BOOKS;
public static final String TABLE_NAME = "books";
public static final String TITLE = "title";
public static final String IMAGE_URL = "imgurl";
public static final String SUBTITLE = "subtitle";
public static final String DESC = "description";
public static Uri buildBookUri(long id) {
return ContentUris.withAppendedId(CONTENT_URI, id);
}
public static Uri buildFullBookUri(long id) {
return ContentUris.withAppendedId(FULL_CONTENT_URI, id);
}
}
public static final class AuthorEntry implements BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_AUTHORS).build();
public static final String CONTENT_TYPE =
"vnd.android.cursor.dir/" + CONTENT_AUTHORITY + "/" + PATH_AUTHORS;
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/" + CONTENT_AUTHORITY + "/" + PATH_AUTHORS;
public static final String TABLE_NAME = "authors";
public static final String AUTHOR = "author";
public static Uri buildAuthorUri(long id) {
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
public static final class CategoryEntry implements BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_CATEGORIES).build();
public static final String CONTENT_TYPE =
"vnd.android.cursor.dir/" + CONTENT_AUTHORITY + "/" + PATH_CATEGORIES;
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/" + CONTENT_AUTHORITY + "/" + PATH_CATEGORIES;
public static final String TABLE_NAME = "categories";
public static final String CATEGORY = "category";
public static Uri buildCategoryUri(long id) {
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
}

View File

@@ -0,0 +1,307 @@
package it.jaschke.alexandria.data;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.util.Log;
/**
* Created by saj on 24/12/14.
*/
public class BookProvider extends ContentProvider {
private static final int BOOK_ID = 100;
private static final int BOOK = 101;
private static final int AUTHOR_ID = 200;
private static final int AUTHOR = 201;
private static final int CATEGORY_ID = 300;
private static final int CATEGORY = 301;
private static final int BOOK_FULL = 500;
private static final int BOOK_FULLDETAIL = 501;
private static final UriMatcher uriMatcher = buildUriMatcher();
private DbHelper dbHelper;
private static final SQLiteQueryBuilder bookFull;
static{
bookFull = new SQLiteQueryBuilder();
bookFull.setTables(
AlexandriaContract.BookEntry.TABLE_NAME + " LEFT OUTER JOIN " +
AlexandriaContract.AuthorEntry.TABLE_NAME + " USING (" +AlexandriaContract.BookEntry._ID + ")" +
" LEFT OUTER JOIN " + AlexandriaContract.CategoryEntry.TABLE_NAME + " USING (" +AlexandriaContract.BookEntry._ID + ")");
}
private static UriMatcher buildUriMatcher() {
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = AlexandriaContract.CONTENT_AUTHORITY;
matcher.addURI(authority, AlexandriaContract.PATH_BOOKS+"/#", BOOK_ID);
matcher.addURI(authority, AlexandriaContract.PATH_AUTHORS+"/#", AUTHOR_ID);
matcher.addURI(authority, AlexandriaContract.PATH_CATEGORIES+"/#", CATEGORY_ID);
matcher.addURI(authority, AlexandriaContract.PATH_BOOKS, BOOK);
matcher.addURI(authority, AlexandriaContract.PATH_AUTHORS, AUTHOR);
matcher.addURI(authority, AlexandriaContract.PATH_CATEGORIES, CATEGORY);
matcher.addURI(authority, AlexandriaContract.PATH_FULLBOOK +"/#", BOOK_FULLDETAIL);
matcher.addURI(authority, AlexandriaContract.PATH_FULLBOOK, BOOK_FULL);
return matcher;
}
@Override
public boolean onCreate() {
dbHelper = new DbHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor retCursor;
switch (uriMatcher.match(uri)) {
case BOOK:
retCursor=dbHelper.getReadableDatabase().query(
AlexandriaContract.BookEntry.TABLE_NAME,
projection,
selection,
selection==null? null : selectionArgs,
null,
null,
sortOrder
);
break;
case AUTHOR:
retCursor=dbHelper.getReadableDatabase().query(
AlexandriaContract.AuthorEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
case CATEGORY:
retCursor=dbHelper.getReadableDatabase().query(
AlexandriaContract.CategoryEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
case BOOK_ID:
retCursor=dbHelper.getReadableDatabase().query(
AlexandriaContract.BookEntry.TABLE_NAME,
projection,
AlexandriaContract.BookEntry._ID + " = '" + ContentUris.parseId(uri) + "'",
selectionArgs,
null,
null,
sortOrder
);
break;
case AUTHOR_ID:
retCursor=dbHelper.getReadableDatabase().query(
AlexandriaContract.AuthorEntry.TABLE_NAME,
projection,
AlexandriaContract.AuthorEntry._ID + " = '" + ContentUris.parseId(uri) + "'",
selectionArgs,
null,
null,
sortOrder
);
break;
case CATEGORY_ID:
retCursor=dbHelper.getReadableDatabase().query(
AlexandriaContract.CategoryEntry.TABLE_NAME,
projection,
AlexandriaContract.CategoryEntry._ID + " = '" + ContentUris.parseId(uri) + "'",
selectionArgs,
null,
null,
sortOrder
);
break;
case BOOK_FULLDETAIL:
String[] bfd_projection ={
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry.TITLE,
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry.SUBTITLE,
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry.IMAGE_URL,
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry.DESC,
"group_concat(DISTINCT " + AlexandriaContract.AuthorEntry.TABLE_NAME+ "."+ AlexandriaContract.AuthorEntry.AUTHOR +") as " + AlexandriaContract.AuthorEntry.AUTHOR,
"group_concat(DISTINCT " + AlexandriaContract.CategoryEntry.TABLE_NAME+ "."+ AlexandriaContract.CategoryEntry.CATEGORY +") as " + AlexandriaContract.CategoryEntry.CATEGORY
};
retCursor = bookFull.query(dbHelper.getReadableDatabase(),
bfd_projection,
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry._ID + " = '" + ContentUris.parseId(uri) + "'",
selectionArgs,
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry._ID,
null,
sortOrder);
break;
case BOOK_FULL:
String[] bf_projection ={
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry.TITLE,
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry.IMAGE_URL,
"group_concat(DISTINCT " + AlexandriaContract.AuthorEntry.TABLE_NAME+ "."+ AlexandriaContract.AuthorEntry.AUTHOR + ") as " + AlexandriaContract.AuthorEntry.AUTHOR,
"group_concat(DISTINCT " + AlexandriaContract.CategoryEntry.TABLE_NAME+ "."+ AlexandriaContract.CategoryEntry.CATEGORY +") as " + AlexandriaContract.CategoryEntry.CATEGORY
};
retCursor = bookFull.query(dbHelper.getReadableDatabase(),
bf_projection,
null,
selectionArgs,
AlexandriaContract.BookEntry.TABLE_NAME + "." + AlexandriaContract.BookEntry._ID,
null,
sortOrder);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
@Override
public String getType(Uri uri) {
final int match = uriMatcher.match(uri);
switch (match) {
case BOOK_FULLDETAIL:
return AlexandriaContract.BookEntry.CONTENT_ITEM_TYPE;
case BOOK_ID:
return AlexandriaContract.BookEntry.CONTENT_ITEM_TYPE;
case AUTHOR_ID:
return AlexandriaContract.AuthorEntry.CONTENT_ITEM_TYPE;
case CATEGORY_ID:
return AlexandriaContract.CategoryEntry.CONTENT_ITEM_TYPE;
case BOOK:
return AlexandriaContract.BookEntry.CONTENT_TYPE;
case AUTHOR:
return AlexandriaContract.AuthorEntry.CONTENT_TYPE;
case CATEGORY:
return AlexandriaContract.CategoryEntry.CONTENT_TYPE;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
final int match = uriMatcher.match(uri);
Uri returnUri;
switch (match) {
case BOOK: {
long _id = db.insert(AlexandriaContract.BookEntry.TABLE_NAME, null, values);
if ( _id > 0 ){
returnUri = AlexandriaContract.BookEntry.buildBookUri(_id);
} else {
throw new android.database.SQLException("Failed to insert row into " + uri);
}
getContext().getContentResolver().notifyChange(AlexandriaContract.BookEntry.buildFullBookUri(_id), null);
break;
}
case AUTHOR:{
long _id = db.insert(AlexandriaContract.AuthorEntry.TABLE_NAME, null, values);
if ( _id > 0 )
returnUri = AlexandriaContract.AuthorEntry.buildAuthorUri(values.getAsLong("_id"));
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
}
case CATEGORY: {
long _id = db.insert(AlexandriaContract.CategoryEntry.TABLE_NAME, null, values);
if (_id > 0)
returnUri = AlexandriaContract.CategoryEntry.buildCategoryUri(values.getAsLong("_id"));
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
}
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
return returnUri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
final int match = uriMatcher.match(uri);
int rowsDeleted;
switch (match) {
case BOOK:
rowsDeleted = db.delete(
AlexandriaContract.BookEntry.TABLE_NAME, selection, selectionArgs);
break;
case AUTHOR:
rowsDeleted = db.delete(
AlexandriaContract.AuthorEntry.TABLE_NAME, selection, selectionArgs);
break;
case CATEGORY:
rowsDeleted = db.delete(
AlexandriaContract.CategoryEntry.TABLE_NAME, selection, selectionArgs);
break;
case BOOK_ID:
rowsDeleted = db.delete(
AlexandriaContract.BookEntry.TABLE_NAME,
AlexandriaContract.BookEntry._ID + " = '" + ContentUris.parseId(uri) + "'",
selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Because a null deletes all rows
if (selection == null || rowsDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsDeleted;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final SQLiteDatabase db = dbHelper.getWritableDatabase();
final int match = uriMatcher.match(uri);
int rowsUpdated;
switch (match) {
case BOOK:
rowsUpdated = db.update(AlexandriaContract.BookEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
case AUTHOR:
rowsUpdated = db.update(AlexandriaContract.AuthorEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
case CATEGORY:
rowsUpdated = db.update(AlexandriaContract.CategoryEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (rowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsUpdated;
}
}

View File

@@ -0,0 +1,58 @@
package it.jaschke.alexandria.data;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* Created by saj on 22/12/14.
*/
public class DbHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "alexandria.db";
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
final String SQL_CREATE_BOOK_TABLE = "CREATE TABLE " + AlexandriaContract.BookEntry.TABLE_NAME + " ("+
AlexandriaContract.BookEntry._ID + " INTEGER PRIMARY KEY," +
AlexandriaContract.BookEntry.TITLE + " TEXT NOT NULL," +
AlexandriaContract.BookEntry.SUBTITLE + " TEXT ," +
AlexandriaContract.BookEntry.DESC + " TEXT ," +
AlexandriaContract.BookEntry.IMAGE_URL + " TEXT, " +
"UNIQUE ("+ AlexandriaContract.BookEntry._ID +") ON CONFLICT IGNORE)";
final String SQL_CREATE_AUTHOR_TABLE = "CREATE TABLE " + AlexandriaContract.AuthorEntry.TABLE_NAME + " ("+
AlexandriaContract.AuthorEntry._ID + " INTEGER," +
AlexandriaContract.AuthorEntry.AUTHOR + " TEXT," +
" FOREIGN KEY (" + AlexandriaContract.AuthorEntry._ID + ") REFERENCES " +
AlexandriaContract.BookEntry.TABLE_NAME + " (" + AlexandriaContract.BookEntry._ID + "))";
final String SQL_CREATE_CATEGORY_TABLE = "CREATE TABLE " + AlexandriaContract.CategoryEntry.TABLE_NAME + " ("+
AlexandriaContract.CategoryEntry._ID + " INTEGER," +
AlexandriaContract.CategoryEntry.CATEGORY + " TEXT," +
" FOREIGN KEY (" + AlexandriaContract.CategoryEntry._ID + ") REFERENCES " +
AlexandriaContract.BookEntry.TABLE_NAME + " (" + AlexandriaContract.BookEntry._ID + "))";
Log.d("sql-statments",SQL_CREATE_BOOK_TABLE);
Log.d("sql-statments",SQL_CREATE_AUTHOR_TABLE);
Log.d("sql-statments",SQL_CREATE_CATEGORY_TABLE);
db.execSQL(SQL_CREATE_BOOK_TABLE);
db.execSQL(SQL_CREATE_AUTHOR_TABLE);
db.execSQL(SQL_CREATE_CATEGORY_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

View File

@@ -0,0 +1,233 @@
package it.jaschke.alexandria.services;
import android.app.IntentService;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import it.jaschke.alexandria.MainActivity;
import it.jaschke.alexandria.R;
import it.jaschke.alexandria.data.AlexandriaContract;
/**
* An {@link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p/>
*/
public class BookService extends IntentService {
private final String LOG_TAG = BookService.class.getSimpleName();
public static final String FETCH_BOOK = "it.jaschke.alexandria.services.action.FETCH_BOOK";
public static final String DELETE_BOOK = "it.jaschke.alexandria.services.action.DELETE_BOOK";
public static final String EAN = "it.jaschke.alexandria.services.extra.EAN";
public BookService() {
super("Alexandria");
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (FETCH_BOOK.equals(action)) {
final String ean = intent.getStringExtra(EAN);
fetchBook(ean);
} else if (DELETE_BOOK.equals(action)) {
final String ean = intent.getStringExtra(EAN);
deleteBook(ean);
}
}
}
/**
* Handle action Foo in the provided background thread with the provided
* parameters.
*/
private void deleteBook(String ean) {
if(ean!=null) {
getContentResolver().delete(AlexandriaContract.BookEntry.buildBookUri(Long.parseLong(ean)), null, null);
}
}
/**
* Handle action fetchBook in the provided background thread with the provided
* parameters.
*/
private void fetchBook(String ean) {
if(ean.length()!=13){
return;
}
Cursor bookEntry = getContentResolver().query(
AlexandriaContract.BookEntry.buildBookUri(Long.parseLong(ean)),
null, // leaving "columns" null just returns all the columns.
null, // cols for "where" clause
null, // values for "where" clause
null // sort order
);
if(bookEntry.getCount()>0){
bookEntry.close();
return;
}
bookEntry.close();
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String bookJsonString = null;
try {
final String FORECAST_BASE_URL = "https://www.googleapis.com/books/v1/volumes?";
final String QUERY_PARAM = "q";
final String ISBN_PARAM = "isbn:" + ean;
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, ISBN_PARAM)
.build();
URL url = new URL(builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
return;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
buffer.append("\n");
}
if (buffer.length() == 0) {
return;
}
bookJsonString = buffer.toString();
} catch (Exception e) {
Log.e(LOG_TAG, "Error ", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
final String ITEMS = "items";
final String VOLUME_INFO = "volumeInfo";
final String TITLE = "title";
final String SUBTITLE = "subtitle";
final String AUTHORS = "authors";
final String DESC = "description";
final String CATEGORIES = "categories";
final String IMG_URL_PATH = "imageLinks";
final String IMG_URL = "thumbnail";
try {
JSONObject bookJson = new JSONObject(bookJsonString);
JSONArray bookArray;
if(bookJson.has(ITEMS)){
bookArray = bookJson.getJSONArray(ITEMS);
}else{
Intent messageIntent = new Intent(MainActivity.MESSAGE_EVENT);
messageIntent.putExtra(MainActivity.MESSAGE_KEY,getResources().getString(R.string.not_found));
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(messageIntent);
return;
}
JSONObject bookInfo = ((JSONObject) bookArray.get(0)).getJSONObject(VOLUME_INFO);
String title = bookInfo.getString(TITLE);
String subtitle = "";
if(bookInfo.has(SUBTITLE)) {
subtitle = bookInfo.getString(SUBTITLE);
}
String desc="";
if(bookInfo.has(DESC)){
desc = bookInfo.getString(DESC);
}
String imgUrl = "";
if(bookInfo.has(IMG_URL_PATH) && bookInfo.getJSONObject(IMG_URL_PATH).has(IMG_URL)) {
imgUrl = bookInfo.getJSONObject(IMG_URL_PATH).getString(IMG_URL);
}
writeBackBook(ean, title, subtitle, desc, imgUrl);
if(bookInfo.has(AUTHORS)) {
writeBackAuthors(ean, bookInfo.getJSONArray(AUTHORS));
}
if(bookInfo.has(CATEGORIES)){
writeBackCategories(ean,bookInfo.getJSONArray(CATEGORIES) );
}
} catch (JSONException | NullPointerException e) {
Log.e(LOG_TAG, "Error ", e);
}
}
private void writeBackBook(String ean, String title, String subtitle, String desc, String imgUrl) {
ContentValues values= new ContentValues();
values.put(AlexandriaContract.BookEntry._ID, ean);
values.put(AlexandriaContract.BookEntry.TITLE, title);
values.put(AlexandriaContract.BookEntry.IMAGE_URL, imgUrl);
values.put(AlexandriaContract.BookEntry.SUBTITLE, subtitle);
values.put(AlexandriaContract.BookEntry.DESC, desc);
getContentResolver().insert(AlexandriaContract.BookEntry.CONTENT_URI,values);
}
private void writeBackAuthors(String ean, JSONArray jsonArray) throws JSONException {
ContentValues values= new ContentValues();
for (int i = 0; i < jsonArray.length(); i++) {
values.put(AlexandriaContract.AuthorEntry._ID, ean);
values.put(AlexandriaContract.AuthorEntry.AUTHOR, jsonArray.getString(i));
getContentResolver().insert(AlexandriaContract.AuthorEntry.CONTENT_URI, values);
values= new ContentValues();
}
}
private void writeBackCategories(String ean, JSONArray jsonArray) throws JSONException {
ContentValues values= new ContentValues();
for (int i = 0; i < jsonArray.length(); i++) {
values.put(AlexandriaContract.CategoryEntry._ID, ean);
values.put(AlexandriaContract.CategoryEntry.CATEGORY, jsonArray.getString(i));
getContentResolver().insert(AlexandriaContract.CategoryEntry.CONTENT_URI, values);
values= new ContentValues();
}
}
}

View File

@@ -0,0 +1,38 @@
package it.jaschke.alexandria.services;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;
import java.io.InputStream;
/**
* Created by saj on 11/01/15.
*/
public class DownloadImage extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImage(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urlDisplay = urls[0];
Bitmap bookCover = null;
try {
InputStream in = new java.net.URL(urlDisplay).openStream();
bookCover = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return bookCover;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,40 @@
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="horizontal"
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/right_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</LinearLayout>
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="@+id/navigation_drawer"
android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent"
android:layout_gravity="start" android:name="it.jaschke.alexandria.NavigationDrawerFragment"
tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>

View File

@@ -0,0 +1,131 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="it.jaschke.alexandria.AddBook">
<RelativeLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="left|center_vertical">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="number"
android:minEms="@integer/ean_width"
android:id="@+id/ean"
android:saveEnabled="true"
android:textIsSelectable="false"
android:maxLength="@integer/ean_size"
android:hint="@string/input_hint"
android:layout_marginLeft="40dp"
android:layout_marginStart="40dp"
android:maxLines="1"
android:layout_marginTop="30dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/scan_button"
android:id="@+id/scan_button"
android:layout_marginLeft="23dp"
android:layout_marginStart="23dp"
android:layout_alignBottom="@+id/ean"
android:layout_toRightOf="@+id/ean"
android:layout_toEndOf="@+id/ean"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bookTitle"
android:textSize="@dimen/head_line"
android:textIsSelectable="true"
android:textStyle="bold"
android:layout_below="@+id/scan_button"
android:layout_alignLeft="@+id/ean"
android:layout_alignStart="@+id/ean"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bookSubTitle"
android:layout_below="@+id/bookTitle"
android:layout_alignLeft="@+id/bookTitle"
android:layout_alignStart="@+id/bookTitle"
android:layout_marginTop="10dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bookCover"
android:contentDescription="@string/book_cover"
android:minHeight="20dip"
android:minWidth="20dip"
android:layout_below="@+id/bookSubTitle"
android:layout_alignLeft="@+id/bookSubTitle"
android:layout_alignStart="@+id/bookSubTitle"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/authors"
android:textSize="@dimen/small_fontsize"
android:layout_marginLeft="25dp"
android:layout_alignTop="@+id/bookCover"
android:layout_toRightOf="@+id/bookCover"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/categories"
android:textSize="@dimen/small_fontsize"
android:layout_below="@+id/bookCover"
android:layout_alignLeft="@+id/bookCover"
android:layout_alignStart="@+id/bookCover"
android:layout_marginTop="10dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:contentDescription="@string/cancel_button"
android:layout_weight="1"
android:src="@drawable/ic_action_discard"
style="?android:attr/buttonBarButtonStyle"
android:id="@+id/delete_button"
android:visibility="invisible"
/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:contentDescription="@string/ok_button"
android:text="@string/ok_button"
android:layout_weight="1"
android:id="@+id/save_button"
android:visibility="invisible"
android:src="@drawable/ic_action_accept"
style="?android:attr/buttonBarButtonStyle"
android:layout_gravity="bottom"
/>
</LinearLayout>
</RelativeLayout>
</FrameLayout>

View File

@@ -0,0 +1,24 @@
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout android:id="@+id/container" android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="@+id/navigation_drawer"
android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent"
android:layout_gravity="start" android:name="it.jaschke.alexandria.NavigationDrawerFragment"
tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>

View File

@@ -0,0 +1,24 @@
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout android:id="@+id/container" android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead. -->
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment android:id="@+id/navigation_drawer"
android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent"
android:layout_gravity="start" android:name="it.jaschke.alexandria.NavigationDrawerFragment"
tools:layout="@layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip" >
<ImageView
android:id="@+id/fullBookCover"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_marginRight="6dip"
android:contentDescription="@string/book_cover"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/listBookTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignWithParentIfMissing="true"
android:layout_toRightOf="@id/fullBookCover"
android:gravity="center_vertical"
android:ellipsize="end"
android:layout_marginRight="10dp"
android:maxLines="1"
android:textSize="16sp" />
<TextView
android:id="@+id/listBookSubTitle"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:singleLine="true"
android:textSize="12sp"
android:ellipsize="end"
android:maxLines="1"
android:layout_marginRight="10dp"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/fullBookCover"
android:layout_toEndOf="@+id/fullBookCover"/>
</RelativeLayout>

View File

@@ -0,0 +1,34 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:clipToPadding="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context="it.jaschke.alexandria.About">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/app_name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:text="@string/about_text" />
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,129 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="it.jaschke.alexandria.AddBook">
<RelativeLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal|top">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:id="@+id/eancontainer"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="number"
android:minEms="@integer/ean_width"
android:id="@+id/ean"
android:saveEnabled="true"
android:maxLength="@integer/ean_size"
android:maxLines="1"
android:hint="@string/input_hint"
android:paddingRight="20dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/scan_button"
android:id="@+id/scan_button"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bookTitle"
android:textSize="@dimen/head_line"
android:textIsSelectable="true"
android:textStyle="bold"
android:layout_marginTop="25dp"
android:paddingRight="20dp"
android:layout_below="@+id/eancontainer"
android:layout_alignLeft="@+id/eancontainer"
android:layout_alignStart="@+id/eancontainer"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bookSubTitle"
android:layout_marginTop="10dp"
android:layout_below="@+id/bookTitle"
android:maxLines="3"
android:ellipsize="end"
android:layout_alignLeft="@+id/eancontainer"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/authors"
android:gravity="end"
android:textSize="@dimen/small_fontsize"
android:layout_marginTop="20dp"
android:layout_below="@+id/bookSubTitle"
android:layout_alignRight="@+id/eancontainer"
android:layout_alignEnd="@+id/eancontainer"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bookCover"
android:contentDescription="@string/book_cover"
android:layout_alignTop="@+id/authors"
android:layout_alignLeft="@+id/eancontainer"
android:layout_alignStart="@+id/eancontainer"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/categories"
android:textSize="@dimen/small_fontsize"
android:layout_below="@+id/bookCover"
android:layout_marginTop="20dp"
android:layout_alignLeft="@+id/eancontainer"
android:layout_alignStart="@+id/eancontainer"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<Button
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="@string/cancel_button"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:id="@+id/delete_button"
android:drawableLeft="@drawable/ic_action_discard"
android:visibility="invisible"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="@string/ok_button"
android:visibility="invisible"
android:layout_weight="1"
android:id="@+id/save_button"
android:drawableLeft="@drawable/ic_action_accept"
style="?android:attr/buttonBarButtonStyle"
android:layout_gravity="bottom"
/>
</LinearLayout>
</RelativeLayout>
</FrameLayout>

View File

@@ -0,0 +1,130 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="it.jaschke.alexandria.AddBook">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ScrollView android:layout_width="fill_parent"
android:layout_height="0dp"
android:fillViewport="false"
android:layout_weight="1">
<RelativeLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/fullBookTitle"
android:textSize="@dimen/head_line"
android:textIsSelectable="true"
android:textStyle="bold"
android:paddingRight="20dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_margin="10dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fullBookCover"
android:contentDescription="@string/book_cover"
android:layout_marginTop="15dp"
android:layout_below="@+id/fullBookTitle"
android:layout_alignLeft="@+id/fullBookTitle"
android:layout_alignStart="@+id/fullBookTitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fullBookSubTitle"
android:maxLines="5"
android:ellipsize="end"
android:textSize="18sp"
android:layout_marginLeft="20dp"
android:layout_marginRight="10dp"
android:layout_alignTop="@+id/fullBookCover"
android:layout_toRightOf="@+id/fullBookCover"
android:layout_toEndOf="@+id/fullBookCover"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/fullBookDesc"
android:ellipsize="end"
android:layout_marginLeft="10dp"
android:layout_below="@+id/fullBookCover"
android:layout_margin="10dp"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/fullBookDesc"
android:layout_marginTop="10dp"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/categories"
android:layout_weight="1"
android:gravity="left|top"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/authors"
android:layout_weight="1"
android:textStyle="bold"
android:gravity="right|top"/>
</LinearLayout>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/back_button"
android:id="@+id/backButton"
android:onClick="goBack"
android:src="@drawable/ic_action_undo"
style="?android:attr/buttonBarButtonStyle"
android:layout_gravity="right|top"
android:layout_alignParentTop="true"
android:layout_alignRight="@+id/fullBookTitle"
android:layout_alignEnd="@+id/fullBookTitle"/>
</RelativeLayout>
</ScrollView>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/delete"
style="?android:attr/buttonBarButtonStyle"
android:id="@+id/delete_button"
android:drawableLeft="@drawable/ic_action_discard"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,52 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="it.jaschke.alexandria.ListOfBooks">
<RelativeLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal|top">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/searchButton"
android:src="@drawable/ic_action_search"
android:contentDescription="@string/search"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
style="?android:attr/buttonBarButtonStyle"
android:layout_marginTop="5dp"
android:layout_alignParentEnd="true"/>
<EditText
android:layout_width = "fill_parent"
android:layout_height="wrap_content"
android:id="@+id/searchText"
android:inputType="text"
android:saveEnabled="true"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal"
android:layout_toLeftOf="@+id/searchButton"
android:layout_toStartOf="@+id/searchButton"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"/>
<ListView android:id="@+id/listOfBooks"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_below="@+id/searchText"
android:layout_alignRight="@id/searchButton"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_toRightOf="@id/searchButton"/>
</RelativeLayout>
</FrameLayout>

View File

@@ -0,0 +1,5 @@
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:choiceMode="singleChoice"
android:divider="@android:color/transparent" android:dividerHeight="0dp"
android:background="#cccc" tools:context=".NavigationDrawerFragment" />

View File

@@ -0,0 +1,9 @@
<menu 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" tools:context=".MainActivity">
<item android:id="@+id/action_share"
android:title="@string/action_share"
app:showAsAction="always"
app:actionProviderClass="android.support.v7.widget.ShareActionProvider" />
</menu>

View File

@@ -0,0 +1,8 @@
<menu 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" tools:context=".MainActivity">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
app:showAsAction="never"
/>
</menu>

View File

@@ -0,0 +1,5 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
</resources>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="pref_start_options">
<item>@string/books</item>
<item>@string/scan</item>
</string-array>
<string-array name="pref_start_values">
<item>0</item>
<item>1</item>
</string-array>
</resources>

View File

@@ -0,0 +1,11 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<integer name="ean_size">13</integer>
<integer name="ean_width">8</integer>
<dimen name="head_line">24sp</dimen>
<dimen name="small_fontsize">12sp</dimen>
<!-- Per the design guidelines, navigation drawers should be between 240dp and 320dp:
https://developer.android.com/design/patterns/navigation-drawer.html -->
<dimen name="navigation_drawer_width">240dp</dimen>
</resources>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Alexandria</string>
<!-- Menu Items -->
<string name="books">List of Books</string>
<string name="scan">Scan/Add a Book</string>
<string name="about">About this App</string>
<string name="navigation_drawer_open" >Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="action_settings">Settings</string>
<string name="scan_button">Scan</string>
<string name="input_hint">Insert ISBN-13. Digits only.</string>
<string name="book_cover">Bookcover</string>
<string name="ok_button">Next</string>
<string name="cancel_button">Cancel</string>
<string name="not_found">No Book found</string>
<string name="search">Search</string>
<string name="delete">Delete Book</string>
<string name="pref_startScreen">Select Startscreen</string>
<string name="title_activity_settings">Settings</string>
<string name="action_share">Share</string>
<string name="back_button">go back</string>
<string name="share_text">"A must read book: "</string>
<string name="about_text">This application gets book information from a Google API. All titles, cover images, and author information come from there.\n\n
The original version of this app was built by Sascha Jaschke, and a modified version is given to students in the Udacity Android Nanodegree program.\n\nBug fixes and Extras by Daniel Bauer\n\nBarcode Scanner by Dushyanth Maguluru (https://github.com/dm77/barcodescanner)</string>
</resources>

View File

@@ -0,0 +1,8 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:tag="PREFERENCE_TAG"
>
<ListPreference
android:key="pref_startFragment"
android:title="@string/pref_startScreen"
android:entries="@array/pref_start_options"
android:entryValues="@array/pref_start_values"
/>
</PreferenceScreen>