diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b13e074..0000000 --- a/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -bin -gen -*.iml -**/build -.gradle diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 3fdc6a1..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 17 - buildToolsVersion "21.1.2" - - defaultConfig { - applicationId "com.example.providerexample" - minSdkVersion 14 - targetSdkVersion 17 - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - } - } -} - -dependencies { - compile 'com.android.support:support-v4:18.0.0' -} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml deleted file mode 100644 index 00f8b40..0000000 --- a/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/example/providerexample/PersonDetailActivity.java b/app/src/main/java/com/example/providerexample/PersonDetailActivity.java deleted file mode 100644 index 36450bb..0000000 --- a/app/src/main/java/com/example/providerexample/PersonDetailActivity.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.example.providerexample; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.NavUtils; -import android.view.MenuItem; - -/** - * An activity representing a single Person detail screen. This - * activity is only used on handset devices. On tablet-size devices, - * item details are presented side-by-side with a list of items - * in a {@link PersonListActivity}. - *

- * This activity is mostly just a 'shell' activity containing nothing - * more than a {@link PersonDetailFragment}. - */ -public class PersonDetailActivity extends FragmentActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_person_detail); - - // Show the Up button in the action bar. - getActionBar().setDisplayHomeAsUpEnabled(true); - - // savedInstanceState is non-null when there is fragment state - // saved from previous configurations of this activity - // (e.g. when rotating the screen from portrait to landscape). - // In this case, the fragment will automatically be re-added - // to its container so we don't need to manually add it. - // For more information, see the Fragments API guide at: - // - // http://developer.android.com/guide/components/fragments.html - // - if (savedInstanceState == null) { - // Create the detail fragment and add it to the activity - // using a fragment transaction. - Bundle arguments = new Bundle(); - arguments.putLong(PersonDetailFragment.ARG_ITEM_ID, - getIntent().getLongExtra(PersonDetailFragment.ARG_ITEM_ID, -1)); - PersonDetailFragment fragment = new PersonDetailFragment(); - fragment.setArguments(arguments); - getSupportFragmentManager().beginTransaction() - .add(R.id.person_detail_container, fragment) - .commit(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // This ID represents the Home or Up button. In the case of this - // activity, the Up button is shown. Use NavUtils to allow users - // to navigate up one level in the application structure. For - // more details, see the Navigation pattern on Android Design: - // - // http://developer.android.com/design/patterns/navigation.html#up-vs-back - // - NavUtils.navigateUpTo(this, new Intent(this, PersonListActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } -} diff --git a/app/src/main/java/com/example/providerexample/PersonDetailFragment.java b/app/src/main/java/com/example/providerexample/PersonDetailFragment.java deleted file mode 100644 index 0983be4..0000000 --- a/app/src/main/java/com/example/providerexample/PersonDetailFragment.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.example.providerexample; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.example.providerexample.database.DatabaseHandler; -import com.example.providerexample.database.Person; - -/** - * A fragment representing a single Person detail screen. - * This fragment is either contained in a {@link PersonListActivity} - * in two-pane mode (on tablets) or a {@link PersonDetailActivity} - * on handsets. - */ -public class PersonDetailFragment extends Fragment { - /** - * The fragment argument representing the item ID that this fragment - * represents. - */ - public static final String ARG_ITEM_ID = "item_id"; - - /** - * The person this fragment is presenting. - */ - private Person mItem; - - /** - * The UI elements showing the details of the Person - */ - private TextView textFirstName; - private TextView textLastName; - private TextView textBio; - - /** - * Mandatory empty constructor for the fragment manager to instantiate the - * fragment (e.g. upon screen orientation changes). - */ - public PersonDetailFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (getArguments().containsKey(ARG_ITEM_ID)) { - // Should use the contentprovider here ideally - mItem = DatabaseHandler.getInstance(getActivity()).getPerson(getArguments().getLong(ARG_ITEM_ID)); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_person_detail, container, false); - - if (mItem != null) { - textFirstName = ((TextView) rootView.findViewById(R.id.textFirstName)); - textFirstName.setText(mItem.firstname); - - textLastName = ((TextView) rootView.findViewById(R.id.textLastName)); - textLastName.setText(mItem.lastname); - - textBio = ((TextView) rootView.findViewById(R.id.textBio)); - textBio.setText(mItem.bio); - } - - return rootView; - } - - @Override - public void onPause() { - super.onPause(); - updatePersonFromUI(); - } - - private void updatePersonFromUI() { - if (mItem != null) { - mItem.firstname = textFirstName.getText().toString(); - mItem.lastname = textLastName.getText().toString(); - mItem.bio = textBio.getText().toString(); - - DatabaseHandler.getInstance(getActivity()).putPerson(mItem); - } - } -} diff --git a/app/src/main/java/com/example/providerexample/PersonListActivity.java b/app/src/main/java/com/example/providerexample/PersonListActivity.java deleted file mode 100644 index 03474b0..0000000 --- a/app/src/main/java/com/example/providerexample/PersonListActivity.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.example.providerexample; - -import com.example.providerexample.database.DatabaseHandler; -import com.example.providerexample.database.Person; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; - -/** - * An activity representing a list of Persons. This activity has different - * presentations for handset and tablet-size devices. On handsets, the activity - * presents a list of items, which when touched, lead to a - * {@link PersonDetailActivity} representing item details. On tablets, the - * activity presents the list of items and item details side-by-side using two - * vertical panes. - *

- * The activity makes heavy use of fragments. The list of items is a - * {@link PersonListFragment} and the item details (if present) is a - * {@link PersonDetailFragment}. - *

