initial
8
alexandria/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea
|
||||
.DS_Store
|
||||
/build
|
||||
*.iml
|
||||
*.apk
|
||||
5
alexandria/CHANGELOG.md
Normal file
@@ -0,0 +1,5 @@
|
||||
* Added barcode scanner
|
||||
* Fixed NPE if the device is offline
|
||||
* Fixed missing whitespace in share_text string
|
||||
* Changed about fragment appearance
|
||||
* Fixed NPE when rotating device in BookDetail fragment by retaining it
|
||||
2
alexandria/app/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
*.iml
|
||||
42
alexandria/app/build.gradle
Normal file
@@ -0,0 +1,42 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 21
|
||||
buildToolsVersion "21.1.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "it.jaschke.alexandria"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 21
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
jacoco {
|
||||
version = '0.6.2.201302030002'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
testCoverageEnabled = true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug{
|
||||
testCoverageEnabled = true
|
||||
}
|
||||
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:appcompat-v7:21.0.3'
|
||||
compile 'me.dm7.barcodescanner:zxing:1.8.3'
|
||||
|
||||
}
|
||||
87
alexandria/app/manifest-merger-release-report.txt
Normal file
@@ -0,0 +1,87 @@
|
||||
-- Merging decision tree log ---
|
||||
manifest
|
||||
ADDED from AndroidManifest.xml:2:1
|
||||
xmlns:android
|
||||
ADDED from AndroidManifest.xml:2:11
|
||||
package
|
||||
ADDED from AndroidManifest.xml:3:5
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
android:versionName
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
android:versionCode
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
uses-permission#android.permission.INTERNET
|
||||
ADDED from AndroidManifest.xml:5:5
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:5:22
|
||||
application
|
||||
ADDED from AndroidManifest.xml:7:5
|
||||
MERGED from com.android.support:appcompat-v7:21.0.3:16:5
|
||||
MERGED from com.android.support:support-v4:21.0.3:16:5
|
||||
android:label
|
||||
ADDED from AndroidManifest.xml:10:9
|
||||
android:allowBackup
|
||||
ADDED from AndroidManifest.xml:8:9
|
||||
android:icon
|
||||
ADDED from AndroidManifest.xml:9:9
|
||||
android:theme
|
||||
ADDED from AndroidManifest.xml:11:9
|
||||
activity#it.jaschke.alexandria.MainActivity
|
||||
ADDED from AndroidManifest.xml:12:9
|
||||
android:label
|
||||
ADDED from AndroidManifest.xml:15:13
|
||||
android:configChanges
|
||||
ADDED from AndroidManifest.xml:14:13
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:13:13
|
||||
intent-filter#android.intent.action.MAIN+android.intent.category.LAUNCHER
|
||||
ADDED from AndroidManifest.xml:16:13
|
||||
action#android.intent.action.MAIN
|
||||
ADDED from AndroidManifest.xml:17:17
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:17:25
|
||||
category#android.intent.category.LAUNCHER
|
||||
ADDED from AndroidManifest.xml:18:17
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:18:27
|
||||
activity#it.jaschke.alexandria.SettingsActivity
|
||||
ADDED from AndroidManifest.xml:21:9
|
||||
android:label
|
||||
ADDED from AndroidManifest.xml:22:13
|
||||
android:parentActivityName
|
||||
ADDED from AndroidManifest.xml:24:13
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:23:13
|
||||
meta-data#android.support.PARENT_ACTIVITY
|
||||
ADDED from AndroidManifest.xml:25:13
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:26:17
|
||||
android:value
|
||||
ADDED from AndroidManifest.xml:27:17
|
||||
provider#it.jaschke.alexandria.data.BookProvider
|
||||
ADDED from AndroidManifest.xml:30:9
|
||||
android:exported
|
||||
ADDED from AndroidManifest.xml:33:13
|
||||
android:authorities
|
||||
ADDED from AndroidManifest.xml:32:13
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:31:13
|
||||
service#it.jaschke.alexandria.services.BookService
|
||||
ADDED from AndroidManifest.xml:34:9
|
||||
android:exported
|
||||
ADDED from AndroidManifest.xml:36:13
|
||||
android:name
|
||||
ADDED from AndroidManifest.xml:35:13
|
||||
uses-sdk
|
||||
INJECTED from AndroidManifest.xml:0:0 reason: use-sdk injection requested
|
||||
MERGED from com.android.support:appcompat-v7:21.0.3:15:5
|
||||
MERGED from com.android.support:support-v4:21.0.3:15:5
|
||||
android:targetSdkVersion
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
android:minSdkVersion
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
INJECTED from AndroidManifest.xml:0:0
|
||||
17
alexandria/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/saj/AndroidSDK/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
47
alexandria/app/src/main/AndroidManifest.xml
Normal 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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
208
alexandria/app/src/main/java/it/jaschke/alexandria/AddBook.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package it.jaschke.alexandria.api;
|
||||
|
||||
/**
|
||||
* Created by saj on 25/01/15.
|
||||
*/
|
||||
public interface Callback {
|
||||
void onItemSelected(String ean);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
BIN
alexandria/app/src/main/res/drawable-hdpi/drawer_shadow.9.png
Normal file
|
After Width: | Height: | Size: 161 B |
BIN
alexandria/app/src/main/res/drawable-hdpi/ic_action_accept.png
Normal file
|
After Width: | Height: | Size: 404 B |
BIN
alexandria/app/src/main/res/drawable-hdpi/ic_action_discard.png
Normal file
|
After Width: | Height: | Size: 454 B |
BIN
alexandria/app/src/main/res/drawable-hdpi/ic_action_search.png
Normal file
|
After Width: | Height: | Size: 702 B |
BIN
alexandria/app/src/main/res/drawable-hdpi/ic_action_undo.png
Normal file
|
After Width: | Height: | Size: 564 B |
BIN
alexandria/app/src/main/res/drawable-hdpi/ic_drawer.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
alexandria/app/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
alexandria/app/src/main/res/drawable-mdpi/drawer_shadow.9.png
Normal file
|
After Width: | Height: | Size: 142 B |
BIN
alexandria/app/src/main/res/drawable-mdpi/ic_action_accept.png
Normal file
|
After Width: | Height: | Size: 271 B |
BIN
alexandria/app/src/main/res/drawable-mdpi/ic_action_discard.png
Normal file
|
After Width: | Height: | Size: 333 B |
BIN
alexandria/app/src/main/res/drawable-mdpi/ic_action_search.png
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
alexandria/app/src/main/res/drawable-mdpi/ic_action_undo.png
Normal file
|
After Width: | Height: | Size: 452 B |
BIN
alexandria/app/src/main/res/drawable-mdpi/ic_drawer.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
alexandria/app/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
alexandria/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png
Normal file
|
After Width: | Height: | Size: 174 B |
BIN
alexandria/app/src/main/res/drawable-xhdpi/ic_action_accept.png
Normal file
|
After Width: | Height: | Size: 489 B |
BIN
alexandria/app/src/main/res/drawable-xhdpi/ic_action_discard.png
Normal file
|
After Width: | Height: | Size: 552 B |
BIN
alexandria/app/src/main/res/drawable-xhdpi/ic_action_search.png
Normal file
|
After Width: | Height: | Size: 900 B |
BIN
alexandria/app/src/main/res/drawable-xhdpi/ic_action_undo.png
Normal file
|
After Width: | Height: | Size: 684 B |
BIN
alexandria/app/src/main/res/drawable-xhdpi/ic_drawer.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
alexandria/app/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
alexandria/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png
Normal file
|
After Width: | Height: | Size: 208 B |
BIN
alexandria/app/src/main/res/drawable-xxhdpi/ic_action_accept.png
Normal file
|
After Width: | Height: | Size: 635 B |
|
After Width: | Height: | Size: 781 B |
BIN
alexandria/app/src/main/res/drawable-xxhdpi/ic_action_search.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
alexandria/app/src/main/res/drawable-xxhdpi/ic_action_undo.png
Normal file
|
After Width: | Height: | Size: 994 B |
BIN
alexandria/app/src/main/res/drawable-xxhdpi/ic_drawer.png
Normal file
|
After Width: | Height: | Size: 202 B |
BIN
alexandria/app/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
alexandria/app/src/main/res/drawable-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
@@ -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>
|
||||
131
alexandria/app/src/main/res/layout-land/fragment_add_book.xml
Normal 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>
|
||||
24
alexandria/app/src/main/res/layout/activity_main.xml
Normal 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>
|
||||
24
alexandria/app/src/main/res/layout/activity_main_tablet.xml
Normal 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>
|
||||
46
alexandria/app/src/main/res/layout/book_list_item.xml
Normal 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>
|
||||
34
alexandria/app/src/main/res/layout/fragment_about.xml
Normal 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>
|
||||
129
alexandria/app/src/main/res/layout/fragment_add_book.xml
Normal 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>
|
||||
130
alexandria/app/src/main/res/layout/fragment_full_book.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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" />
|
||||
9
alexandria/app/src/main/res/menu/book_detail.xml
Normal 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>
|
||||
8
alexandria/app/src/main/res/menu/main.xml
Normal 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>
|
||||
5
alexandria/app/src/main/res/values-w820dp/dimens.xml
Normal 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>
|
||||
12
alexandria/app/src/main/res/values/arrays.xml
Normal 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>
|
||||
11
alexandria/app/src/main/res/values/dimens.xml
Normal 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>
|
||||
30
alexandria/app/src/main/res/values/strings.xml
Normal 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>
|
||||
8
alexandria/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
16
alexandria/app/src/main/res/xml/preferences.xml
Normal 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>
|
||||
19
alexandria/build.gradle
Normal file
@@ -0,0 +1,19 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.0.+'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
18
alexandria/gradle.properties
Normal file
@@ -0,0 +1,18 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
BIN
alexandria/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
alexandria/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Sat Nov 29 13:59:53 CET 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
||||
164
alexandria/gradlew
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
alexandria/gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
1
alexandria/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
include ':app'
|
||||