├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── example-todo ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── co │ │ └── jasonwyatt │ │ └── squeakytodo │ │ ├── App.java │ │ ├── MainActivity.java │ │ ├── Todo.java │ │ └── event │ │ └── DeleteEvent.java │ └── res │ ├── drawable │ └── ic_add.xml │ ├── layout │ ├── activity_main.xml │ ├── content_main.xml │ └── todo_item.xml │ ├── menu │ ├── item_popup.xml │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── build.gradle └── src │ ├── androidTest │ └── java │ │ └── co │ │ └── jasonwyatt │ │ └── squeaky │ │ ├── BlobColumnTest.java │ │ ├── QueryTest.java │ │ ├── TableCreationTest.java │ │ ├── TableMigrationTest.java │ │ └── VersionsTableTest.java │ └── main │ ├── AndroidManifest.xml │ └── java │ └── co │ └── jasonwyatt │ └── squeaky │ ├── BlobValue.java │ ├── Database.java │ ├── DatabaseException.java │ ├── DatabaseHelper.java │ ├── Table.java │ └── util │ └── Logger.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | *.iml 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | build/ 7 | bin/ 8 | gen/ 9 | out/ 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jason Wyatt Feinstein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Squeaky for Android [![](https://jitpack.io/v/jasonwyatt/squeaky-android.svg)](https://jitpack.io/#jasonwyatt/squeaky-android) 2 | 3 | SQLite is simple and lightweight; it follows that managing SQLite databases on Android should be also. 4 | 5 | Squeaky strives to be a straightforward approach to creating, migrating, and accessing SQLite 6 | databases. 7 | 8 | ## Setup 9 | 10 | Add [jitpack.io](https://jitpack.io) to your root build.gradle at the end of repositories: 11 | 12 | ```groovy 13 | allprojects { 14 | repositories { 15 | ... 16 | maven { url "https://jitpack.io" } 17 | } 18 | } 19 | ``` 20 | 21 | Add Squeaky-Android as a dependency to your app's build.gradle: 22 | 23 | ```groovy 24 | dependencies { 25 | compile 'com.github.jasonwyatt:squeaky-android:1.2.0' 26 | } 27 | ``` 28 | 29 | ## Getting Started 30 | 31 | ### Define your Tables 32 | 33 | import co.jasonwyatt.squeaky.Table 34 | 35 | public class TodosTable extends Table { 36 | @Override 37 | public String getName() { 38 | return "todos"; 39 | } 40 | 41 | @Override 42 | public int getVersion() { 43 | return 1; 44 | } 45 | 46 | @Override 47 | public String[] getCreateTable() { 48 | return new String[] { 49 | "CREATE TABLE todos ("+ 50 | " name TEXT NOT NULL"+ 51 | " completed INTEGER NOT NULL DEFAULT 0"+ 52 | ")" 53 | }; 54 | } 55 | 56 | @Override 57 | public String[] getMigration(int nextVersion) { 58 | return new String[0]; 59 | } 60 | } 61 | 62 | ### Create your Database and add Tables to it 63 | 64 | // in your Application's or Activity's onCreate() method 65 | Database myDB = new Database(this, "todos_db"); 66 | 67 | myDb.addTable(new TodosTable()); 68 | myDb.prepare(); 69 | 70 | ### Use it! 71 | 72 | myDb.insert("INSERT INTO todos (name) VALUES (?)", "Learn how to use Squeaky"); 73 | myDb.insert("INSERT INTO todos (name, completed) VALUES (?, ?)", "Already done", 1); 74 | 75 | // query 76 | Cursor c = myDb.query("SELECT rowid, name, completed FROM todos"); 77 | while (c.moveToNext()) { 78 | // get values 79 | long rowid = c.getLong(0); 80 | String name = c.getString(1); 81 | boolean completed = c.getInt(2) == 1; 82 | } 83 | 84 | // in an OnClickListener, for example.. 85 | myDb.update("UPDATE todos SET completed = 1 WHERE rowid = ?", rowid); 86 | 87 | ### Migrate a Table 88 | 89 | Modify your Table definition class: 90 | 91 | import co.jasonwyatt.squeaky.Table 92 | 93 | public class TodosTable extends Table { 94 | @Override 95 | public String getName() { 96 | return "todos"; 97 | } 98 | 99 | @Override 100 | public int getVersion() { 101 | return 2; 102 | } 103 | 104 | @Override 105 | public String[] getCreateTable() { 106 | return new String[] { 107 | "CREATE TABLE todos ("+ 108 | " name TEXT NOT NULL"+ 109 | " completed INTEGER NOT NULL DEFAULT 0"+ 110 | " due_date INTEGER"+ 111 | ")" 112 | }; 113 | } 114 | 115 | @Override 116 | public String[] getMigration(int nextVersion) { 117 | if (nextVersion == 2) { 118 | return new String[] { 119 | "ALTER TABLE todos ADD COLUMN due_date INTEGER" 120 | }; 121 | } 122 | return new String[0]; 123 | } 124 | } 125 | 126 | That's it. Next time your database is prepared after adding the table definition, the table will be 127 | migrated for you! 128 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.1.4' 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | jcenter() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /example-todo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example-todo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | 6 | defaultConfig { 7 | applicationId "co.jasonwyatt.squeakytodo" 8 | minSdkVersion 16 9 | targetSdkVersion 27 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(dir: 'libs', include: ['*.jar']) 26 | implementation project(':library') 27 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | implementation 'com.android.support:appcompat-v7:27.1.1' 31 | implementation 'com.android.support:design:27.1.1' 32 | implementation 'com.yarolegovich:lovely-dialog:1.0.4' 33 | testImplementation 'junit:junit:4.12' 34 | } 35 | -------------------------------------------------------------------------------- /example-todo/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/jason/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /example-todo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /example-todo/src/main/java/co/jasonwyatt/squeakytodo/App.java: -------------------------------------------------------------------------------- 1 | package co.jasonwyatt.squeakytodo; 2 | 3 | import android.app.Application; 4 | 5 | import co.jasonwyatt.squeaky.Database; 6 | 7 | /** 8 | * @author jason 9 | */ 10 | 11 | public class App extends Application { 12 | private static App sInstance; 13 | private Database mDB; 14 | 15 | @Override 16 | public void onCreate() { 17 | super.onCreate(); 18 | 19 | mDB = new Database(App.this, "todos"); 20 | mDB.addTable(new Todo.Table()); 21 | mDB.prepare(); 22 | 23 | sInstance = this; 24 | } 25 | 26 | public Database getDB() { 27 | return mDB; 28 | } 29 | 30 | public static App getInstance() { 31 | return sInstance; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example-todo/src/main/java/co/jasonwyatt/squeakytodo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package co.jasonwyatt.squeakytodo; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.v4.app.LoaderManager; 6 | import android.support.v4.content.Loader; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.util.DiffUtil; 9 | import android.support.v7.widget.DividerItemDecoration; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.PopupMenu; 12 | import android.support.v7.widget.RecyclerView; 13 | import android.support.v7.widget.Toolbar; 14 | import android.view.LayoutInflater; 15 | import android.view.MenuItem; 16 | import android.view.MotionEvent; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | import android.widget.CheckBox; 20 | import android.widget.CompoundButton; 21 | import android.widget.TextView; 22 | 23 | import com.yarolegovich.lovelydialog.LovelyTextInputDialog; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | import java.util.Observable; 28 | import java.util.Observer; 29 | 30 | import co.jasonwyatt.squeakytodo.event.DeleteEvent; 31 | 32 | public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks>, Observer { 33 | 34 | private Adapter mAdapter; 35 | private static Observable sObservable = new Observable() { 36 | @Override 37 | public void notifyObservers(Object arg) { 38 | setChanged(); 39 | super.notifyObservers(arg); 40 | } 41 | 42 | @Override 43 | public synchronized boolean hasChanged() { 44 | return true; 45 | } 46 | }; 47 | 48 | @Override 49 | protected void onCreate(Bundle savedInstanceState) { 50 | super.onCreate(savedInstanceState); 51 | setContentView(R.layout.activity_main); 52 | 53 | getSupportLoaderManager().initLoader(R.id.todo_items_loader_id, null, this); 54 | 55 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 56 | setSupportActionBar(toolbar); 57 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 58 | fab.setOnClickListener(new View.OnClickListener() { 59 | @Override 60 | public void onClick(View view) { 61 | new LovelyTextInputDialog(view.getContext()) 62 | .setConfirmButton(R.string.save, new LovelyTextInputDialog.OnTextInputConfirmListener() { 63 | @Override 64 | public void onTextInputConfirmed(String text) { 65 | sObservable.notifyObservers(new Todo(text.trim())); 66 | } 67 | }) 68 | .show(); 69 | } 70 | }); 71 | 72 | RecyclerView rv = (RecyclerView) findViewById(R.id.content_main); 73 | rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); 74 | mAdapter = new Adapter(); 75 | rv.setAdapter(mAdapter); 76 | rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); 77 | } 78 | 79 | @Override 80 | protected void onResume() { 81 | super.onResume(); 82 | sObservable.addObserver(this); 83 | } 84 | 85 | @Override 86 | protected void onPause() { 87 | super.onPause(); 88 | sObservable.deleteObserver(this); 89 | } 90 | 91 | @Override 92 | public Loader> onCreateLoader(int id, Bundle args) { 93 | return new Todo.Loader(this); 94 | } 95 | 96 | @Override 97 | public void onLoadFinished(Loader> loader, List data) { 98 | mAdapter.setTodoItems(data); 99 | } 100 | 101 | @Override 102 | public void onLoaderReset(Loader> loader) { 103 | } 104 | 105 | @Override 106 | public void update(Observable observable, Object o) { 107 | if (o instanceof Todo) { 108 | new Todo.SaveTask(App.getInstance().getDB(), (Todo) o) { 109 | @Override 110 | protected void onPostExecute(List todos) { 111 | mAdapter.setTodoItems(todos); 112 | } 113 | }.execute(); 114 | } 115 | 116 | if (o instanceof DeleteEvent) { 117 | new Todo.DeleteTask(App.getInstance().getDB(), ((DeleteEvent) o).getItem()) { 118 | @Override 119 | protected void onPostExecute(List todos) { 120 | mAdapter.setTodoItems(todos); 121 | } 122 | }.execute(); 123 | } 124 | } 125 | 126 | private static class Adapter extends RecyclerView.Adapter { 127 | private List mTodoItems; 128 | 129 | Adapter() { 130 | mTodoItems = new ArrayList<>(0); 131 | } 132 | 133 | void setTodoItems(final List todoItems) { 134 | DiffUtil.DiffResult res = DiffUtil.calculateDiff(new DiffUtil.Callback() { 135 | @Override 136 | public int getOldListSize() { 137 | return mTodoItems.size(); 138 | } 139 | 140 | @Override 141 | public int getNewListSize() { 142 | return todoItems.size(); 143 | } 144 | 145 | @Override 146 | public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { 147 | return mTodoItems.get(oldItemPosition).getId() == todoItems.get(newItemPosition).getId(); 148 | } 149 | 150 | @Override 151 | public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { 152 | Todo oude = mTodoItems.get(oldItemPosition); 153 | Todo nieuw = todoItems.get(newItemPosition); 154 | 155 | boolean contentEquals = false; 156 | if (oude.getContent() == null && nieuw.getContent() == null) { 157 | contentEquals = true; 158 | } else if (oude.getContent() != null && nieuw.getContent() != null && oude.getContent().equals(nieuw.getContent())) { 159 | contentEquals = true; 160 | } 161 | 162 | boolean finishedEquals = false; 163 | if (oude.getFinishedDate() == null && nieuw.getFinishedDate() == null) { 164 | finishedEquals = true; 165 | } else if (oude.getFinishedDate() != null && nieuw.getFinishedDate() != null && oude.getFinishedDate().equals(nieuw.getFinishedDate())) { 166 | finishedEquals = true; 167 | } 168 | 169 | return contentEquals && finishedEquals; 170 | } 171 | }); 172 | mTodoItems = todoItems; 173 | res.dispatchUpdatesTo(this); 174 | } 175 | 176 | @Override 177 | public TodoHolder onCreateViewHolder(ViewGroup parent, int viewType) { 178 | LayoutInflater inf = LayoutInflater.from(parent.getContext()); 179 | return new TodoHolder(inf, parent); 180 | } 181 | 182 | @Override 183 | public void onBindViewHolder(TodoHolder holder, int position) { 184 | holder.bind(mTodoItems.get(position)); 185 | } 186 | 187 | @Override 188 | public int getItemCount() { 189 | return mTodoItems.size(); 190 | } 191 | } 192 | 193 | private static class TodoHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener, CompoundButton.OnCheckedChangeListener { 194 | private final CheckBox mCheckbox; 195 | private final TextView mContent; 196 | private Todo mItem; 197 | 198 | TodoHolder(LayoutInflater inf, ViewGroup parent) { 199 | super(inf.inflate(R.layout.todo_item, parent, false)); 200 | 201 | mCheckbox = (CheckBox) itemView.findViewById(R.id.todo_finished); 202 | mContent = (TextView) itemView.findViewById(R.id.todo_content); 203 | itemView.setOnClickListener(this); 204 | itemView.setOnLongClickListener(this); 205 | 206 | mCheckbox.setOnCheckedChangeListener(this); 207 | } 208 | 209 | void bind(Todo item) { 210 | mItem = item; 211 | mCheckbox.setChecked(item.getFinishedDate() != null); 212 | mContent.setText(item.getContent()); 213 | } 214 | 215 | @Override 216 | public void onClick(View view) { 217 | if (view == itemView) { 218 | mCheckbox.toggle(); 219 | } 220 | } 221 | 222 | @Override 223 | public boolean onLongClick(View view) { 224 | PopupMenu menu = new PopupMenu(view.getContext(), view); 225 | menu.inflate(R.menu.item_popup); 226 | menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 227 | @Override 228 | public boolean onMenuItemClick(MenuItem item) { 229 | if (item.getItemId() == R.id.delete) { 230 | sObservable.notifyObservers(new DeleteEvent(mItem)); 231 | } 232 | return false; 233 | } 234 | }); 235 | menu.show(); 236 | return true; 237 | } 238 | 239 | @Override 240 | public void onCheckedChanged(CompoundButton view, boolean checked) { 241 | mItem.setFinishedDate(checked ? System.currentTimeMillis() : null); 242 | MainActivity.sObservable.notifyObservers(mItem); 243 | } 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /example-todo/src/main/java/co/jasonwyatt/squeakytodo/Todo.java: -------------------------------------------------------------------------------- 1 | package co.jasonwyatt.squeakytodo; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.os.AsyncTask; 6 | import android.support.annotation.WorkerThread; 7 | import android.support.v4.content.AsyncTaskLoader; 8 | 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | import co.jasonwyatt.squeaky.Database; 13 | 14 | /** 15 | * @author jason 16 | */ 17 | 18 | public class Todo { 19 | private final long mCreateDate; 20 | private final String mContent; 21 | private Long mFinishedDate; 22 | private final int mId; 23 | 24 | public Todo(int id, long createDate, String content, Long finishedDate) { 25 | mId = id; 26 | mCreateDate = createDate; 27 | mContent = content; 28 | mFinishedDate = finishedDate; 29 | } 30 | 31 | public Todo(String s) { 32 | mId = -1; 33 | mCreateDate = System.currentTimeMillis(); 34 | mContent = s; 35 | mFinishedDate = null; 36 | } 37 | 38 | public int getId() { 39 | return mId; 40 | } 41 | 42 | public long getCreateDate() { 43 | return mCreateDate; 44 | } 45 | 46 | public String getContent() { 47 | return mContent; 48 | } 49 | 50 | public Long getFinishedDate() { 51 | return mFinishedDate; 52 | } 53 | 54 | public void setFinishedDate(Long date) { 55 | mFinishedDate = date; 56 | } 57 | 58 | @SuppressWarnings("WeakerAccess") 59 | @WorkerThread 60 | public static void saveTodo(Database db, Todo todo) { 61 | if (todo.getId() >= 0) { 62 | db.update("UPDATE todos SET create_date = ?, content = ?, finished_date = ? WHERE rowid = ?", todo.getCreateDate(), todo.getContent(), todo.getFinishedDate(), todo.getId()); 63 | } else { 64 | db.insert("INSERT INTO todos (create_date, content) VALUES (?, ?)", todo.getCreateDate(), todo.getContent()); 65 | } 66 | } 67 | 68 | @SuppressWarnings("WeakerAccess") 69 | @WorkerThread 70 | public static List getTodos(Database db) { 71 | List todos = new LinkedList<>(); 72 | 73 | Cursor c = db.query("SELECT rowid, create_date, content, finished_date, case when finished_date IS NULL then 0 else 1 end AS is_finished FROM todos ORDER BY is_finished ASC, finished_date DESC, create_date ASC"); 74 | try { 75 | while (c.moveToNext()) { 76 | todos.add(new Todo(c.getInt(0), c.getLong(1), c.getString(2), c.isNull(3) ? null : c.getLong(3))); 77 | } 78 | } finally { 79 | c.close(); 80 | } 81 | 82 | return todos; 83 | } 84 | 85 | @SuppressWarnings("WeakerAccess") 86 | @WorkerThread 87 | public static void deleteTodo(Database db, Todo todo) { 88 | if (todo.getId() >= 0) { 89 | db.update("DELETE FROM todos WHERE rowid = ?", todo.getId()); 90 | } 91 | } 92 | 93 | static class SaveTask extends AsyncTask> { 94 | private final Database mDB; 95 | private final Todo mTodo; 96 | 97 | SaveTask(Database db, Todo todo) { 98 | mDB = db; 99 | mTodo = todo; 100 | } 101 | 102 | @Override 103 | protected List doInBackground(Void... voids) { 104 | saveTodo(mDB, mTodo); 105 | return getTodos(mDB); 106 | } 107 | } 108 | 109 | static class DeleteTask extends AsyncTask> { 110 | private final Database mDB; 111 | private final Todo mTodo; 112 | 113 | DeleteTask(Database db, Todo todo) { 114 | mDB = db; 115 | mTodo = todo; 116 | } 117 | 118 | @Override 119 | protected List doInBackground(Void... voids) { 120 | deleteTodo(mDB, mTodo); 121 | return getTodos(mDB); 122 | } 123 | } 124 | 125 | static class Table extends co.jasonwyatt.squeaky.Table { 126 | private static final String NAME = "todos"; 127 | 128 | @Override 129 | public String getName() { 130 | return NAME; 131 | } 132 | 133 | @Override 134 | public int getVersion() { 135 | return 1; 136 | } 137 | 138 | @Override 139 | public String[] getCreateTable() { 140 | return new String[] { 141 | "CREATE TABLE todos (" + 142 | "create_date INTEGER NOT NULL," + 143 | "content TEXT NOT NULL," + 144 | "finished_date INTEGER" + 145 | ")", 146 | "INSERT INTO todos (create_date, content) VALUES ("+System.currentTimeMillis()+", 'Try creating a new todo item..'), ("+System.currentTimeMillis()+", 'Use Squeaky in my app.')" 147 | }; 148 | } 149 | 150 | @Override 151 | public String[] getMigration(int nextVersion) { 152 | return new String[0]; 153 | } 154 | } 155 | 156 | static class Loader extends AsyncTaskLoader> { 157 | Loader(Context context) { 158 | super(context); 159 | } 160 | 161 | @Override 162 | public List loadInBackground() { 163 | return Todo.getTodos(App.getInstance().getDB()); 164 | } 165 | 166 | @Override 167 | protected void onStartLoading() { 168 | forceLoad(); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /example-todo/src/main/java/co/jasonwyatt/squeakytodo/event/DeleteEvent.java: -------------------------------------------------------------------------------- 1 | package co.jasonwyatt.squeakytodo.event; 2 | 3 | import co.jasonwyatt.squeakytodo.Todo; 4 | 5 | /** 6 | * @author jason 7 | */ 8 | public class DeleteEvent { 9 | private final Todo mItem; 10 | 11 | public DeleteEvent(Todo item) { 12 | mItem = item; 13 | } 14 | 15 | public Todo getItem() { 16 | return mItem; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example-todo/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /example-todo/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example-todo/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | -------------------------------------------------------------------------------- /example-todo/src/main/res/layout/todo_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 18 | 31 | -------------------------------------------------------------------------------- /example-todo/src/main/res/menu/item_popup.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /example-todo/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /example-todo/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonwyatt/Squeaky-Android/5dbc23063133985ecc3a776d1851ee945623dc77/example-todo/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-todo/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonwyatt/Squeaky-Android/5dbc23063133985ecc3a776d1851ee945623dc77/example-todo/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-todo/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonwyatt/Squeaky-Android/5dbc23063133985ecc3a776d1851ee945623dc77/example-todo/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-todo/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonwyatt/Squeaky-Android/5dbc23063133985ecc3a776d1851ee945623dc77/example-todo/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-todo/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonwyatt/Squeaky-Android/5dbc23063133985ecc3a776d1851ee945623dc77/example-todo/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-todo/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /example-todo/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /example-todo/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #555555 7 | 8 | -------------------------------------------------------------------------------- /example-todo/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /example-todo/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /example-todo/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Squeaky ToDo 3 | Settings 4 | Save 5 | Delete 6 | 7 | -------------------------------------------------------------------------------- /example-todo/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 14 |