- * This activity also implements the required - * {@link PersonListFragment.Callbacks} interface to listen for item selections. - */ -public class PersonListActivity extends FragmentActivity implements - PersonListFragment.Callbacks { - - /** - * Whether or not the activity is in two-pane mode, i.e. running on a tablet - * device. - */ - private boolean mTwoPane; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_person_list); - - if (findViewById(R.id.person_detail_container) != null) { - // The detail container view will be present only in the - // large-screen layouts (res/values-large and - // res/values-sw600dp). If this view is present, then the - // activity should be in two-pane mode. - mTwoPane = true; - - // In two-pane mode, list items should be given the - // 'activated' state when touched. - ((PersonListFragment) getSupportFragmentManager().findFragmentById( - R.id.person_list)).setActivateOnItemClick(true); - } - - // TODO: If exposing deep links into your app, handle intents here. - } - - /** - * Callback method from {@link PersonListFragment.Callbacks} indicating that - * the item with the given ID was selected. - */ - @Override - public void onItemSelected(long id) { - if (mTwoPane) { - // In two-pane mode, show the detail view in this activity by - // adding or replacing the detail fragment using a - // fragment transaction. - Bundle arguments = new Bundle(); - arguments.putLong(PersonDetailFragment.ARG_ITEM_ID, id); - PersonDetailFragment fragment = new PersonDetailFragment(); - fragment.setArguments(arguments); - getSupportFragmentManager().beginTransaction() - .replace(R.id.person_detail_container, fragment).commit(); - - } else { - // In single-pane mode, simply start the detail activity - // for the selected item ID. - Intent detailIntent = new Intent(this, PersonDetailActivity.class); - detailIntent.putExtra(PersonDetailFragment.ARG_ITEM_ID, id); - startActivity(detailIntent); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.list_activity, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - boolean result = false; - if (R.id.newPerson == item.getItemId()) { - result = true; - // Create a new person. - Person p = new Person(); - DatabaseHandler.getInstance(this).putPerson(p); - // Open a new fragment with the new id - onItemSelected(p.id); - } - - return result; - } -} diff --git a/app/src/main/java/com/example/providerexample/PersonListFragment.java b/app/src/main/java/com/example/providerexample/PersonListFragment.java deleted file mode 100644 index 8fcdf5f..0000000 --- a/app/src/main/java/com/example/providerexample/PersonListFragment.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.example.providerexample; - -import android.app.Activity; -import android.support.v4.app.ListFragment; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.widget.SimpleCursorAdapter; -import android.database.Cursor; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; - -import com.example.providerexample.database.Person; -import com.example.providerexample.database.PersonProvider; - -/** - * A list fragment representing a list of Persons. This fragment also supports - * tablet devices by allowing list items to be given an 'activated' state upon - * selection. This helps indicate which item is currently being viewed in a - * {@link PersonDetailFragment}. - *

- * Activities containing this fragment MUST implement the {@link Callbacks} - * interface. - */ -public class PersonListFragment extends ListFragment { - - /** - * The serialization (saved instance state) Bundle key representing the - * activated item position. Only used on tablets. - */ - private static final String STATE_ACTIVATED_POSITION = "activated_position"; - - /** - * The fragment's current callback object, which is notified of list item - * clicks. - */ - private Callbacks mCallbacks = sDummyCallbacks; - - /** - * The current activated item position. Only used on tablets. - */ - private int mActivatedPosition = ListView.INVALID_POSITION; - - /** - * A callback interface that all activities containing this fragment must - * implement. This mechanism allows activities to be notified of item - * selections. - */ - public interface Callbacks { - /** - * Callback for when an item has been selected. - */ - public void onItemSelected(long l); - } - - /** - * A dummy implementation of the {@link Callbacks} interface that does - * nothing. Used only when this fragment is not attached to an activity. - */ - private static Callbacks sDummyCallbacks = new Callbacks() { - @Override - public void onItemSelected(long id) { - } - }; - - /** - * Mandatory empty constructor for the fragment manager to instantiate the - * fragment (e.g. upon screen orientation changes). - */ - public PersonListFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setListAdapter(new SimpleCursorAdapter(getActivity(), - R.layout.person_listitem, null, new String[] { - Person.COL_FIRSTNAME, Person.COL_LASTNAME, - Person.COL_BIO }, new int[] { R.id.cardFirstName, - R.id.cardLastName, R.id.cardDescription }, 0)); - - // Load the content - getLoaderManager().initLoader(0, null, new LoaderCallbacks() { - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new CursorLoader(getActivity(), - PersonProvider.URI_PERSONS, Person.FIELDS, null, null, - null); - } - - @Override - public void onLoadFinished(Loader loader, Cursor c) { - ((SimpleCursorAdapter) getListAdapter()).swapCursor(c); - } - - @Override - public void onLoaderReset(Loader arg0) { - ((SimpleCursorAdapter) getListAdapter()).swapCursor(null); - } - }); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_person_list, null); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - // Restore the previously serialized activated item position. - if (savedInstanceState != null - && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { - setActivatedPosition(savedInstanceState - .getInt(STATE_ACTIVATED_POSITION)); - } - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - // Activities containing this fragment must implement its callbacks. - if (!(activity instanceof Callbacks)) { - throw new IllegalStateException( - "Activity must implement fragment's callbacks."); - } - - mCallbacks = (Callbacks) activity; - } - - @Override - public void onDetach() { - super.onDetach(); - - // Reset the active callbacks interface to the dummy implementation. - mCallbacks = sDummyCallbacks; - } - - @Override - public void onListItemClick(ListView listView, View view, int position, - long id) { - super.onListItemClick(listView, view, position, id); - - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - mCallbacks.onItemSelected(getListAdapter().getItemId(position)); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (mActivatedPosition != ListView.INVALID_POSITION) { - // Serialize and persist the activated item position. - outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); - } - } - - /** - * Turns on activate-on-click mode. When this mode is on, list items will be - * given the 'activated' state when touched. - */ - public void setActivateOnItemClick(boolean activateOnItemClick) { - // When setting CHOICE_MODE_SINGLE, ListView will automatically - // give items the 'activated' state when touched. - getListView().setChoiceMode( - activateOnItemClick ? ListView.CHOICE_MODE_SINGLE - : ListView.CHOICE_MODE_NONE); - } - - private void setActivatedPosition(int position) { - if (position == ListView.INVALID_POSITION) { - getListView().setItemChecked(mActivatedPosition, false); - } else { - getListView().setItemChecked(position, true); - } - - mActivatedPosition = position; - } -} diff --git a/app/src/main/java/com/example/providerexample/database/DatabaseHandler.java b/app/src/main/java/com/example/providerexample/database/DatabaseHandler.java deleted file mode 100644 index cf27cc2..0000000 --- a/app/src/main/java/com/example/providerexample/database/DatabaseHandler.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.example.providerexample.database; - -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; - -public class DatabaseHandler extends SQLiteOpenHelper { - - private static DatabaseHandler singleton; - - public static DatabaseHandler getInstance(final Context context) { - if (singleton == null) { - singleton = new DatabaseHandler(context); - } - return singleton; - } - - private static final int DATABASE_VERSION = 1; - private static final String DATABASE_NAME = "providerExample"; - - private final Context context; - - public DatabaseHandler(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - // Good idea to have the context that doesn't die with the window - this.context = context.getApplicationContext(); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(Person.CREATE_TABLE); - - Person person = new Person(); - person.firstname = "Sylvester"; - person.lastname = "Stallone"; - person.bio = "..."; - db.insert(Person.TABLE_NAME, null, person.getContent()); - - person.firstname = "Danny"; - person.lastname = "DeVito"; - person.bio = "..."; - db.insert(Person.TABLE_NAME, null, person.getContent()); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - } - - public synchronized Person getPerson(final long id) { - final SQLiteDatabase db = this.getReadableDatabase(); - final Cursor cursor = db.query(Person.TABLE_NAME, Person.FIELDS, - Person.COL_ID + " IS ?", new String[] { String.valueOf(id) }, - null, null, null, null); - if (cursor == null || cursor.isAfterLast()) { - return null; - } - - Person item = null; - if (cursor.moveToFirst()) { - item = new Person(cursor); - } - cursor.close(); - return item; - } - - public synchronized boolean putPerson(final Person person) { - boolean success = false; - int result = 0; - final SQLiteDatabase db = this.getWritableDatabase(); - - if (person.id > -1) { - result += db.update(Person.TABLE_NAME, person.getContent(), - Person.COL_ID + " IS ?", - new String[] { String.valueOf(person.id) }); - } - - if (result > 0) { - success = true; - } else { - // Update failed or wasn't possible, insert instead - final long id = db.insert(Person.TABLE_NAME, null, - person.getContent()); - - if (id > -1) { - person.id = id; - success = true; - } - } - - if (success) { - notifyProviderOnPersonChange(); - } - - return success; - } - - public synchronized int removePerson(final Person person) { - final SQLiteDatabase db = this.getWritableDatabase(); - final int result = db.delete(Person.TABLE_NAME, - Person.COL_ID + " IS ?", - new String[] { Long.toString(person.id) }); - - if (result > 0) { - notifyProviderOnPersonChange(); - } - return result; - } - - private void notifyProviderOnPersonChange() { - context.getContentResolver().notifyChange( - PersonProvider.URI_PERSONS, null, false); - } -} diff --git a/app/src/main/java/com/example/providerexample/database/Person.java b/app/src/main/java/com/example/providerexample/database/Person.java deleted file mode 100644 index 9b9511b..0000000 --- a/app/src/main/java/com/example/providerexample/database/Person.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.example.providerexample.database; - -import android.content.ContentValues; -import android.database.Cursor; - -/** - * A class representation of a row in table "Person". - */ -public class Person { - - // SQL convention says Table name should be "singular", so not Persons - public static final String TABLE_NAME = "Person"; - // Naming the id column with an underscore is good to be consistent - // with other Android things. This is ALWAYS needed - public static final String COL_ID = "_id"; - // These fields can be anything you want. - public static final String COL_FIRSTNAME = "firstname"; - public static final String COL_LASTNAME = "lastname"; - public static final String COL_BIO = "bio"; - - // For database projection so order is consistent - public static final String[] FIELDS = { COL_ID, COL_FIRSTNAME, COL_LASTNAME, - COL_BIO }; - - /* - * The SQL code that creates a Table for storing Persons in. - * Note that the last row does NOT end in a comma like the others. - * This is a common source of error. - */ - public static final String CREATE_TABLE = - "CREATE TABLE " + TABLE_NAME + "(" - + COL_ID + " INTEGER PRIMARY KEY," - + COL_FIRSTNAME + " TEXT NOT NULL DEFAULT ''," - + COL_LASTNAME + " TEXT NOT NULL DEFAULT ''," - + COL_BIO + " TEXT NOT NULL DEFAULT ''" - + ")"; - - // Fields corresponding to database columns - public long id = -1; - public String firstname = ""; - public String lastname = ""; - public String bio = ""; - - /** - * No need to do anything, fields are already set to default values above - */ - public Person() { - } - - /** - * Convert information from the database into a Person object. - */ - public Person(final Cursor cursor) { - // Indices expected to match order in FIELDS! - this.id = cursor.getLong(0); - this.firstname = cursor.getString(1); - this.lastname = cursor.getString(2); - this.bio = cursor.getString(3); - } - - /** - * Return the fields in a ContentValues object, suitable for insertion - * into the database. - */ - public ContentValues getContent() { - final ContentValues values = new ContentValues(); - // Note that ID is NOT included here - values.put(COL_FIRSTNAME, firstname); - values.put(COL_LASTNAME, lastname); - values.put(COL_BIO, bio); - - return values; - } -} diff --git a/app/src/main/java/com/example/providerexample/database/PersonProvider.java b/app/src/main/java/com/example/providerexample/database/PersonProvider.java deleted file mode 100644 index c046e4f..0000000 --- a/app/src/main/java/com/example/providerexample/database/PersonProvider.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.example.providerexample.database; - - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class PersonProvider extends ContentProvider { - - // All URIs share these parts - public static final String AUTHORITY = "com.example.providerexample.provider"; - public static final String SCHEME = "content://"; - - // URIs - // Used for all persons - public static final String PERSONS = SCHEME + AUTHORITY + "/person"; - public static final Uri URI_PERSONS = Uri.parse(PERSONS); - // Used for a single person, just add the id to the end - public static final String PERSON_BASE = PERSONS + "/"; - - public PersonProvider() { - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - // Implement this to handle requests to delete one or more rows. - throw new UnsupportedOperationException("Not yet implemented"); - } - - @Override - public String getType(Uri uri) { - // TODO: Implement this to handle requests for the MIME type of the data - // at the given URI. - throw new UnsupportedOperationException("Not yet implemented"); - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - // TODO: Implement this to handle requests to insert a new row. - throw new UnsupportedOperationException("Not yet implemented"); - } - - @Override - public boolean onCreate() { - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - Cursor result = null; - if (URI_PERSONS.equals(uri)) { - result = DatabaseHandler - .getInstance(getContext()) - .getReadableDatabase() - .query(Person.TABLE_NAME, Person.FIELDS, null, null, null, - null, null, null); - result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS); - } else if (uri.toString().startsWith(PERSON_BASE)) { - final long id = Long.parseLong(uri.getLastPathSegment()); - result = DatabaseHandler - .getInstance(getContext()) - .getReadableDatabase() - .query(Person.TABLE_NAME, Person.FIELDS, - Person.COL_ID + " IS ?", - new String[] { String.valueOf(id) }, null, null, - null, null); - result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS); - } else { - throw new UnsupportedOperationException("Not yet implemented"); - } - - return result; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - // TODO: Implement this to handle requests to update one or more rows. - throw new UnsupportedOperationException("Not yet implemented"); - } -} diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 2981225..0000000 Binary files a/app/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/ic_launcher.png b/app/src/main/res/drawable-ldpi/ic_launcher.png deleted file mode 100644 index 8eeade2..0000000 Binary files a/app/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index be5c15d..0000000 Binary files a/app/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index ef17472..0000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/drawable/rounded_corners_white.xml b/app/src/main/res/drawable/rounded_corners_white.xml deleted file mode 100644 index 05e99f4..0000000 --- a/app/src/main/res/drawable/rounded_corners_white.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_person_detail.xml b/app/src/main/res/layout/activity_person_detail.xml deleted file mode 100644 index 3b468f8..0000000 --- a/app/src/main/res/layout/activity_person_detail.xml +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/app/src/main/res/layout/activity_person_list.xml b/app/src/main/res/layout/activity_person_list.xml deleted file mode 100644 index 811c990..0000000 --- a/app/src/main/res/layout/activity_person_list.xml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/app/src/main/res/layout/activity_person_twopane.xml b/app/src/main/res/layout/activity_person_twopane.xml deleted file mode 100644 index a0e6d75..0000000 --- a/app/src/main/res/layout/activity_person_twopane.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_person_detail.xml b/app/src/main/res/layout/fragment_person_detail.xml deleted file mode 100644 index 1b1ada2..0000000 --- a/app/src/main/res/layout/fragment_person_detail.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_person_list.xml b/app/src/main/res/layout/fragment_person_list.xml deleted file mode 100644 index e231db1..0000000 --- a/app/src/main/res/layout/fragment_person_list.xml +++ /dev/null @@ -1,13 +0,0 @@ - - diff --git a/app/src/main/res/layout/person_listitem.xml b/app/src/main/res/layout/person_listitem.xml deleted file mode 100644 index 3c8fc2f..0000000 --- a/app/src/main/res/layout/person_listitem.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/list_activity.xml b/app/src/main/res/menu/list_activity.xml deleted file mode 100644 index e9c2f04..0000000 --- a/app/src/main/res/menu/list_activity.xml +++ /dev/null @@ -1,10 +0,0 @@ - -

- - - - \ No newline at end of file diff --git a/app/src/main/res/values-large/refs.xml b/app/src/main/res/values-large/refs.xml deleted file mode 100644 index 4661785..0000000 --- a/app/src/main/res/values-large/refs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - @layout/activity_person_twopane - - \ No newline at end of file diff --git a/app/src/main/res/values-sw600dp/refs.xml b/app/src/main/res/values-sw600dp/refs.xml deleted file mode 100644 index 4661785..0000000 --- a/app/src/main/res/values-sw600dp/refs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - @layout/activity_person_twopane - - \ No newline at end of file diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml deleted file mode 100644 index 541752f..0000000 --- a/app/src/main/res/values-v11/styles.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-v14/styles.xml b/app/src/main/res/values-v14/styles.xml deleted file mode 100644 index f20e015..0000000 --- a/app/src/main/res/values-v14/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml deleted file mode 100644 index 68b463d..0000000 --- a/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - ProviderExample - Person Detail - - \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml deleted file mode 100644 index 4a10ca4..0000000 --- a/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index c447727..0000000 --- a/build.gradle +++ /dev/null @@ -1,15 +0,0 @@ -// 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.1' - } -} - -allprojects { - repositories { - jcenter() - } -} diff --git a/readme_img/cardItem.png b/cardItem.png similarity index 100% rename from readme_img/cardItem.png rename to cardItem.png diff --git a/readme_img/changetolongarg.png b/changetolongarg.png similarity index 100% rename from readme_img/changetolongarg.png rename to changetolongarg.png diff --git a/fonts/OpenSans-Bold-webfont.eot b/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..e1c7674 Binary files /dev/null and b/fonts/OpenSans-Bold-webfont.eot differ diff --git a/fonts/OpenSans-Bold-webfont.svg b/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..364b368 --- /dev/null +++ b/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-Bold-webfont.ttf b/fonts/OpenSans-Bold-webfont.ttf new file mode 100644 index 0000000..2d94f06 Binary files /dev/null and b/fonts/OpenSans-Bold-webfont.ttf differ diff --git a/fonts/OpenSans-Bold-webfont.woff b/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..cd86852 Binary files /dev/null and b/fonts/OpenSans-Bold-webfont.woff differ diff --git a/fonts/OpenSans-BoldItalic-webfont.eot b/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..f44ac9a Binary files /dev/null and b/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/fonts/OpenSans-BoldItalic-webfont.svg b/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..8392240 --- /dev/null +++ b/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-BoldItalic-webfont.ttf b/fonts/OpenSans-BoldItalic-webfont.ttf new file mode 100644 index 0000000..f74e0e3 Binary files /dev/null and b/fonts/OpenSans-BoldItalic-webfont.ttf differ diff --git a/fonts/OpenSans-BoldItalic-webfont.woff b/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..f3248c1 Binary files /dev/null and b/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/fonts/OpenSans-Italic-webfont.eot b/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..277c189 Binary files /dev/null and b/fonts/OpenSans-Italic-webfont.eot differ diff --git a/fonts/OpenSans-Italic-webfont.svg b/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..29c7497 --- /dev/null +++ b/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-Italic-webfont.ttf b/fonts/OpenSans-Italic-webfont.ttf new file mode 100644 index 0000000..63f187e Binary files /dev/null and b/fonts/OpenSans-Italic-webfont.ttf differ diff --git a/fonts/OpenSans-Italic-webfont.woff b/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..469a29b Binary files /dev/null and b/fonts/OpenSans-Italic-webfont.woff differ diff --git a/fonts/OpenSans-Light-webfont.eot b/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..837daab Binary files /dev/null and b/fonts/OpenSans-Light-webfont.eot differ diff --git a/fonts/OpenSans-Light-webfont.svg b/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..bdb6726 --- /dev/null +++ b/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-Light-webfont.ttf b/fonts/OpenSans-Light-webfont.ttf new file mode 100644 index 0000000..b50ef9d Binary files /dev/null and b/fonts/OpenSans-Light-webfont.ttf differ diff --git a/fonts/OpenSans-Light-webfont.woff b/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..99514d1 Binary files /dev/null and b/fonts/OpenSans-Light-webfont.woff differ diff --git a/fonts/OpenSans-LightItalic-webfont.eot b/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..f0ebf2c Binary files /dev/null and b/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/fonts/OpenSans-LightItalic-webfont.svg b/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..60765da --- /dev/null +++ b/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-LightItalic-webfont.ttf b/fonts/OpenSans-LightItalic-webfont.ttf new file mode 100644 index 0000000..5898c8c Binary files /dev/null and b/fonts/OpenSans-LightItalic-webfont.ttf differ diff --git a/fonts/OpenSans-LightItalic-webfont.woff b/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..9c978dc Binary files /dev/null and b/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/fonts/OpenSans-Regular-webfont.eot b/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..dd6fd2c Binary files /dev/null and b/fonts/OpenSans-Regular-webfont.eot differ diff --git a/fonts/OpenSans-Regular-webfont.svg b/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..01038bb --- /dev/null +++ b/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-Regular-webfont.ttf b/fonts/OpenSans-Regular-webfont.ttf new file mode 100644 index 0000000..05951e7 Binary files /dev/null and b/fonts/OpenSans-Regular-webfont.ttf differ diff --git a/fonts/OpenSans-Regular-webfont.woff b/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..274664b Binary files /dev/null and b/fonts/OpenSans-Regular-webfont.woff differ diff --git a/fonts/OpenSans-Semibold-webfont.eot b/fonts/OpenSans-Semibold-webfont.eot new file mode 100644 index 0000000..289aade Binary files /dev/null and b/fonts/OpenSans-Semibold-webfont.eot differ diff --git a/fonts/OpenSans-Semibold-webfont.svg b/fonts/OpenSans-Semibold-webfont.svg new file mode 100644 index 0000000..cc2ca42 --- /dev/null +++ b/fonts/OpenSans-Semibold-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 2011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-Semibold-webfont.ttf b/fonts/OpenSans-Semibold-webfont.ttf new file mode 100644 index 0000000..6f15073 Binary files /dev/null and b/fonts/OpenSans-Semibold-webfont.ttf differ diff --git a/fonts/OpenSans-Semibold-webfont.woff b/fonts/OpenSans-Semibold-webfont.woff new file mode 100644 index 0000000..4e47cb1 Binary files /dev/null and b/fonts/OpenSans-Semibold-webfont.woff differ diff --git a/fonts/OpenSans-SemiboldItalic-webfont.eot b/fonts/OpenSans-SemiboldItalic-webfont.eot new file mode 100644 index 0000000..50a8a6f Binary files /dev/null and b/fonts/OpenSans-SemiboldItalic-webfont.eot differ diff --git a/fonts/OpenSans-SemiboldItalic-webfont.svg b/fonts/OpenSans-SemiboldItalic-webfont.svg new file mode 100644 index 0000000..65b50e2 --- /dev/null +++ b/fonts/OpenSans-SemiboldItalic-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/OpenSans-SemiboldItalic-webfont.ttf b/fonts/OpenSans-SemiboldItalic-webfont.ttf new file mode 100644 index 0000000..55ba312 Binary files /dev/null and b/fonts/OpenSans-SemiboldItalic-webfont.ttf differ diff --git a/fonts/OpenSans-SemiboldItalic-webfont.woff b/fonts/OpenSans-SemiboldItalic-webfont.woff new file mode 100644 index 0000000..0adc6df Binary files /dev/null and b/fonts/OpenSans-SemiboldItalic-webfont.woff differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 8c0fb64..0000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 0c71e76..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Wed Apr 10 15:27:10 PDT 2013 -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 diff --git a/gradlew b/gradlew deleted file mode 100755 index 91a7e26..0000000 --- a/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/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 "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 8a0b282..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@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 diff --git a/images/bullet.png b/images/bullet.png new file mode 100644 index 0000000..22ea543 Binary files /dev/null and b/images/bullet.png differ diff --git a/images/hr.gif b/images/hr.gif new file mode 100644 index 0000000..bdb4168 Binary files /dev/null and b/images/hr.gif differ diff --git a/images/nav-bg.gif b/images/nav-bg.gif new file mode 100644 index 0000000..4743965 Binary files /dev/null and b/images/nav-bg.gif differ diff --git a/javascripts/respond.js b/javascripts/respond.js new file mode 100644 index 0000000..76bc260 --- /dev/null +++ b/javascripts/respond.js @@ -0,0 +1,779 @@ +if(typeof Object.create!=="function"){ +Object.create=function(o){ +function F(){ +}; +F.prototype=o; +return new F(); +}; +} +var ua={toString:function(){ +return navigator.userAgent; +},test:function(s){ +return this.toString().toLowerCase().indexOf(s.toLowerCase())>-1; +}}; +ua.version=(ua.toString().toLowerCase().match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1]; +ua.webkit=ua.test("webkit"); +ua.gecko=ua.test("gecko")&&!ua.webkit; +ua.opera=ua.test("opera"); +ua.ie=ua.test("msie")&&!ua.opera; +ua.ie6=ua.ie&&document.compatMode&&typeof document.documentElement.style.maxHeight==="undefined"; +ua.ie7=ua.ie&&document.documentElement&&typeof document.documentElement.style.maxHeight!=="undefined"&&typeof XDomainRequest==="undefined"; +ua.ie8=ua.ie&&typeof XDomainRequest!=="undefined"; +var domReady=function(){ +var _1=[]; +var _2=function(){ +if(!arguments.callee.done){ +arguments.callee.done=true; +for(var i=0;i<_1.length;i++){ +_1[i](); +} +} +}; +if(document.addEventListener){ +document.addEventListener("DOMContentLoaded",_2,false); +} +if(ua.ie){ +(function(){ +try{ +document.documentElement.doScroll("left"); +} +catch(e){ +setTimeout(arguments.callee,50); +return; +} +_2(); +})(); +document.onreadystatechange=function(){ +if(document.readyState==="complete"){ +document.onreadystatechange=null; +_2(); +} +}; +} +if(ua.webkit&&document.readyState){ +(function(){ +if(document.readyState!=="loading"){ +_2(); +}else{ +setTimeout(arguments.callee,10); +} +})(); +} +window.onload=_2; +return function(fn){ +if(typeof fn==="function"){ +_1[_1.length]=fn; +} +return fn; +}; +}(); +var cssHelper=function(){ +var _3={BLOCKS:/[^\s{][^{]*\{(?:[^{}]*\{[^{}]*\}[^{}]*|[^{}]*)*\}/g,BLOCKS_INSIDE:/[^\s{][^{]*\{[^{}]*\}/g,DECLARATIONS:/[a-zA-Z\-]+[^;]*:[^;]+;/g,RELATIVE_URLS:/url\(['"]?([^\/\)'"][^:\)'"]+)['"]?\)/g,REDUNDANT_COMPONENTS:/(?:\/\*([^*\\\\]|\*(?!\/))+\*\/|@import[^;]+;)/g,REDUNDANT_WHITESPACE:/\s*(,|:|;|\{|\})\s*/g,MORE_WHITESPACE:/\s{2,}/g,FINAL_SEMICOLONS:/;\}/g,NOT_WHITESPACE:/\S+/g}; +var _4,_5=false; +var _6=[]; +var _7=function(fn){ +if(typeof fn==="function"){ +_6[_6.length]=fn; +} +}; +var _8=function(){ +for(var i=0;i<_6.length;i++){ +_6[i](_4); +} +}; +var _9={}; +var _a=function(n,v){ +if(_9[n]){ +var _b=_9[n].listeners; +if(_b){ +for(var i=0;i<_b.length;i++){ +_b[i](v); +} +} +} +}; +var _c=function(_d,_e,_f){ +if(ua.ie&&!window.XMLHttpRequest){ +window.XMLHttpRequest=function(){ +return new ActiveXObject("Microsoft.XMLHTTP"); +}; +} +if(!XMLHttpRequest){ +return ""; +} +var r=new XMLHttpRequest(); +try{ +r.open("get",_d,true); +r.setRequestHeader("X_REQUESTED_WITH","XMLHttpRequest"); +} +catch(e){ +_f(); +return; +} +var _10=false; +setTimeout(function(){ +_10=true; +},5000); +document.documentElement.style.cursor="progress"; +r.onreadystatechange=function(){ +if(r.readyState===4&&!_10){ +if(!r.status&&location.protocol==="file:"||(r.status>=200&&r.status<300)||r.status===304||navigator.userAgent.indexOf("Safari")>-1&&typeof r.status==="undefined"){ +_e(r.responseText); +}else{ +_f(); +} +document.documentElement.style.cursor=""; +r=null; +} +}; +r.send(""); +}; +var _11=function(_12){ +_12=_12.replace(_3.REDUNDANT_COMPONENTS,""); +_12=_12.replace(_3.REDUNDANT_WHITESPACE,"$1"); +_12=_12.replace(_3.MORE_WHITESPACE," "); +_12=_12.replace(_3.FINAL_SEMICOLONS,"}"); +return _12; +}; +var _13={mediaQueryList:function(s){ +var o={}; +var idx=s.indexOf("{"); +var lt=s.substring(0,idx); +s=s.substring(idx+1,s.length-1); +var mqs=[],rs=[]; +var qts=lt.toLowerCase().substring(7).split(","); +for(var i=0;i-1&&_23.href&&_23.href.length!==0&&!_23.disabled){ +_1f[_1f.length]=_23; +} +} +if(_1f.length>0){ +var c=0; +var _24=function(){ +c++; +if(c===_1f.length){ +_20(); +} +}; +var _25=function(_26){ +var _27=_26.href; +_c(_27,function(_28){ +_28=_11(_28).replace(_3.RELATIVE_URLS,"url("+_27.substring(0,_27.lastIndexOf("/"))+"/$1)"); +_26.cssHelperText=_28; +_24(); +},_24); +}; +for(i=0;i<_1f.length;i++){ +_25(_1f[i]); +} +}else{ +_20(); +} +}; +var _29={mediaQueryLists:"array",rules:"array",selectors:"object",declarations:"array",properties:"object"}; +var _2a={mediaQueryLists:null,rules:null,selectors:null,declarations:null,properties:null}; +var _2b=function(_2c,v){ +if(_2a[_2c]!==null){ +if(_29[_2c]==="array"){ +return (_2a[_2c]=_2a[_2c].concat(v)); +}else{ +var c=_2a[_2c]; +for(var n in v){ +if(v.hasOwnProperty(n)){ +if(!c[n]){ +c[n]=v[n]; +}else{ +c[n]=c[n].concat(v[n]); +} +} +} +return c; +} +} +}; +var _2d=function(_2e){ +_2a[_2e]=(_29[_2e]==="array")?[]:{}; +for(var i=0;i<_4.length;i++){ +_2b(_2e,_4[i].cssHelperParsed[_2e]); +} +return _2a[_2e]; +}; +domReady(function(){ +var els=document.body.getElementsByTagName("*"); +for(var i=0;i=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44)); +}else{ +return false; +} +}else{ +return _46>0; +} +}else{ +if("device-height"===_41.substring(l-13,l)){ +_47=screen.height; +if(_42!==null){ +if(_43==="length"){ +return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44)); +}else{ +return false; +} +}else{ +return _47>0; +} +}else{ +if("width"===_41.substring(l-5,l)){ +_46=document.documentElement.clientWidth||document.body.clientWidth; +if(_42!==null){ +if(_43==="length"){ +return ((min&&_46>=_44)||(max&&_46<_44)||(!min&&!max&&_46===_44)); +}else{ +return false; +} +}else{ +return _46>0; +} +}else{ +if("height"===_41.substring(l-6,l)){ +_47=document.documentElement.clientHeight||document.body.clientHeight; +if(_42!==null){ +if(_43==="length"){ +return ((min&&_47>=_44)||(max&&_47<_44)||(!min&&!max&&_47===_44)); +}else{ +return false; +} +}else{ +return _47>0; +} +}else{ +if("device-aspect-ratio"===_41.substring(l-19,l)){ +return _43==="aspect-ratio"&&screen.width*_44[1]===screen.height*_44[0]; +}else{ +if("color-index"===_41.substring(l-11,l)){ +var _48=Math.pow(2,screen.colorDepth); +if(_42!==null){ +if(_43==="absolute"){ +return ((min&&_48>=_44)||(max&&_48<_44)||(!min&&!max&&_48===_44)); +}else{ +return false; +} +}else{ +return _48>0; +} +}else{ +if("color"===_41.substring(l-5,l)){ +var _49=screen.colorDepth; +if(_42!==null){ +if(_43==="absolute"){ +return ((min&&_49>=_44)||(max&&_49<_44)||(!min&&!max&&_49===_44)); +}else{ +return false; +} +}else{ +return _49>0; +} +}else{ +if("resolution"===_41.substring(l-10,l)){ +var res; +if(_45==="dpcm"){ +res=_3d("1cm"); +}else{ +res=_3d("1in"); +} +if(_42!==null){ +if(_43==="resolution"){ +return ((min&&res>=_44)||(max&&res<_44)||(!min&&!max&&res===_44)); +}else{ +return false; +} +}else{ +return res>0; +} +}else{ +return false; +} +} +} +} +} +} +} +} +}; +var _4a=function(mq){ +var _4b=mq.getValid(); +var _4c=mq.getExpressions(); +var l=_4c.length; +if(l>0){ +for(var i=0;i0){ +s[c++]=","; +} +s[c++]=n; +} +} +if(s.length>0){ +_39[_39.length]=cssHelper.addStyle("@media "+s.join("")+"{"+mql.getCssText()+"}",false); +} +}; +var _4e=function(_4f){ +for(var i=0;i<_4f.length;i++){ +_4d(_4f[i]); +} +if(ua.ie){ +document.documentElement.style.display="block"; +setTimeout(function(){ +document.documentElement.style.display=""; +},0); +setTimeout(function(){ +cssHelper.broadcast("cssMediaQueriesTested"); +},100); +}else{ +cssHelper.broadcast("cssMediaQueriesTested"); +} +}; +var _50=function(){ +for(var i=0;i<_39.length;i++){ +cssHelper.removeStyle(_39[i]); +} +_39=[]; +cssHelper.mediaQueryLists(_4e); +}; +var _51=0; +var _52=function(){ +var _53=cssHelper.getViewportWidth(); +var _54=cssHelper.getViewportHeight(); +if(ua.ie){ +var el=document.createElement("div"); +el.style.position="absolute"; +el.style.top="-9999em"; +el.style.overflow="scroll"; +document.body.appendChild(el); +_51=el.offsetWidth-el.clientWidth; +document.body.removeChild(el); +} +var _55; +var _56=function(){ +var vpw=cssHelper.getViewportWidth(); +var vph=cssHelper.getViewportHeight(); +if(Math.abs(vpw-_53)>_51||Math.abs(vph-_54)>_51){ +_53=vpw; +_54=vph; +clearTimeout(_55); +_55=setTimeout(function(){ +if(!_3a()){ +_50(); +}else{ +cssHelper.broadcast("cssMediaQueriesTested"); +} +},500); +} +}; +window.onresize=function(){ +var x=window.onresize||function(){ +}; +return function(){ +x(); +_56(); +}; +}(); +}; +var _57=document.documentElement; +_57.style.marginLeft="-32767px"; +setTimeout(function(){ +_57.style.marginTop=""; +},20000); +return function(){ +if(!_3a()){ +cssHelper.addListener("newStyleParsed",function(el){ +_4e(el.cssHelperParsed.mediaQueryLists); +}); +cssHelper.addListener("cssMediaQueriesTested",function(){ +if(ua.ie){ +_57.style.width="1px"; +} +setTimeout(function(){ +_57.style.width=""; +_57.style.marginLeft=""; +},0); +cssHelper.removeListener("cssMediaQueriesTested",arguments.callee); +}); +_3c(); +_50(); +}else{ +_57.style.marginLeft=""; +} +_52(); +}; +}()); +try{ +document.execCommand("BackgroundImageCache",false,true); +} +catch(e){ +} + diff --git a/readme.md b/lists_sqlite_providers.md similarity index 64% rename from readme.md rename to lists_sqlite_providers.md index 4505755..1833451 100755 --- a/readme.md +++ b/lists_sqlite_providers.md @@ -1,49 +1,17 @@ # Things I wish I'd known about sooner: Lists, SQLite and ContentProviders -This tutorial is good if you want to learn about SQLite and how to use it effectively -in Android. I have upgraded the project to Android Studio so some of the -Eclipse-centric content is slightly out-dated, but the gist of it is the same. -All the same functionality is present in Android Studio as it was in Eclipse, -with the same kind of wizards etc. You can also enable a setting in Android Studio -so most of the key commands are the same. - ## Introduction Lists must be one of the most ubiquitous UI-elements. What app doesn't have them? If they don't they probably have some kind of grid view. This tutorial will apply -to them both. The final result will look like this: - -![On Galaxy Nexus](readme_img/gnex_framed.png) - -![On Nexus7](readme_img/nexus7_framed.png) - -The structure of the tutorial might not be common. I am going to start by -creating the app, documenting all the steps on the way. Once that's done, -I will explain some things in more detail. - -To start with, we're going to have to start a new project. This means there -will be a small amount of boiler plate to deal with before we can actually -get our code running. - -Somewhere in the middle, I will be taking a detour to make those nice looking layouts. -If you don't care about the layout stuff, just skip that section. - -The final step is to make the app use the new layouts, and load the data -from our database into them. - -Once the app is complete, I can explain a few things in more detail by -pointing to the code just created. - +to them both. ### Motivation Many tutorials only show how to use ArrayAdapters and I find that problematic. ArrayAdapters are fine if you're showing a static list, but I think most devs have something more dynamic in mind. Simple rule of thumb is, if the data backing the list can *change* while the list is displaying it, then you want -to use a ContentProvider. While it isn't the only way to get everything working, -together with Loaders, it's just very smooth. The data is fetched on a -background thread and is always up to date. And the system does it all -for you (as long as you have a ContentProvider). What's not to like? +to use a ContentProvider. ### What's a ContentProvider A ContentProvider is seperate from the actual data. In this example, and many @@ -52,16 +20,8 @@ have to be. We will use the Provider to supply our list with content. The advant over a simple ArrayAdapter will be that if the data changes, the list will change, all by itself, as it happens. -### What's a Loader -Loader is a class offered by the Android Framework. It loads (surprise) data -in a background thread and offers a callback interface to allow you to -use that data once it's loaded. We will focus entirely on the case of using -the Loader together with a database cursor. You can use a Loader to load -anything in the background though. So if you have data stored as txt files, -you can use a Loader then as well. - ### What's SQLite and why do I want to store data in a database -SQLite is a dialect of SQL, which stands for *Structured Query Language*. There are +SQLite is a dialect of SQL, which stands for *Simple Query Language*. There are many dialects of SQL and this is the one supported by Android. It is a light and fast version of SQL which does not support all features present in other dialects, but you can do anything even though you might have to phrase it differently. @@ -74,20 +34,20 @@ searches among *millions* of entries in real time. I will be using Eclipse together with the standard SDK only. Target will be Jelly Bean MR2 (Android 4.2), but compatibility will be preserved back to Ice Cream Sandwich. I am assuming that you have managed to install Eclipse together with the SDK and -are good to go. If not, follow the steps [here](http://developer.android.com/sdk/installing/bundle.html). Make sure you have downloaded +are good to go. If not, follow the steps here (LINK!). Make sure you have downloaded the SDK for the Android version you intend to compile against (in our case, android-17). This is not the same as the least required android version to run your app. ### Create a new project Go to the menu, select New, Other, Android Application Project. -![New project](readme_img/newandroid.png) -![New project details](readme_img/newandroid2.png) +![New project](newandroid.png) +![New project details](newandroid2.png) I am going to go with the MasterDetail style to get a nice two-pane view on tablets for free. -![Setting the default layout](readme_img/newandroid3.png) +![Setting the default layout](newandroid3.png) I selected to name my "items" Persons. @@ -101,9 +61,7 @@ have a **modern** device, or were smart enough to get the Nexus S back in the da put your least required version to ICS (android-14). ICS also introduced a lot of great APIs which you don't want to miss out on. Many of them can be used with the support package but to get the action bar and good looks from ICS, you'll need some library like -ActionBarSherlock, and that's a tutorial for another day. The project wizard -adds the support library by default, so staying backwards compatible shouldn't -be too hard. +ActionBarSherlock, and that's a tutorial for another day. ## Let's make our database By selecting the MasterDetail style in the wizard, we got a lot of code for free. @@ -119,11 +77,11 @@ first thing we want to do is to replace this with the SQLite database. First create a new package for your database (not necessary, it's just nice). I'll name it "com.example.providerexample.database". -![New package](readme_img/newpkg.png) +![New package](newpkg.png) Next, in that package create a new class called "DatabaseHandler". -![New class](readme_img/newdbhandler.png) +![New class](newdbhandler.png) Once you have the class open, make it extend "SQLiteOpenHelper" and save. @@ -132,26 +90,17 @@ imported. Put the text cursor somewhere in "SQLiteOpenHelper", hit **CTRL-1**, and select "import SQLiteOpenHelper.." -![Extending the super class](readme_img/newdbhandler2.png) +![Extending the super class](newdbhandler2.png) Save. Now, we need to implement the needed methods. Put the text cursor instead somewhere in "DatabaseHandler", **CTRL-1**, "Add unimplemented methods..". -![Auto fixing errors](readme_img/newdbhandler3.png) +![Auto fixing errors](newdbhandler3.png) The last thing missing is a constructor. Instead of adding a default one, add the following code to the top of the class: ```java - private static DatabaseHandler singleton; - - public static DatabaseHandler getInstance(final Context context) { - if (singleton == null) { - singleton = new DatabaseHandler(context); - } - return singleton; - } - private static final int DATABASE_VERSION = 1; private static final String DATABASE_NAME = "providerExample"; @@ -159,12 +108,13 @@ the following code to the top of the class: public DatabaseHandler(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); - // Good idea to use process context here - this.context = context.getApplicationContext(); + this.context = context; } ``` -Your project should no longer show any errors. +Your project should no longer show any errors. This stage of the project +corresponds to +commit 22a5b48f963eac813ad67b8f2682b8174ff62652. Before we make any further changes to the DatabaseHandler, let's make a Person class. We are now doing a kind of DAO/ORM approach @@ -321,17 +271,17 @@ do the following: add/update a person, remove a person and of course get a perso Let's add methods corresponding to those cases: ```java - public synchronized Person getPerson(final long id) { + public Person getPerson(final long id) { // TODO return null; } - public synchronized boolean putPerson(final Person person) { + public boolean putPerson(final Person person) { // TODO return false; } - public synchronized int removePerson(final Person person) { + public int removePerson(final Person person) { // TODO return 0; } @@ -342,15 +292,13 @@ Your case might differ but I find that if my code wants to save a person, then it wants to save it regardless if it is already present in the database or not. -The methods are *synchronized* because we are going to use loaders to load -the data, which run on separate background threads. So we want to make sure -that only one thread is reading/writing at any given time. +We are now at commit c2a050d32455eb292c1aec35dc49dcf41c69873d. Let's start with *getPerson*. All we want to do is query the database for a row with the specified id. ```java - public synchronized Person getPerson(final long id) { + public Person getPerson(final long id) { final SQLiteDatabase db = this.getReadableDatabase(); final Cursor cursor = db.query(Person.TABLE_NAME, Person.FIELDS, Person.COL_ID + " IS ?", @@ -364,7 +312,7 @@ for a row with the specified id. item = new Person(cursor); } cursor.close(); - + db.close(); return item; } ``` @@ -376,12 +324,12 @@ row in the database matches the specified ID. IDs start at 1, so -1 is always a safe default value. The delete method is similarly simple: ```java - public synchronized int removePerson(final Person person) { + public int removePerson(final Person person) { final SQLiteDatabase db = this.getWritableDatabase(); final int result = db.delete(Person.TABLE_NAME, Person.COL_ID + " IS ?", new String[] { Long.toString(person.id) }); - + db.close(); return result; } ``` @@ -394,7 +342,7 @@ because it is both an insert and an update method. First, we try to update the person. If that fails, we insert it instead. ```java - public synchronized boolean putPerson(final Person person) { + public boolean putPerson(final Person person) { boolean success = false; int result = 0; final SQLiteDatabase db = this.getWritableDatabase(); @@ -418,12 +366,13 @@ First, we try to update the person. If that fails, we insert it instead. } } + db.close(); + return success; } ``` -Our ORM layer is complete. - +Our ORM layer is complete. This is at commit b6a3a519ae45c762b98e43c6a8455147303fa06b. Using Person as a base, it is fairly easy to add additional tables to the database. All we need are get,put and remote methods in the database handler and we're set. Changes made to Person basically never have to touch the database handler ever. @@ -438,11 +387,11 @@ at first, so making it will be quick. First we need to create the shell of the class. The newer versions of the Android SDK make this easy. Go to New -> Other. Then select "Android Object". -![new android object](readme_img/newandroidobject.png) +![new android object](newandroidobject.png) Next select "ContentProvider" from the list! -![new content provider](readme_img/newcontentprovider.png) +![new content provider](newcontentprovider.png) It's important to keep in mind what you type as your authority. It should basically be "your.package.provider", but that's just a convention I read @@ -450,12 +399,7 @@ somewhere. It would be anything but must be unique to your application. I went with *com.example.providerexample.provider*. Exported isn't needed as we will only use the provider internally so far. -![choosing authority](readme_img/newcontentprovider2.png) - -By default, the wizard places the class in your main package. I want it to -be in the database package. Remember if you move it, you must change the -corresponding package name in the *AndroidManifest.xml* or your app will -crash on start. +![choosing authority](newcontentprovider2.png) Now you have the shell of a Provider done! This is the complete generated class: @@ -621,13 +565,6 @@ And similarly for *removePerson*: } ``` -Last, make the Provider listen for such notifications. Add the following -line to both blocks in *query*: - -```Java -result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS); -``` - That's it. We're done. Here are the complete *PersonProvider* and *DatabaseHandler* classes before we move on to displaying the content: ```java @@ -779,8 +716,7 @@ public class PersonProvider extends ContentProvider { .getReadableDatabase() .query(Person.TABLE_NAME, Person.FIELDS, null, null, null, null, null, null); - result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS); - } else if (uri.toString().startsWith(PERSON_BASE)) { + } else if (uri.toString().startsWith(PERSON_BASE)) { final long id = Long.parseLong(uri.getLastPathSegment()); result = DatabaseHandler .getInstance(getContext()) @@ -789,8 +725,7 @@ public class PersonProvider extends ContentProvider { Person.COL_ID + " IS ?", new String[] { String.valueOf(id) }, null, null, null, null); - result.setNotificationUri(getContext().getContentResolver(), URI_PERSONS); - } else { + } else { throw new UnsupportedOperationException("Not yet implemented"); } @@ -885,7 +820,7 @@ with the following to get a more interesting view: This will look like this: -![Fancy person detail view](readme_img/persondetailview.png) +![Fancy person detail view](persondetailview.png) The whole thing is wrapped in a scrollview to allow people to have really long biographies even on small screens. @@ -939,7 +874,7 @@ the following in it: Create a new layout xml file called "person_listitem.xml", make the root view a linear vertical layout. -![New layout file](readme_img/newlayoutfile.png) +![New layout file](newlayoutfile.png) You want the file contents to look like: @@ -989,7 +924,6 @@ You want the file contents to look like: android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" - android:maxLines="3" android:paddingLeft="4dp" android:paddingRight="4dp" android:textColor="#ff8d8d8d" @@ -1008,74 +942,16 @@ its content: android:layout_width="match_parent" android:layout_height="match_parent" android:id="@id/android:list" - android:divider="@android:color/transparent" - android:dividerHeight="12dp" android:drawSelectorOnTop="true" - android:background="#e5e5e5" - android:paddingLeft="16dp" - android:paddingRight="16dp" - /> + android:background="#e5e5e5" /> ``` This is a straight up list view with a grey background and it draws selectors on top. The items in the list will now look like this: -![List item layout](readme_img/cardItem.png) +![List item layout](cardItem.png) -Because of the background, I want to move the location of some margins so the -correct background is rendered at that location. - -*activity_person_twopange* only margins and layout weights changed: -```XML - - - - - - - - - -``` - -And same deal for *activity_person_list*: -```XML - -``` +We are now at commit 1a0b5e10466e1cf0500c698bb95cb2a241ec91bb. ## Make the app use the new layouts and load the data By now you should have one or two compiler errors because we removed @@ -1216,25 +1092,6 @@ public class PersonDetailFragment extends Fragment { } ``` -#### Why not use the provider here? -It would be good practice to use a Loader to fetch the Person from the Provider, -if only just because the data would be loaded on a background thread. Right -now the fragment is fetching the person on the UI thread. - -First, I wanted to show how to use an SQLite database without a ContentProvider. -As you can see, the changes from some kind of ArrayAdapter situation are quite -minimal in the fragments/activities. - -Second, fetching the data on a background thread is just about the only -benefit we will get from using a Loader in the detail fragment. We **DON'T** -want the data to auto update in here like we want it to do in the List. -Because consider if it is possible that the data is changed somewhere else, -maybe you implement some kind of synchronization service. It would be really -bad user experience to have your entire item change as you were editing it. - -Fetching a single item on the UI thread is fine for now. If you have more -advanced ideas in mind, yes you should use a Loader. - ### Fixing list view First we need to use the layout defined in "fragment_person_list.xml". This is more or less only because I want a grey background in the list. @@ -1248,7 +1105,7 @@ Add: ``` Next we set the adapter using a *SimpleCursorAdapter*. -Initially it has a null cursor. The data is loaded using a *Loader*. +Initially it has a null cursor. The data is getting loaded using a *Loader*. So in *onCreate*, change from: ```java @@ -1304,7 +1161,7 @@ As a last step, update the *onListItemClick* method to utilize the Cursor instea But, we must also change the callback interface to use a Long instead of a String to match our database ID and what the Fragment expects. -![Change to long](readme_img/changetolongarg.png) +![Change to long](changetolongarg.png) Make suitable changes everywhere. In the same file update the dummyCallback: @@ -1345,399 +1202,3 @@ And in PersonListActivity update *onItemSelected*: ## Add a new button Running the app now should present an empty list. Not that interesting! We need to be able to add some items. Just implement a menu item for that: - -![New menu file](readme_img/newmenu.png) - -```XML - - - - - - -``` - -Inflate the menu and click handler in *PersonListActivity*: - -```Java - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.list_activity, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - boolean result = false; - if (R.id.newPerson == item.getItemId()) { - result = true; - // Create a new person. - Person p = new Person(); - DatabaseHandler.getInstance(this).putPerson(p); - // Open a new fragment with the new id - onItemSelected(p.id); - } - - return result; - } -``` - -Change to LongExtras in *PersonListActivity.java* -```Java - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_person_detail); - - // Show the Up button in the action bar. - getActionBar().setDisplayHomeAsUpEnabled(true); - - // savedInstanceState is non-null when there is fragment state - // saved from previous configurations of this activity - // (e.g. when rotating the screen from portrait to landscape). - // In this case, the fragment will automatically be re-added - // to its container so we don't need to manually add it. - // For more information, see the Fragments API guide at: - // - // http://developer.android.com/guide/components/fragments.html - // - if (savedInstanceState == null) { - // Create the detail fragment and add it to the activity - // using a fragment transaction. - Bundle arguments = new Bundle(); - arguments.putLong(PersonDetailFragment.ARG_ITEM_ID, - getIntent().getLongExtra(PersonDetailFragment.ARG_ITEM_ID, -1)); - PersonDetailFragment fragment = new PersonDetailFragment(); - fragment.setArguments(arguments); - getSupportFragmentManager().beginTransaction() - .add(R.id.person_detail_container, fragment) - .commit(); - } - } -``` - -## Add some data -Before shipping off your newly created app you might want to add some data to it. -You can do so by updating the onCreate method of the DatabaseHandler. -First you create a new person object, populate it with the desired values and -finally insert it using the insert method of the db object. Eventually it should look like below. - -Do note that ideally any predefined data should be loaded from resources -and not be hardcoded like done here. But doing so is beyond this tutorial. - -```java - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(Person.CREATE_TABLE); - - Person person = new Person(); - person.firstname = "Sylvester"; - person.lastname = "Stallone"; - person.bio = "..."; - db.insert(Person.TABLE_NAME, null, person.getContent()); - - person.firstname = "Danny"; - person.lastname = "DeVito"; - person.bio = "..."; - db.insert(Person.TABLE_NAME, null, person.getContent()); - } -``` - -## Final result -Nexus 7 - -![Nexus 7](readme_img/nexus7.png) - -Galaxy Nexus List - -![Galaxy Nexus](readme_img/gnexlist.png) - -Galaxy Nexus Details - -![Galaxy Nexus](readme_img/gnexdetail1.png) - -## Explaining the details - -Let's clarify a few of the things I skipped over quite fast. - -### URIs - -A URI is pretty much an address. You are quite familiar with URIs like -*http://www.google.com*. The URIs which point to information handled by -ContentProviders always start with *content://* instead of *http://*, but -you see that the structure is the same. This part is what is called the -**scheme**. A URI pointing to a file on the SD card would have the scheme: -*file://*. - -The next part of the URI is the **authority**. This identifies which entity -(in our case, which provider in which app) should handle the request. In the -example above the authority was *www.google.com*. In the case of content -providers, the authority typically involves your package name (like -*com.example.providerexample*) in order to guarantee its uniqueness to your -provider. Some Google document says its convention to put *.provider* at -the end. It makes sure the system knows to pass the request along to our -content provider and not one of the others in the system. - -The final part of the URI is the **path**. The google address does not have -a path. If it looked like: *http://www.google.com/a/folder/img.png* then -*/a/folder/img.png* would be the path. This is meaningless to the system -and only relevant to our content provider. We can define anything we -want here. We use it to differentiate between different requests. For -example: */persons* used in a query will retrieve a list of all persons. -*/persons/id* will fetch only a single person with the designated id. -*/squirrels* won't lead to anything since the provider doesn't know -what to do with that. But it could. It's all up to the developer. - -### SQLite - -There are (many) books written about SQL so I'm not even going to try to -condense everything thing in here. Instead I'll focus on what you have seen -and what is obviously still missing. - -SQLite is merely the language dialect we are using. We are using it because -it is what Google decided to support natively in Android. The point is -to create and manage a database. A relational database (there are other kinds) -stores its information in tables. Each entry corresponds to a row in the -table, with each kind of information stored in the different columns. - -A concrete example: - - - - - - - - - - - - - - - - - -
IDnamephonenumber
1Bob326346
2Alice326346
- -Created by: - -```SQL -CREATE TABLE contact( - INT ID primary key, - TEXT name, - TEXT phonenumber) -``` - -This table would store people with their phone numbers and possibly other -information as well. Now, if you wanted to support more than one phone number -per person, this structure would break down. There is no way to make a list -of phone numbers (without doing string parsing) for a single person here. To -do that, you'd need to take advantage of the *relational* part of the database. -We'd have to store the phonenumbers in a separate table. For example: - - - - - - - - - - - - - - -
IDname
1Bob
2Alice
- - - - - - - - - - - - - - - - - -
IDcontactidphonenumber
12326346
21326346
- - -Created by: - -```SQL -CREATE TABLE contact( - INT ID primary key, - TEXT name); - -CREATE TABLE phonenumber( - INT ID primary key, - INT contactid, - TEXT phonenumber); -``` - -Now we can store an arbitrary amount of phone numbers per contact. This might -seem messy, and it kind of is. But, once you get the hang of it you can do -some pretty powerful and convenient things too. One thing that I missed above -was to have a *CONSTRAINT* on the table. Right now, the phonenumbers table -has a column called contactid, but the database doesn't care what you insert -there. Consider instead the following modification to the code: - -```SQL -CREATE TABLE phonenumber( - INT ID primary key, - INT contactid REFERENCES contact, - TEXT phonenumber) -``` - -Now we are telling the database that this number should match a valid ID -in the contacts table. If we do something that will make this statement -false, the database will throw an exception. This is good because it -prevents us from doing stupid things. Like filling the database with a -bunch of orphan phone numbers. We can make things easy on ourselves however -by adding a *CONFLICT RESOLUTION CLAUSE*: - -```SQL -CREATE TABLE phonenumber( - INT ID primary key, - INT contactid REFERENCES contact ON DELETE CASCADE, - TEXT phonenumber) -``` - -If we delete a contact and that contact is linked to phone numbers, now -those phone numbers are deleted automatically at the same time. So the database -will not break because we delete a contact. We can also constrain the -phone numbers to be unique: - -```SQL -CREATE TABLE phonenumber( - INT ID primary key, - INT contactid REFERENCES contact ON DELETE CASCADE, - TEXT phonenumber, - UNIQUE(phonenumber)) -``` - -This means that only one contact can be linked to a single phone number, which -is probably a lot like reality. But consider something like a hard line, a -home phone. That is probably linked to an entire family, logically speaking. -We can make the database understand that by doing: - -```SQL -CREATE TABLE phonenumber( - INT ID primary key, - INT contactid REFERENCES contact ON DELETE CASCADE, - TEXT phonenumber, - UNIQUE(contactid, phonenumber)) -``` - -Now we are only constraining the phonenumber to be unique within a person's -collection of numbers. So a number can not occur more than once for a single -persons, which makes sense. But a number can belong to several persons, which -is true in case of home phones. - -#### Queries - -To get information from the database, we will be doing a **query**. The -result is returned in a Cursor. The basic SQL syntax of a query is: - -```SQL -SELECT columnname1, columnname2 - FROM table - WHERE something IS something - ORDER BY columname; -``` - -This returns a cursor with all the rows that matched the *WHERE*-part. But, -you can do queries on multiple tables at once and do internal queries as -part of your *WHERE*-clause. We can also do some arithmetic and string operations. -In Android we will probably tend to use the suitable helper classes. They -work fine unless you want to do things that concern multiple tables at -once (JOINED queries). You have already seen the syntax being of the form: - -```Java -db.query(tableName, columnsToReturn, "something IS ?", someValue, - null, null, - orderByColumnName, - null); -``` - -You can see that this matches quite literally the parts from the SQL code. -The nulls represents possible other constraints -that I will not mention. - -The question mark however is useful. While you could have put your argument -directly in the string instead of the question mark, that might break at times. -Namely when that argument is a string. For example: - -**WHERE column1 IS Arthur** - -would crash because the correct syntax would be - -**WHERE column1 IS 'Arthur'** - -And those quotes are easy to forget. Putting the question mark in the java -call means that the implementation will wrap your argument in quotes for you. -It's basically safer, and means you have a fixed where-clause as a static -string somewhere, and only change the argument array. - -To order the data, just specify the columnname and whether to do it "ASC" or -"DESC" (forwards or backwards). To sort the names in the list in the app -alphabetically, just do something like: - -```Java -final Cursor cursor = db.query(Person.TABLE_NAME, Person.FIELDS, - Person.COL_ID + " IS ?", new String[] { String.valueOf(id) }, - null, null, - Person.COL_FIRSTNAME, - , null); -``` - -To do it backwards replace the OrderBy part with (don't forget the space): - -```Java -Person.COL_FIRSTNAME + " DESC" -``` - -#### Changing data -Operating on tables is possible using *insert*, *update* or *delete*. They -are probably self explanatory from their names. Just like queries, *update* -and *delete* accept WHERE-clauses. Which means you can update or delete -a whole bunch of items fulfilling some criteria. Like deleting all -people over 50 years old if you had that data. - -Another thing that is handy to know about is how to change tha database -tables. SQLite will not allow you to delete columns from tables, but -you can add columns or rename them. Adding columns after the fact has -a few restrictions though: - -- The column may not have a PRIMARY KEY or UNIQUE constraint. -- The column may not have a default value of CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, or an expression in parentheses. -- If a NOT NULL constraint is specified, then the column must have a default value other than NULL. -- If foreign key constraints are enabled and a column with a REFERENCES clause is added, the column must have a default value of NULL. - -The only thing relevant is probably the first one, they can not have a -unique constraint which could be something of a bummer. The syntax you could -put in your Databasehandler's onUpdate method would be something like: - -```Java -public void onUpdate(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion < 2) { - db.execSQL("ALTER TABLE contact ADD COLUMN INT age NOT NULL DEFAULT 25"); - } -} -``` - -Just remember to update your original create table statement for fresh installs. -They will NOT get a call to onUpdate. diff --git a/readme_img/new.png b/new.png similarity index 100% rename from readme_img/new.png rename to new.png diff --git a/readme_img/newandroid.png b/newandroid.png similarity index 100% rename from readme_img/newandroid.png rename to newandroid.png diff --git a/readme_img/newandroid2.png b/newandroid2.png similarity index 100% rename from readme_img/newandroid2.png rename to newandroid2.png diff --git a/readme_img/newandroid3.png b/newandroid3.png similarity index 100% rename from readme_img/newandroid3.png rename to newandroid3.png diff --git a/readme_img/newandroidobject.png b/newandroidobject.png similarity index 100% rename from readme_img/newandroidobject.png rename to newandroidobject.png diff --git a/readme_img/newcontentprovider.png b/newcontentprovider.png similarity index 100% rename from readme_img/newcontentprovider.png rename to newcontentprovider.png diff --git a/readme_img/newcontentprovider2.png b/newcontentprovider2.png similarity index 100% rename from readme_img/newcontentprovider2.png rename to newcontentprovider2.png diff --git a/readme_img/newdbhandler.png b/newdbhandler.png similarity index 100% rename from readme_img/newdbhandler.png rename to newdbhandler.png diff --git a/readme_img/newdbhandler2.png b/newdbhandler2.png similarity index 100% rename from readme_img/newdbhandler2.png rename to newdbhandler2.png diff --git a/readme_img/newdbhandler3.png b/newdbhandler3.png similarity index 100% rename from readme_img/newdbhandler3.png rename to newdbhandler3.png diff --git a/readme_img/newlayoutfile.png b/newlayoutfile.png similarity index 100% rename from readme_img/newlayoutfile.png rename to newlayoutfile.png diff --git a/readme_img/newpkg.png b/newpkg.png similarity index 100% rename from readme_img/newpkg.png rename to newpkg.png diff --git a/params.json b/params.json new file mode 100644 index 0000000..8c02542 --- /dev/null +++ b/params.json @@ -0,0 +1 @@ +{"google":"","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.","note":"Don't delete this file! It's used internally to help with page regeneration.","tagline":"","name":"Androidtutorialcontentprovider"} \ No newline at end of file diff --git a/readme_img/persondetailview.png b/persondetailview.png similarity index 100% rename from readme_img/persondetailview.png rename to persondetailview.png diff --git a/readme_img/gnex_framed.png b/readme_img/gnex_framed.png deleted file mode 100644 index 7a5bf4c..0000000 Binary files a/readme_img/gnex_framed.png and /dev/null differ diff --git a/readme_img/gnexdetail1.png b/readme_img/gnexdetail1.png deleted file mode 100644 index 15e82df..0000000 Binary files a/readme_img/gnexdetail1.png and /dev/null differ diff --git a/readme_img/gnexdetail2.png b/readme_img/gnexdetail2.png deleted file mode 100644 index 4a7c2ef..0000000 Binary files a/readme_img/gnexdetail2.png and /dev/null differ diff --git a/readme_img/gnexlist.png b/readme_img/gnexlist.png deleted file mode 100644 index f9ec0a1..0000000 Binary files a/readme_img/gnexlist.png and /dev/null differ diff --git a/readme_img/newmenu.png b/readme_img/newmenu.png deleted file mode 100644 index 4b2ffdc..0000000 Binary files a/readme_img/newmenu.png and /dev/null differ diff --git a/readme_img/nexus7.png b/readme_img/nexus7.png deleted file mode 100644 index 5851fd8..0000000 Binary files a/readme_img/nexus7.png and /dev/null differ diff --git a/readme_img/nexus7_framed.png b/readme_img/nexus7_framed.png deleted file mode 100644 index 891faeb..0000000 Binary files a/readme_img/nexus7_framed.png and /dev/null differ diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index e7b4def..0000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/stylesheets/ie.css b/stylesheets/ie.css new file mode 100644 index 0000000..43882f2 --- /dev/null +++ b/stylesheets/ie.css @@ -0,0 +1,3 @@ +nav { + display: none; +} diff --git a/stylesheets/normalize.css b/stylesheets/normalize.css new file mode 100644 index 0000000..bc2ba93 --- /dev/null +++ b/stylesheets/normalize.css @@ -0,0 +1,459 @@ +/* normalize.css 2012-02-07T12:37 UTC - http://github.com/necolas/normalize.css */ +/* ============================================================================= + HTML5 display definitions + ========================================================================== */ +/* + * Corrects block display not defined in IE6/7/8/9 & FF3 + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section, +summary { + display: block; +} + +/* + * Corrects inline-block display not defined in IE6/7/8/9 & FF3 + */ +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +/* + * Prevents modern browsers from displaying 'audio' without controls + */ +audio:not([controls]) { + display: none; +} + +/* + * Addresses styling for 'hidden' attribute not present in IE7/8/9, FF3, S4 + * Known issue: no IE6 support + */ +[hidden] { + display: none; +} + +/* ============================================================================= + Base + ========================================================================== */ +/* + * 1. Corrects text resizing oddly in IE6/7 when body font-size is set using em units + * http://clagnut.com/blog/348/#c790 + * 2. Prevents iOS text size adjust after orientation change, without disabling user zoom + * www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/ + */ +html { + font-size: 100%; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -ms-text-size-adjust: 100%; + /* 2 */ +} + +/* + * Addresses font-family inconsistency between 'textarea' and other form elements. + */ +html, +button, +input, +select, +textarea { + font-family: sans-serif; +} + +/* + * Addresses margins handled incorrectly in IE6/7 + */ +body { + margin: 0; +} + +/* ============================================================================= + Links + ========================================================================== */ +/* + * Addresses outline displayed oddly in Chrome + */ +a:focus { + outline: thin dotted; +} + +/* + * Improves readability when focused and also mouse hovered in all browsers + * people.opera.com/patrickl/experiments/keyboard/test + */ +a:hover, +a:active { + outline: 0; +} + +/* ============================================================================= + Typography + ========================================================================== */ +/* + * Addresses font sizes and margins set differently in IE6/7 + * Addresses font sizes within 'section' and 'article' in FF4+, Chrome, S5 + */ +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +h2 { + font-size: 1.5em; + margin: 0.83em 0; +} + +h3 { + font-size: 1.17em; + margin: 1em 0; +} + +h4 { + font-size: 1em; + margin: 1.33em 0; +} + +h5 { + font-size: 0.83em; + margin: 1.67em 0; +} + +h6 { + font-size: 0.75em; + margin: 2.33em 0; +} + +/* + * Addresses styling not present in IE7/8/9, S5, Chrome + */ +abbr[title] { + border-bottom: 1px dotted; +} + +/* + * Addresses style set to 'bolder' in FF3+, S4/5, Chrome +*/ +b, +strong { + font-weight: bold; +} + +blockquote { + margin: 1em 40px; +} + +/* + * Addresses styling not present in S5, Chrome + */ +dfn { + font-style: italic; +} + +/* + * Addresses styling not present in IE6/7/8/9 + */ +mark { + background: #ff0; + color: #000; +} + +/* + * Addresses margins set differently in IE6/7 + */ +p, +pre { + margin: 1em 0; +} + +/* + * Corrects font family set oddly in IE6, S4/5, Chrome + * en.wikipedia.org/wiki/User:Davidgothberg/Test59 + */ +pre, +code, +kbd, +samp { + font-family: monospace, serif; + _font-family: 'courier new', monospace; + font-size: 1em; +} + +/* + * 1. Addresses CSS quotes not supported in IE6/7 + * 2. Addresses quote property not supported in S4 + */ +/* 1 */ +q { + quotes: none; +} + +/* 2 */ +q:before, +q:after { + content: ''; + content: none; +} + +small { + font-size: 75%; +} + +/* + * Prevents sub and sup affecting line-height in all browsers + * gist.github.com/413930 + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ============================================================================= + Lists + ========================================================================== */ +/* + * Addresses margins set differently in IE6/7 + */ +dl, +menu, +ol, +ul { + margin: 1em 0; +} + +dd { + margin: 0 0 0 40px; +} + +/* + * Addresses paddings set differently in IE6/7 + */ +menu, +ol, +ul { + padding: 0 0 0 40px; +} + +/* + * Corrects list images handled incorrectly in IE7 + */ +nav ul, +nav ol { + list-style: none; + list-style-image: none; +} + +/* ============================================================================= + Embedded content + ========================================================================== */ +/* + * 1. Removes border when inside 'a' element in IE6/7/8/9, FF3 + * 2. Improves image quality when scaled in IE7 + * code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ + */ +img { + border: 0; + /* 1 */ + -ms-interpolation-mode: bicubic; + /* 2 */ +} + +/* + * Corrects overflow displayed oddly in IE9 + */ +svg:not(:root) { + overflow: hidden; +} + +/* ============================================================================= + Figures + ========================================================================== */ +/* + * Addresses margin not present in IE6/7/8/9, S5, O11 + */ +figure { + margin: 0; +} + +/* ============================================================================= + Forms + ========================================================================== */ +/* + * Corrects margin displayed oddly in IE6/7 + */ +form { + margin: 0; +} + +/* + * Define consistent border, margin, and padding + */ +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/* + * 1. Corrects color not being inherited in IE6/7/8/9 + * 2. Corrects text not wrapping in FF3 + * 3. Corrects alignment displayed oddly in IE6/7 + */ +legend { + border: 0; + /* 1 */ + padding: 0; + white-space: normal; + /* 2 */ + *margin-left: -7px; + /* 3 */ +} + +/* + * 1. Corrects font size not being inherited in all browsers + * 2. Addresses margins set differently in IE6/7, FF3+, S5, Chrome + * 3. Improves appearance and consistency in all browsers + */ +button, +input, +select, +textarea { + font-size: 100%; + /* 1 */ + margin: 0; + /* 2 */ + vertical-align: baseline; + /* 3 */ + *vertical-align: middle; + /* 3 */ +} + +/* + * Addresses FF3/4 setting line-height on 'input' using !important in the UA stylesheet + */ +button, +input { + line-height: normal; + /* 1 */ +} + +/* + * 1. Improves usability and consistency of cursor style between image-type 'input' and others + * 2. Corrects inability to style clickable 'input' types in iOS + * 3. Removes inner spacing in IE7 without affecting normal text inputs + * Known issue: inner spacing remains in IE6 + */ +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + /* 1 */ + -webkit-appearance: button; + /* 2 */ + *overflow: visible; + /* 3 */ +} + +/* + * Re-set default cursor for disabled elements + */ +button[disabled], +input[disabled] { + cursor: default; +} + +/* + * 1. Addresses box sizing set to content-box in IE8/9 + * 2. Removes excess padding in IE8/9 + * 3. Removes excess padding in IE7 + Known issue: excess padding remains in IE6 + */ +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ + *height: 13px; + /* 3 */ + *width: 13px; + /* 3 */ +} + +/* + * 1. Addresses appearance set to searchfield in S5, Chrome + * 2. Addresses box-sizing set to border-box in S5, Chrome (include -moz to future-proof) + */ +input[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + /* 2 */ + box-sizing: content-box; +} + +/* + * Removes inner padding and search cancel button in S5, Chrome on OS X + */ +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +/* + * Removes inner padding and border in FF3+ + * www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/ + */ +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/* + * 1. Removes default vertical scrollbar in IE6/7/8/9 + * 2. Improves readability and alignment in all browsers + */ +textarea { + overflow: auto; + /* 1 */ + vertical-align: top; + /* 2 */ +} + +/* ============================================================================= + Tables + ========================================================================== */ +/* + * Remove most spacing between table cells + */ +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css new file mode 100644 index 0000000..c79bef4 --- /dev/null +++ b/stylesheets/pygment_trac.css @@ -0,0 +1,70 @@ +.highlight .hll { background-color: #404040 } +.highlight { color: #d0d0d0 } +.highlight .c { color: #999999; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .g { color: #d0d0d0 } /* Generic */ +.highlight .k { color: #6ab825; font-weight: normal } /* Keyword */ +.highlight .l { color: #d0d0d0 } /* Literal */ +.highlight .n { color: #d0d0d0 } /* Name */ +.highlight .o { color: #d0d0d0 } /* Operator */ +.highlight .x { color: #d0d0d0 } /* Other */ +.highlight .p { color: #d0d0d0 } /* Punctuation */ +.highlight .cm { color: #999999; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #cd2828; font-weight: normal } /* Comment.Preproc */ +.highlight .c1 { color: #999999; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #e50808; font-weight: normal; background-color: #520000 } /* Comment.Special */ +.highlight .gd { color: #d22323 } /* Generic.Deleted */ +.highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #d22323 } /* Generic.Error */ +.highlight .gh { color: #ffffff; font-weight: normal } /* Generic.Heading */ +.highlight .gi { color: #589819 } /* Generic.Inserted */ +.highlight .go { color: #cccccc } /* Generic.Output */ +.highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +.highlight .gs { color: #d0d0d0; font-weight: normal } /* Generic.Strong */ +.highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +.highlight .gt { color: #d22323 } /* Generic.Traceback */ +.highlight .kc { color: #6ab825; font-weight: normal } /* Keyword.Constant */ +.highlight .kd { color: #6ab825; font-weight: normal } /* Keyword.Declaration */ +.highlight .kn { color: #6ab825; font-weight: normal } /* Keyword.Namespace */ +.highlight .kp { color: #6ab825 } /* Keyword.Pseudo */ +.highlight .kr { color: #6ab825; font-weight: normal } /* Keyword.Reserved */ +.highlight .kt { color: #6ab825; font-weight: normal } /* Keyword.Type */ +.highlight .ld { color: #d0d0d0 } /* Literal.Date */ +.highlight .m { color: #3677a9 } /* Literal.Number */ +.highlight .s { color: #9dd5f1 } /* Literal.String */ +.highlight .na { color: #bbbbbb } /* Name.Attribute */ +.highlight .nb { color: #24909d } /* Name.Builtin */ +.highlight .nc { color: #447fcf; text-decoration: underline } /* Name.Class */ +.highlight .no { color: #40ffff } /* Name.Constant */ +.highlight .nd { color: #ffa500 } /* Name.Decorator */ +.highlight .ni { color: #d0d0d0 } /* Name.Entity */ +.highlight .ne { color: #bbbbbb } /* Name.Exception */ +.highlight .nf { color: #447fcf } /* Name.Function */ +.highlight .nl { color: #d0d0d0 } /* Name.Label */ +.highlight .nn { color: #447fcf; text-decoration: underline } /* Name.Namespace */ +.highlight .nx { color: #d0d0d0 } /* Name.Other */ +.highlight .py { color: #d0d0d0 } /* Name.Property */ +.highlight .nt { color: #6ab825;} /* Name.Tag */ +.highlight .nv { color: #40ffff } /* Name.Variable */ +.highlight .ow { color: #6ab825; font-weight: normal } /* Operator.Word */ +.highlight .w { color: #666666 } /* Text.Whitespace */ +.highlight .mf { color: #3677a9 } /* Literal.Number.Float */ +.highlight .mh { color: #3677a9 } /* Literal.Number.Hex */ +.highlight .mi { color: #3677a9 } /* Literal.Number.Integer */ +.highlight .mo { color: #3677a9 } /* Literal.Number.Oct */ +.highlight .sb { color: #9dd5f1 } /* Literal.String.Backtick */ +.highlight .sc { color: #9dd5f1 } /* Literal.String.Char */ +.highlight .sd { color: #9dd5f1 } /* Literal.String.Doc */ +.highlight .s2 { color: #9dd5f1 } /* Literal.String.Double */ +.highlight .se { color: #9dd5f1 } /* Literal.String.Escape */ +.highlight .sh { color: #9dd5f1 } /* Literal.String.Heredoc */ +.highlight .si { color: #9dd5f1 } /* Literal.String.Interpol */ +.highlight .sx { color: #ffa500 } /* Literal.String.Other */ +.highlight .sr { color: #9dd5f1 } /* Literal.String.Regex */ +.highlight .s1 { color: #9dd5f1 } /* Literal.String.Single */ +.highlight .ss { color: #9dd5f1 } /* Literal.String.Symbol */ +.highlight .bp { color: #24909d } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #40ffff } /* Name.Variable.Class */ +.highlight .vg { color: #40ffff } /* Name.Variable.Global */ +.highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +.highlight .il { color: #3677a9 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/stylesheets/styles.css b/stylesheets/styles.css new file mode 100644 index 0000000..e7b4ffc --- /dev/null +++ b/stylesheets/styles.css @@ -0,0 +1,851 @@ +@font-face { + font-family: 'OpenSansLight'; + src: url("../fonts/OpenSans-Light-webfont.eot"); + src: url("../fonts/OpenSans-Light-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Light-webfont.woff") format("woff"), url("../fonts/OpenSans-Light-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Light-webfont.svg#OpenSansLight") format("svg"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'OpenSansLightItalic'; + src: url("../fonts/OpenSans-LightItalic-webfont.eot"); + src: url("../fonts/OpenSans-LightItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-LightItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-LightItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic") format("svg"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'OpenSansRegular'; + src: url("../fonts/OpenSans-Regular-webfont.eot"); + src: url("../fonts/OpenSans-Regular-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Regular-webfont.woff") format("woff"), url("../fonts/OpenSans-Regular-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular") format("svg"); + font-weight: normal; + font-style: normal; + -webkit-font-smoothing: antialiased; +} + +@font-face { + font-family: 'OpenSansItalic'; + src: url("../fonts/OpenSans-Italic-webfont.eot"); + src: url("../fonts/OpenSans-Italic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Italic-webfont.woff") format("woff"), url("../fonts/OpenSans-Italic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Italic-webfont.svg#OpenSansItalic") format("svg"); + font-weight: normal; + font-style: normal; + -webkit-font-smoothing: antialiased; +} + +@font-face { + font-family: 'OpenSansSemibold'; + src: url("../fonts/OpenSans-Semibold-webfont.eot"); + src: url("../fonts/OpenSans-Semibold-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Semibold-webfont.woff") format("woff"), url("../fonts/OpenSans-Semibold-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold") format("svg"); + font-weight: normal; + font-style: normal; + -webkit-font-smoothing: antialiased; +} + +@font-face { + font-family: 'OpenSansSemiboldItalic'; + src: url("../fonts/OpenSans-SemiboldItalic-webfont.eot"); + src: url("../fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-SemiboldItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-SemiboldItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic") format("svg"); + font-weight: normal; + font-style: normal; + -webkit-font-smoothing: antialiased; +} + +@font-face { + font-family: 'OpenSansBold'; + src: url("../fonts/OpenSans-Bold-webfont.eot"); + src: url("../fonts/OpenSans-Bold-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Bold-webfont.woff") format("woff"), url("../fonts/OpenSans-Bold-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Bold-webfont.svg#OpenSansBold") format("svg"); + font-weight: normal; + font-style: normal; + -webkit-font-smoothing: antialiased; +} + +@font-face { + font-family: 'OpenSansBoldItalic'; + src: url("../fonts/OpenSans-BoldItalic-webfont.eot"); + src: url("../fonts/OpenSans-BoldItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-BoldItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-BoldItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic") format("svg"); + font-weight: normal; + font-style: normal; + -webkit-font-smoothing: antialiased; +} + +/* normalize.css 2012-02-07T12:37 UTC - http://github.com/necolas/normalize.css */ +/* ============================================================================= + HTML5 display definitions + ========================================================================== */ +/* + * Corrects block display not defined in IE6/7/8/9 & FF3 + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section, +summary { + display: block; +} + +/* + * Corrects inline-block display not defined in IE6/7/8/9 & FF3 + */ +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +/* + * Prevents modern browsers from displaying 'audio' without controls + */ +audio:not([controls]) { + display: none; +} + +/* + * Addresses styling for 'hidden' attribute not present in IE7/8/9, FF3, S4 + * Known issue: no IE6 support + */ +[hidden] { + display: none; +} + +/* ============================================================================= + Base + ========================================================================== */ +/* + * 1. Corrects text resizing oddly in IE6/7 when body font-size is set using em units + * http://clagnut.com/blog/348/#c790 + * 2. Prevents iOS text size adjust after orientation change, without disabling user zoom + * www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/ + */ +html { + font-size: 100%; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -ms-text-size-adjust: 100%; + /* 2 */ +} + +/* + * Addresses font-family inconsistency between 'textarea' and other form elements. + */ +html, +button, +input, +select, +textarea { + font-family: sans-serif; +} + +/* + * Addresses margins handled incorrectly in IE6/7 + */ +body { + margin: 0; +} + +/* ============================================================================= + Links + ========================================================================== */ +/* + * Addresses outline displayed oddly in Chrome + */ +a:focus { + outline: thin dotted; +} + +/* + * Improves readability when focused and also mouse hovered in all browsers + * people.opera.com/patrickl/experiments/keyboard/test + */ +a:hover, +a:active { + outline: 0; +} + +/* ============================================================================= + Typography + ========================================================================== */ +/* + * Addresses font sizes and margins set differently in IE6/7 + * Addresses font sizes within 'section' and 'article' in FF4+, Chrome, S5 + */ +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +h2 { + font-size: 1.5em; + margin: 0.83em 0; +} + +h3 { + font-size: 1.17em; + margin: 1em 0; +} + +h4 { + font-size: 1em; + margin: 1.33em 0; +} + +h5 { + font-size: 0.83em; + margin: 1.67em 0; +} + +h6 { + font-size: 0.75em; + margin: 2.33em 0; +} + +/* + * Addresses styling not present in IE7/8/9, S5, Chrome + */ +abbr[title] { + border-bottom: 1px dotted; +} + +/* + * Addresses style set to 'bolder' in FF3+, S4/5, Chrome +*/ +b, +strong { + font-weight: bold; +} + +blockquote { + margin: 1em 40px; +} + +/* + * Addresses styling not present in S5, Chrome + */ +dfn { + font-style: italic; +} + +/* + * Addresses styling not present in IE6/7/8/9 + */ +mark { + background: #ff0; + color: #000; +} + +/* + * Addresses margins set differently in IE6/7 + */ +p, +pre { + margin: 1em 0; +} + +/* + * Corrects font family set oddly in IE6, S4/5, Chrome + * en.wikipedia.org/wiki/User:Davidgothberg/Test59 + */ +pre, +code, +kbd, +samp { + font-family: monospace, serif; + _font-family: 'courier new', monospace; + font-size: 1em; +} + +/* + * 1. Addresses CSS quotes not supported in IE6/7 + * 2. Addresses quote property not supported in S4 + */ +/* 1 */ +q { + quotes: none; +} + +/* 2 */ +q:before, +q:after { + content: ''; + content: none; +} + +small { + font-size: 75%; +} + +/* + * Prevents sub and sup affecting line-height in all browsers + * gist.github.com/413930 + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ============================================================================= + Lists + ========================================================================== */ +/* + * Addresses margins set differently in IE6/7 + */ +dl, +menu, +ol, +ul { + margin: 1em 0; +} + +dd { + margin: 0 0 0 40px; +} + +/* + * Addresses paddings set differently in IE6/7 + */ +menu, +ol, +ul { + padding: 0 0 0 40px; +} + +/* + * Corrects list images handled incorrectly in IE7 + */ +nav ul, +nav ol { + list-style: none; + list-style-image: none; +} + +/* ============================================================================= + Embedded content + ========================================================================== */ +/* + * 1. Removes border when inside 'a' element in IE6/7/8/9, FF3 + * 2. Improves image quality when scaled in IE7 + * code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ + */ +img { + border: 0; + /* 1 */ + -ms-interpolation-mode: bicubic; + /* 2 */ +} + +/* + * Corrects overflow displayed oddly in IE9 + */ +svg:not(:root) { + overflow: hidden; +} + +/* ============================================================================= + Figures + ========================================================================== */ +/* + * Addresses margin not present in IE6/7/8/9, S5, O11 + */ +figure { + margin: 0; +} + +/* ============================================================================= + Forms + ========================================================================== */ +/* + * Corrects margin displayed oddly in IE6/7 + */ +form { + margin: 0; +} + +/* + * Define consistent border, margin, and padding + */ +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/* + * 1. Corrects color not being inherited in IE6/7/8/9 + * 2. Corrects text not wrapping in FF3 + * 3. Corrects alignment displayed oddly in IE6/7 + */ +legend { + border: 0; + /* 1 */ + padding: 0; + white-space: normal; + /* 2 */ + *margin-left: -7px; + /* 3 */ +} + +/* + * 1. Corrects font size not being inherited in all browsers + * 2. Addresses margins set differently in IE6/7, FF3+, S5, Chrome + * 3. Improves appearance and consistency in all browsers + */ +button, +input, +select, +textarea { + font-size: 100%; + /* 1 */ + margin: 0; + /* 2 */ + vertical-align: baseline; + /* 3 */ + *vertical-align: middle; + /* 3 */ +} + +/* + * Addresses FF3/4 setting line-height on 'input' using !important in the UA stylesheet + */ +button, +input { + line-height: normal; + /* 1 */ +} + +/* + * 1. Improves usability and consistency of cursor style between image-type 'input' and others + * 2. Corrects inability to style clickable 'input' types in iOS + * 3. Removes inner spacing in IE7 without affecting normal text inputs + * Known issue: inner spacing remains in IE6 + */ +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + /* 1 */ + -webkit-appearance: button; + /* 2 */ + *overflow: visible; + /* 3 */ +} + +/* + * Re-set default cursor for disabled elements + */ +button[disabled], +input[disabled] { + cursor: default; +} + +/* + * 1. Addresses box sizing set to content-box in IE8/9 + * 2. Removes excess padding in IE8/9 + * 3. Removes excess padding in IE7 + Known issue: excess padding remains in IE6 + */ +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ + *height: 13px; + /* 3 */ + *width: 13px; + /* 3 */ +} + +/* + * 1. Addresses appearance set to searchfield in S5, Chrome + * 2. Addresses box-sizing set to border-box in S5, Chrome (include -moz to future-proof) + */ +input[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + /* 2 */ + box-sizing: content-box; +} + +/* + * Removes inner padding and search cancel button in S5, Chrome on OS X + */ +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +/* + * Removes inner padding and border in FF3+ + * www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/ + */ +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/* + * 1. Removes default vertical scrollbar in IE6/7/8/9 + * 2. Improves readability and alignment in all browsers + */ +textarea { + overflow: auto; + /* 1 */ + vertical-align: top; + /* 2 */ +} + +/* ============================================================================= + Tables + ========================================================================== */ +/* + * Remove most spacing between table cells + */ +table { + border-collapse: collapse; + border-spacing: 0; +} + +body { + padding: 0px 0 20px 0px; + margin: 0px; + font: 14px/1.5 "OpenSansRegular", "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #f0e7d5; + font-weight: normal; + background: #252525; + background-attachment: fixed !important; + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #2a2a29), color-stop(100%, #1c1c1c)); + background: -webkit-linear-gradient(#2a2a29, #1c1c1c); + background: -moz-linear-gradient(#2a2a29, #1c1c1c); + background: -o-linear-gradient(#2a2a29, #1c1c1c); + background: -ms-linear-gradient(#2a2a29, #1c1c1c); + background: linear-gradient(#2a2a29, #1c1c1c); +} + +h1, h2, h3, h4, h5, h6 { + color: #e8e8e8; + margin: 0 0 10px; + font-family: 'OpenSansRegular', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + font-size: 24px; +} + +h4, h5, h6 { + color: #e8e8e8; +} + +h3 { + font-size: 18px; + line-height: 24px; + font-family: 'OpenSansRegular', "Helvetica Neue", Helvetica, Arial, sans-serif !important; + font-weight: normal; + color: #b6b6b6; +} + +a { + color: #ffcc00; + font-weight: 400; + text-decoration: none; +} +a:hover { + color: #ffeb9b; +} + +a small { + font-size: 11px; + color: #666; + margin-top: -0.6em; + display: block; +} + +ul { + list-style-image: url("../images/bullet.png"); +} + +strong { + font-family: 'OpenSansBold', "Helvetica Neue", Helvetica, Arial, sans-serif !important; + font-weight: normal; +} + +.wrapper { + max-width: 650px; + margin: 0 auto; + position: relative; + padding: 0 20px; +} + +section img { + max-width: 100%; +} + +blockquote { + border-left: 3px solid #ffcc00; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code { + font-family: "Lucida Sans", Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #efefef; + font-size: 13px; + margin: 0 4px; + padding: 4px 6px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; +} + +pre { + padding: 8px 15px; + background: #191919; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; + border: 1px solid #121212; + -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3); + -o-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3); + overflow: auto; + overflow-y: hidden; +} +pre code { + color: #efefef; + text-shadow: 0px 1px 0px #000; + margin: 0; + padding: 0; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th { + text-align: left; + padding: 5px 10px; + border-bottom: 1px solid #434343; + color: #b6b6b6; + font-family: 'OpenSansSemibold', "Helvetica Neue", Helvetica, Arial, sans-serif !important; + font-weight: normal; +} + +td { + text-align: left; + padding: 5px 10px; + border-bottom: 1px solid #434343; +} + +hr { + border: 0; + outline: none; + height: 3px; + background: transparent url("../images/hr.gif") center center repeat-x; + margin: 0 0 20px; +} + +dt { + color: #F0E7D5; + font-family: 'OpenSansSemibold', "Helvetica Neue", Helvetica, Arial, sans-serif !important; + font-weight: normal; +} + +#header { + z-index: 100; + left: 0; + top: 0px; + height: 60px; + width: 100%; + position: fixed; + background: url(../images/nav-bg.gif) #353535; + border-bottom: 4px solid #434343; + -moz-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.25); + -webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.25); + -o-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.25); + box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.25); +} +#header nav { + max-width: 650px; + margin: 0 auto; + padding: 0 10px; + background: blue; + margin: 6px auto; +} +#header nav li { + font-family: 'OpenSansLight', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + list-style: none; + display: inline; + color: white; + line-height: 50px; + text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.2); + font-size: 14px; +} +#header nav li a { + color: white; + border: 1px solid #5d910b; + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #93bd20), color-stop(100%, #659e10)); + background: -webkit-linear-gradient(#93bd20, #659e10); + background: -moz-linear-gradient(#93bd20, #659e10); + background: -o-linear-gradient(#93bd20, #659e10); + background: -ms-linear-gradient(#93bd20, #659e10); + background: linear-gradient(#93bd20, #659e10); + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.3), 0px 3px 7px rgba(0, 0, 0, 0.7); + -webkit-box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.3), 0px 3px 7px rgba(0, 0, 0, 0.7); + -o-box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.3), 0px 3px 7px rgba(0, 0, 0, 0.7); + box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.3), 0px 3px 7px rgba(0, 0, 0, 0.7); + background-color: #93bd20; + padding: 10px 12px; + margin-top: 6px; + line-height: 14px; + font-size: 14px; + display: inline-block; + text-align: center; +} +#header nav li a:hover { + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #749619), color-stop(100%, #527f0e)); + background: -webkit-linear-gradient(#749619, #527f0e); + background: -moz-linear-gradient(#749619, #527f0e); + background: -o-linear-gradient(#749619, #527f0e); + background: -ms-linear-gradient(#749619, #527f0e); + background: linear-gradient(#749619, #527f0e); + background-color: #659e10; + border: 1px solid #527f0e; + -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.2), 0px 1px 0px rgba(0, 0, 0, 0); + -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.2), 0px 1px 0px rgba(0, 0, 0, 0); + -o-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.2), 0px 1px 0px rgba(0, 0, 0, 0); + box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.2), 0px 1px 0px rgba(0, 0, 0, 0); +} +#header nav li.fork { + float: left; + margin-left: 0px; +} +#header nav li.downloads { + float: right; + margin-left: 6px; +} +#header nav li.title { + float: right; + margin-right: 10px; + font-size: 11px; +} + +section { + max-width: 650px; + padding: 30px 0px 50px 0px; + margin: 20px 0; + margin-top: 70px; +} +section #title { + border: 0; + outline: none; + margin: 0 0 50px 0; + padding: 0 0 5px 0; +} +section #title h1 { + font-family: 'OpenSansLight', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + font-size: 40px; + text-align: center; + line-height: 36px; +} +section #title p { + color: #d7cfbe; + font-family: 'OpenSansLight', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + font-size: 18px; + text-align: center; +} +section #title .credits { + font-size: 11px; + font-family: 'OpenSansRegular', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: normal; + color: #696969; + margin-top: -10px; +} +section #title .credits.left { + float: left; +} +section #title .credits.right { + float: right; +} + +@media print, screen and (max-width: 720px) { + #title .credits { + display: block; + width: 100%; + line-height: 30px; + text-align: center; + } + #title .credits .left { + float: none; + display: block; + } + #title .credits .right { + float: none; + display: block; + } +} +@media print, screen and (max-width: 480px) { + #header { + margin-top: -20px; + } + + section { + margin-top: 40px; + } + + nav { + display: none; + } +}