├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── codingwithmitch │ │ └── notes │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── codingwithmitch │ │ │ └── notes │ │ │ ├── LinedEditText.java │ │ │ ├── NoteActivity.java │ │ │ ├── NotesListActivity.java │ │ │ ├── adapters │ │ │ └── NotesRecyclerAdapter.java │ │ │ ├── async │ │ │ ├── DeleteAsyncTask.java │ │ │ ├── InsertAsyncTask.java │ │ │ └── UpdateAsyncTask.java │ │ │ ├── models │ │ │ └── Note.java │ │ │ ├── persistence │ │ │ ├── NoteDao.java │ │ │ ├── NoteDatabase.java │ │ │ └── NoteRepository.java │ │ │ └── util │ │ │ ├── Utility.java │ │ │ └── VerticalSpacingItemDecorator.java │ └── res │ │ ├── drawable-v24 │ │ ├── ic_add_black_24dp.xml │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_arrow_back_black_24dp.xml │ │ ├── ic_check_black_24dp.xml │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_note.xml │ │ ├── activity_notes_list.xml │ │ ├── layout_note_list_item.xml │ │ └── layout_note_toolbar.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── codingwithmitch │ └── notes │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Android SQLite for Beginners 2019

4 |

Watch the app demo.

5 | 6 |

In this course I teach you the best practice way to interact with an SQLite database locally on the android device. The room persistence library was designed to simplify interactions with SQLite on the device.

7 | 8 |

This course is ideal for beginners. If you have absolutely zero experience programming on android, or even programming in general, this is the course for you.

9 | 10 |

Here's what you will see in the course:

11 | 34 |
35 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.codingwithmitch.notes" 7 | minSdkVersion 23 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:28.0.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 28 | 29 | def room_version = "1.1.1" 30 | implementation "android.arch.persistence.room:runtime:$room_version" 31 | annotationProcessor "android.arch.persistence.room:compiler:$room_version" 32 | 33 | //RecyclerView 34 | implementation 'com.android.support:recyclerview-v7:28.0.0' 35 | 36 | //Support Design (toolbars) 37 | implementation 'com.android.support:design:28.0.0' 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/codingwithmitch/notes/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.codingwithmitch.notes", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/LinedEditText.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | 10 | public class LinedEditText extends android.support.v7.widget.AppCompatEditText { 11 | 12 | private static final String TAG = "LinedEditText"; 13 | 14 | private Rect mRect; 15 | private Paint mPaint; 16 | 17 | 18 | // we need this constructor for LayoutInflater 19 | public LinedEditText(Context context, AttributeSet attrs) { 20 | super(context, attrs); 21 | 22 | mRect = new Rect(); 23 | mPaint = new Paint(); 24 | mPaint.setStyle(Paint.Style.STROKE); 25 | mPaint.setStrokeWidth(2); 26 | mPaint.setColor(0xFFFFD966); // Color of the lines on paper 27 | 28 | } 29 | 30 | @Override 31 | protected void onDraw(Canvas canvas) { 32 | 33 | // get the height of the view 34 | int height = ((View)this.getParent()).getHeight(); 35 | 36 | int lineHeight = getLineHeight(); 37 | int numberOfLines = height / lineHeight; 38 | 39 | Rect r = mRect; 40 | Paint paint = mPaint; 41 | 42 | int baseline = getLineBounds(0, r); 43 | 44 | for (int i = 0; i < numberOfLines; i++) { 45 | 46 | canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint); 47 | 48 | baseline += lineHeight; 49 | } 50 | 51 | super.onDraw(canvas); 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/NoteActivity.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.text.Editable; 6 | import android.text.TextWatcher; 7 | import android.util.Log; 8 | import android.view.GestureDetector; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.widget.EditText; 12 | import android.widget.ImageButton; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.codingwithmitch.notes.models.Note; 17 | import com.codingwithmitch.notes.persistence.NoteRepository; 18 | import com.codingwithmitch.notes.util.Utility; 19 | 20 | public class NoteActivity extends AppCompatActivity implements 21 | View.OnTouchListener, 22 | GestureDetector.OnGestureListener, 23 | GestureDetector.OnDoubleTapListener, 24 | View.OnClickListener, 25 | TextWatcher 26 | { 27 | 28 | private static final String TAG = "NoteActivity"; 29 | private static final int EDIT_MODE_ENABLED = 1; 30 | private static final int EDIT_MODE_DISABLED = 0; 31 | 32 | // UI components 33 | private LinedEditText mLinedEditText; 34 | private EditText mEditTitle; 35 | private TextView mViewTitle; 36 | private RelativeLayout mCheckContainer, mBackArrowContainer; 37 | private ImageButton mCheck, mBackArrow; 38 | 39 | 40 | // vars 41 | private boolean mIsNewNote; 42 | private Note mNoteInitial; 43 | private GestureDetector mGestureDetector; 44 | private int mMode; 45 | private NoteRepository mNoteRepository; 46 | private Note mNoteFinal; 47 | 48 | 49 | @Override 50 | protected void onCreate(Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | setContentView(R.layout.activity_note); 53 | mLinedEditText = findViewById(R.id.note_text); 54 | mEditTitle = findViewById(R.id.note_edit_title); 55 | mViewTitle = findViewById(R.id.note_text_title); 56 | mCheck = findViewById(R.id.toolbar_check); 57 | mBackArrow = findViewById(R.id.toolbar_back_arrow); 58 | mCheckContainer = findViewById(R.id.check_container); 59 | mBackArrowContainer = findViewById(R.id.back_arrow_container); 60 | 61 | mNoteRepository = new NoteRepository(this); 62 | 63 | setListeners(); 64 | 65 | if(getIncomingIntent()){ 66 | setNewNoteProperties(); 67 | enableEditMode(); 68 | } 69 | else{ 70 | setNoteProperties(); 71 | disableContentInteraction(); 72 | } 73 | } 74 | 75 | private void saveChanges(){ 76 | if(mIsNewNote){ 77 | saveNewNote(); 78 | }else{ 79 | updateNote(); 80 | } 81 | } 82 | 83 | public void updateNote() { 84 | mNoteRepository.updateNoteTask(mNoteFinal); 85 | } 86 | 87 | public void saveNewNote() { 88 | mNoteRepository.insertNoteTask(mNoteFinal); 89 | } 90 | 91 | private void setListeners(){ 92 | mGestureDetector = new GestureDetector(this, this); 93 | mLinedEditText.setOnTouchListener(this); 94 | mCheck.setOnClickListener(this); 95 | mViewTitle.setOnClickListener(this); 96 | mBackArrow.setOnClickListener(this); 97 | mEditTitle.addTextChangedListener(this); 98 | } 99 | 100 | private boolean getIncomingIntent(){ 101 | if(getIntent().hasExtra("selected_note")){ 102 | mNoteInitial = getIntent().getParcelableExtra("selected_note"); 103 | 104 | mNoteFinal = new Note(); 105 | mNoteFinal.setTitle(mNoteInitial.getTitle()); 106 | mNoteFinal.setContent(mNoteInitial.getContent()); 107 | mNoteFinal.setTimestamp(mNoteInitial.getTimestamp()); 108 | mNoteFinal.setId(mNoteInitial.getId()); 109 | 110 | mMode = EDIT_MODE_ENABLED; 111 | mIsNewNote = false; 112 | return false; 113 | } 114 | mMode = EDIT_MODE_ENABLED; 115 | mIsNewNote = true; 116 | return true; 117 | } 118 | 119 | private void disableContentInteraction(){ 120 | mLinedEditText.setKeyListener(null); 121 | mLinedEditText.setFocusable(false); 122 | mLinedEditText.setFocusableInTouchMode(false); 123 | mLinedEditText.setCursorVisible(false); 124 | mLinedEditText.clearFocus(); 125 | } 126 | 127 | private void enableContentInteraction(){ 128 | mLinedEditText.setKeyListener(new EditText(this).getKeyListener()); 129 | mLinedEditText.setFocusable(true); 130 | mLinedEditText.setFocusableInTouchMode(true); 131 | mLinedEditText.setCursorVisible(true); 132 | mLinedEditText.requestFocus(); 133 | } 134 | 135 | private void enableEditMode(){ 136 | mBackArrowContainer.setVisibility(View.GONE); 137 | mCheckContainer.setVisibility(View.VISIBLE); 138 | 139 | mViewTitle.setVisibility(View.GONE); 140 | mEditTitle.setVisibility(View.VISIBLE); 141 | 142 | mMode = EDIT_MODE_ENABLED; 143 | 144 | enableContentInteraction(); 145 | } 146 | 147 | private void disableEditMode(){ 148 | Log.d(TAG, "disableEditMode: called."); 149 | mBackArrowContainer.setVisibility(View.VISIBLE); 150 | mCheckContainer.setVisibility(View.GONE); 151 | 152 | mViewTitle.setVisibility(View.VISIBLE); 153 | mEditTitle.setVisibility(View.GONE); 154 | 155 | mMode = EDIT_MODE_DISABLED; 156 | 157 | disableContentInteraction(); 158 | 159 | // Check if they typed anything into the note. Don't want to save an empty note. 160 | String temp = mLinedEditText.getText().toString(); 161 | temp = temp.replace("\n", ""); 162 | temp = temp.replace(" ", ""); 163 | if(temp.length() > 0){ 164 | mNoteFinal.setTitle(mEditTitle.getText().toString()); 165 | mNoteFinal.setContent(mLinedEditText.getText().toString()); 166 | String timestamp = Utility.getCurrentTimeStamp(); 167 | mNoteFinal.setTimestamp(timestamp); 168 | 169 | Log.d(TAG, "disableEditMode: initial: " + mNoteInitial.toString()); 170 | Log.d(TAG, "disableEditMode: final: " + mNoteFinal.toString()); 171 | 172 | // If the note was altered, save it. 173 | if(!mNoteFinal.getContent().equals(mNoteInitial.getContent()) 174 | || !mNoteFinal.getTitle().equals(mNoteInitial.getTitle())){ 175 | Log.d(TAG, "disableEditMode: called?"); 176 | saveChanges(); 177 | } 178 | } 179 | } 180 | 181 | private void setNewNoteProperties(){ 182 | mViewTitle.setText("Note Title"); 183 | mEditTitle.setText("Note Title"); 184 | 185 | mNoteFinal = new Note(); 186 | mNoteInitial = new Note(); 187 | mNoteInitial.setTitle("Note Title"); 188 | } 189 | 190 | private void setNoteProperties(){ 191 | mViewTitle.setText(mNoteInitial.getTitle()); 192 | mEditTitle.setText(mNoteInitial.getTitle()); 193 | mLinedEditText.setText(mNoteInitial.getContent()); 194 | } 195 | 196 | @Override 197 | public boolean onTouch(View view, MotionEvent motionEvent) { 198 | return mGestureDetector.onTouchEvent(motionEvent); 199 | } 200 | 201 | @Override 202 | public boolean onSingleTapConfirmed(MotionEvent motionEvent) { 203 | return false; 204 | } 205 | 206 | @Override 207 | public boolean onDoubleTap(MotionEvent motionEvent) { 208 | Log.d(TAG, "onDoubleTap: double tapped."); 209 | enableEditMode(); 210 | return false; 211 | } 212 | 213 | @Override 214 | public boolean onDoubleTapEvent(MotionEvent motionEvent) { 215 | return false; 216 | } 217 | 218 | @Override 219 | public boolean onDown(MotionEvent motionEvent) { 220 | return false; 221 | } 222 | 223 | @Override 224 | public void onShowPress(MotionEvent motionEvent) { 225 | 226 | } 227 | 228 | @Override 229 | public boolean onSingleTapUp(MotionEvent motionEvent) { 230 | return false; 231 | } 232 | 233 | @Override 234 | public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { 235 | return false; 236 | } 237 | 238 | @Override 239 | public void onLongPress(MotionEvent motionEvent) { 240 | 241 | } 242 | 243 | @Override 244 | public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { 245 | return false; 246 | } 247 | 248 | @Override 249 | public void onClick(View view) { 250 | switch (view.getId()){ 251 | case R.id.toolbar_back_arrow:{ 252 | finish(); 253 | break; 254 | } 255 | case R.id.toolbar_check:{ 256 | disableEditMode(); 257 | break; 258 | } 259 | case R.id.note_text_title:{ 260 | enableEditMode(); 261 | mEditTitle.requestFocus(); 262 | mEditTitle.setSelection(mEditTitle.length()); 263 | break; 264 | } 265 | } 266 | } 267 | 268 | @Override 269 | public void onBackPressed() { 270 | if(mMode == EDIT_MODE_ENABLED){ 271 | onClick(mCheck); 272 | } 273 | else{ 274 | super.onBackPressed(); 275 | } 276 | } 277 | 278 | @Override 279 | protected void onSaveInstanceState(Bundle outState) { 280 | super.onSaveInstanceState(outState); 281 | outState.putInt("mode", mMode); 282 | } 283 | 284 | @Override 285 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 286 | super.onRestoreInstanceState(savedInstanceState); 287 | mMode = savedInstanceState.getInt("mode"); 288 | if(mMode == EDIT_MODE_ENABLED){ 289 | enableEditMode(); 290 | } 291 | } 292 | 293 | @Override 294 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 295 | 296 | } 297 | 298 | @Override 299 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 300 | mViewTitle.setText(charSequence.toString()); 301 | } 302 | 303 | @Override 304 | public void afterTextChanged(Editable editable) { 305 | 306 | } 307 | } 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/NotesListActivity.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes; 2 | 3 | import android.arch.lifecycle.Observer; 4 | import android.content.Intent; 5 | import android.support.annotation.Nullable; 6 | import android.support.design.widget.FloatingActionButton; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.os.Bundle; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.support.v7.widget.Toolbar; 12 | import android.support.v7.widget.helper.ItemTouchHelper; 13 | import android.util.Log; 14 | import android.view.View; 15 | 16 | import com.codingwithmitch.notes.adapters.NotesRecyclerAdapter; 17 | import com.codingwithmitch.notes.models.Note; 18 | import com.codingwithmitch.notes.persistence.NoteRepository; 19 | import com.codingwithmitch.notes.util.VerticalSpacingItemDecorator; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class NotesListActivity extends AppCompatActivity implements 25 | NotesRecyclerAdapter.OnNoteListener, 26 | FloatingActionButton.OnClickListener 27 | { 28 | 29 | private static final String TAG = "NotesListActivity"; 30 | 31 | // ui components 32 | private RecyclerView mRecyclerView; 33 | 34 | // vars 35 | private ArrayList mNotes = new ArrayList<>(); 36 | private NotesRecyclerAdapter mNoteRecyclerAdapter; 37 | private NoteRepository mNoteRepository; 38 | 39 | 40 | @Override 41 | protected void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.activity_notes_list); 44 | mRecyclerView = findViewById(R.id.recyclerView); 45 | 46 | findViewById(R.id.fab).setOnClickListener(this); 47 | 48 | initRecyclerView(); 49 | mNoteRepository = new NoteRepository(this); 50 | retrieveNotes(); 51 | // insertFakeNotes(); 52 | 53 | setSupportActionBar((Toolbar)findViewById(R.id.notes_toolbar)); 54 | setTitle("Notes"); 55 | } 56 | 57 | 58 | private void retrieveNotes() { 59 | mNoteRepository.retrieveNotesTask().observe(this, new Observer>() { 60 | @Override 61 | public void onChanged(@Nullable List notes) { 62 | if(mNotes.size() > 0){ 63 | mNotes.clear(); 64 | } 65 | if(notes != null){ 66 | mNotes.addAll(notes); 67 | } 68 | mNoteRecyclerAdapter.notifyDataSetChanged(); 69 | } 70 | }); 71 | } 72 | 73 | private void insertFakeNotes(){ 74 | for(int i = 0; i < 1000; i++){ 75 | Note note = new Note(); 76 | note.setTitle("title #" + i); 77 | note.setContent("content #: " + i); 78 | note.setTimestamp("Jan 2019"); 79 | mNotes.add(note); 80 | } 81 | mNoteRecyclerAdapter.notifyDataSetChanged(); 82 | } 83 | 84 | private void initRecyclerView(){ 85 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); 86 | mRecyclerView.setLayoutManager(linearLayoutManager); 87 | VerticalSpacingItemDecorator itemDecorator = new VerticalSpacingItemDecorator(10); 88 | mRecyclerView.addItemDecoration(itemDecorator); 89 | new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(mRecyclerView); 90 | mNoteRecyclerAdapter = new NotesRecyclerAdapter(mNotes, this); 91 | mRecyclerView.setAdapter(mNoteRecyclerAdapter); 92 | } 93 | 94 | 95 | @Override 96 | public void onNoteClick(int position) { 97 | Intent intent = new Intent(this, NoteActivity.class); 98 | intent.putExtra("selected_note", mNotes.get(position)); 99 | startActivity(intent); 100 | } 101 | 102 | @Override 103 | public void onClick(View view) { 104 | Intent intent = new Intent(this, NoteActivity.class); 105 | startActivity(intent); 106 | } 107 | 108 | private void deleteNote(Note note) { 109 | mNotes.remove(note); 110 | mNoteRecyclerAdapter.notifyDataSetChanged(); 111 | 112 | mNoteRepository.deleteNoteTask(note); 113 | } 114 | 115 | ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) { 116 | @Override 117 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 118 | return false; 119 | } 120 | 121 | @Override 122 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 123 | deleteNote(mNotes.get(viewHolder.getAdapterPosition())); 124 | } 125 | }; 126 | } 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/adapters/NotesRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.adapters; 2 | 3 | 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.codingwithmitch.notes.R; 13 | import com.codingwithmitch.notes.models.Note; 14 | import com.codingwithmitch.notes.util.Utility; 15 | 16 | 17 | import java.util.ArrayList; 18 | 19 | public class NotesRecyclerAdapter extends RecyclerView.Adapter { 20 | 21 | private static final String TAG = "NotesRecyclerAdapter"; 22 | 23 | private ArrayList mNotes = new ArrayList<>(); 24 | private OnNoteListener mOnNoteListener; 25 | 26 | public NotesRecyclerAdapter(ArrayList mNotes, OnNoteListener onNoteListener) { 27 | this.mNotes = mNotes; 28 | this.mOnNoteListener = onNoteListener; 29 | } 30 | 31 | @NonNull 32 | @Override 33 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 34 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_note_list_item, parent, false); 35 | return new ViewHolder(view, mOnNoteListener); 36 | } 37 | 38 | @Override 39 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 40 | 41 | try{ 42 | String month = mNotes.get(position).getTimestamp().substring(0, 2); 43 | month = Utility.getMonthFromNumber(month); 44 | String year = mNotes.get(position).getTimestamp().substring(3); 45 | String timestamp = month + " " + year; 46 | holder.timestamp.setText(timestamp); 47 | holder.title.setText(mNotes.get(position).getTitle()); 48 | }catch (NullPointerException e){ 49 | Log.e(TAG, "onBindViewHolder: Null Pointer: " + e.getMessage() ); 50 | } 51 | } 52 | 53 | @Override 54 | public int getItemCount() { 55 | return mNotes.size(); 56 | } 57 | 58 | public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 59 | 60 | TextView timestamp, title; 61 | OnNoteListener mOnNoteListener; 62 | 63 | public ViewHolder(View itemView, OnNoteListener onNoteListener) { 64 | super(itemView); 65 | timestamp = itemView.findViewById(R.id.note_timestamp); 66 | title = itemView.findViewById(R.id.note_title); 67 | mOnNoteListener = onNoteListener; 68 | 69 | itemView.setOnClickListener(this); 70 | } 71 | 72 | @Override 73 | public void onClick(View view) { 74 | Log.d(TAG, "onClick: " + getAdapterPosition()); 75 | mOnNoteListener.onNoteClick(getAdapterPosition()); 76 | } 77 | } 78 | 79 | public interface OnNoteListener{ 80 | void onNoteClick(int position); 81 | } 82 | } 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/async/DeleteAsyncTask.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.async; 2 | 3 | import android.os.AsyncTask; 4 | 5 | import com.codingwithmitch.notes.models.Note; 6 | import com.codingwithmitch.notes.persistence.NoteDao; 7 | 8 | public class DeleteAsyncTask extends AsyncTask { 9 | 10 | private NoteDao mNoteDao; 11 | 12 | public DeleteAsyncTask(NoteDao dao) { 13 | mNoteDao = dao; 14 | } 15 | 16 | @Override 17 | protected Void doInBackground(Note... notes) { 18 | mNoteDao.delete(notes); 19 | return null; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/async/InsertAsyncTask.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.async; 2 | 3 | import android.os.AsyncTask; 4 | 5 | import com.codingwithmitch.notes.models.Note; 6 | import com.codingwithmitch.notes.persistence.NoteDao; 7 | 8 | public class InsertAsyncTask extends AsyncTask { 9 | 10 | private NoteDao mNoteDao; 11 | 12 | public InsertAsyncTask(NoteDao dao) { 13 | mNoteDao = dao; 14 | } 15 | 16 | @Override 17 | protected Void doInBackground(Note... notes) { 18 | mNoteDao.insertNotes(notes); 19 | return null; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/async/UpdateAsyncTask.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.async; 2 | 3 | import android.os.AsyncTask; 4 | 5 | import com.codingwithmitch.notes.models.Note; 6 | import com.codingwithmitch.notes.persistence.NoteDao; 7 | 8 | public class UpdateAsyncTask extends AsyncTask { 9 | 10 | private NoteDao mNoteDao; 11 | 12 | public UpdateAsyncTask(NoteDao dao) { 13 | mNoteDao = dao; 14 | } 15 | 16 | @Override 17 | protected Void doInBackground(Note... notes) { 18 | mNoteDao.updateNotes(notes); 19 | return null; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/models/Note.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.models; 2 | 3 | import android.arch.persistence.room.ColumnInfo; 4 | import android.arch.persistence.room.Entity; 5 | import android.arch.persistence.room.Ignore; 6 | import android.arch.persistence.room.PrimaryKey; 7 | import android.os.Parcel; 8 | import android.os.Parcelable; 9 | 10 | @Entity(tableName = "notes") 11 | public class Note implements Parcelable { 12 | 13 | @PrimaryKey(autoGenerate = true) 14 | private int id; 15 | 16 | @ColumnInfo(name = "title") 17 | private String title; 18 | 19 | @ColumnInfo(name = "content") 20 | private String content; 21 | 22 | @ColumnInfo(name = "timestamp") 23 | private String timestamp; 24 | 25 | public Note(String title, String content, String timestamp) { 26 | this.title = title; 27 | this.content = content; 28 | this.timestamp = timestamp; 29 | } 30 | 31 | @Ignore 32 | public Note() { 33 | 34 | } 35 | 36 | 37 | protected Note(Parcel in) { 38 | id = in.readInt(); 39 | title = in.readString(); 40 | content = in.readString(); 41 | timestamp = in.readString(); 42 | } 43 | 44 | public static final Creator CREATOR = new Creator() { 45 | @Override 46 | public Note createFromParcel(Parcel in) { 47 | return new Note(in); 48 | } 49 | 50 | @Override 51 | public Note[] newArray(int size) { 52 | return new Note[size]; 53 | } 54 | }; 55 | 56 | public int getId() { 57 | return id; 58 | } 59 | 60 | public void setId(int id) { 61 | this.id = id; 62 | } 63 | 64 | public String getTitle() { 65 | return title; 66 | } 67 | 68 | public void setTitle(String title) { 69 | this.title = title; 70 | } 71 | 72 | public String getContent() { 73 | return content; 74 | } 75 | 76 | public void setContent(String content) { 77 | this.content = content; 78 | } 79 | 80 | public String getTimestamp() { 81 | return timestamp; 82 | } 83 | 84 | public void setTimestamp(String timestamp) { 85 | this.timestamp = timestamp; 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | return "Note{" + 91 | "title='" + title + '\'' + 92 | ", content='" + content + '\'' + 93 | ", timestamp='" + timestamp + '\'' + 94 | '}'; 95 | } 96 | 97 | 98 | @Override 99 | public int describeContents() { 100 | return 0; 101 | } 102 | 103 | @Override 104 | public void writeToParcel(Parcel parcel, int i) { 105 | parcel.writeInt(id); 106 | parcel.writeString(title); 107 | parcel.writeString(content); 108 | parcel.writeString(timestamp); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/persistence/NoteDao.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.persistence; 2 | 3 | import android.arch.lifecycle.LiveData; 4 | import android.arch.persistence.room.Dao; 5 | import android.arch.persistence.room.Delete; 6 | import android.arch.persistence.room.Insert; 7 | import android.arch.persistence.room.Query; 8 | import android.arch.persistence.room.Update; 9 | 10 | import com.codingwithmitch.notes.models.Note; 11 | 12 | import java.util.List; 13 | 14 | @Dao 15 | public interface NoteDao { 16 | 17 | @Insert 18 | long[] insertNotes(Note... notes); 19 | 20 | @Query("SELECT * FROM notes") 21 | LiveData> getNotes(); 22 | 23 | @Delete 24 | int delete(Note... notes); 25 | 26 | @Update 27 | int updateNotes(Note... notes); 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/persistence/NoteDatabase.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.persistence; 2 | 3 | import android.arch.persistence.room.Database; 4 | import android.arch.persistence.room.Room; 5 | import android.arch.persistence.room.RoomDatabase; 6 | import android.content.Context; 7 | 8 | import com.codingwithmitch.notes.models.Note; 9 | 10 | @Database(entities = {Note.class}, version = 1) 11 | public abstract class NoteDatabase extends RoomDatabase { 12 | 13 | public static final String DATABASE_NAME = "notes_db"; 14 | 15 | private static NoteDatabase instance; 16 | 17 | static NoteDatabase getInstance(final Context context){ 18 | if(instance == null){ 19 | instance = Room.databaseBuilder( 20 | context.getApplicationContext(), 21 | NoteDatabase.class, 22 | DATABASE_NAME 23 | ).build(); 24 | } 25 | return instance; 26 | } 27 | 28 | public abstract NoteDao getNoteDao(); 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/persistence/NoteRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.persistence; 2 | 3 | 4 | import android.arch.lifecycle.LiveData; 5 | import android.content.Context; 6 | 7 | import com.codingwithmitch.notes.async.DeleteAsyncTask; 8 | import com.codingwithmitch.notes.async.InsertAsyncTask; 9 | import com.codingwithmitch.notes.async.UpdateAsyncTask; 10 | import com.codingwithmitch.notes.models.Note; 11 | 12 | import java.util.List; 13 | 14 | public class NoteRepository { 15 | 16 | private NoteDatabase mNoteDatabase; 17 | 18 | public NoteRepository(Context context) { 19 | mNoteDatabase = NoteDatabase.getInstance(context); 20 | } 21 | 22 | public void insertNoteTask(Note note){ 23 | new InsertAsyncTask(mNoteDatabase.getNoteDao()).execute(note); 24 | } 25 | 26 | public void updateNoteTask(Note note){ 27 | new UpdateAsyncTask(mNoteDatabase.getNoteDao()).execute(note); 28 | } 29 | 30 | public LiveData> retrieveNotesTask() { 31 | return mNoteDatabase.getNoteDao().getNotes(); 32 | } 33 | 34 | public void deleteNoteTask(Note note){ 35 | new DeleteAsyncTask(mNoteDatabase.getNoteDao()).execute(note); 36 | } 37 | } 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/util/Utility.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Utility { 7 | 8 | private static final String TAG = "Utility"; 9 | 10 | public static String getCurrentTimeStamp(){ 11 | try { 12 | 13 | SimpleDateFormat dateFormat = new SimpleDateFormat("MM-yyyy"); //MUST USE LOWERCASE 'y'. API 23- can't use uppercase 14 | String currentDateTime = dateFormat.format(new Date()); // Find todays date 15 | 16 | return currentDateTime; 17 | } catch (Exception e) { 18 | e.printStackTrace(); 19 | 20 | return null; 21 | } 22 | } 23 | 24 | public static String getMonthFromNumber(String monthNumber){ 25 | switch(monthNumber){ 26 | case "01":{ 27 | return "Jan"; 28 | } 29 | case "02":{ 30 | return "Feb"; 31 | } 32 | case "03":{ 33 | return "Mar"; 34 | } 35 | case "04":{ 36 | return "Apr"; 37 | } 38 | case "05":{ 39 | return "May"; 40 | } 41 | case "06":{ 42 | return "Jun"; 43 | } 44 | case "07":{ 45 | return "Jul"; 46 | } 47 | case "08":{ 48 | return "Aug"; 49 | } 50 | case "09":{ 51 | return "Sep"; 52 | } 53 | case "10":{ 54 | return "Oct"; 55 | } 56 | case "11":{ 57 | return "Nov"; 58 | } 59 | case "12":{ 60 | return "Dec"; 61 | } 62 | 63 | default:{ 64 | return "Error"; 65 | } 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingwithmitch/notes/util/VerticalSpacingItemDecorator.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes.util; 2 | 3 | import android.graphics.Rect; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | 7 | public class VerticalSpacingItemDecorator extends RecyclerView.ItemDecoration{ 8 | 9 | private final int verticalSpaceHeight; 10 | 11 | public VerticalSpacingItemDecorator(int verticalSpaceHeight) { 12 | this.verticalSpaceHeight = verticalSpaceHeight; 13 | } 14 | 15 | @Override 16 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 17 | RecyclerView.State state) { 18 | 19 | outRect.bottom = verticalSpaceHeight; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_add_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_note.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_notes_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | 35 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_note_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 27 | 28 | 32 | 33 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_note_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 42 | 43 | 44 | 45 | 55 | 56 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffd24d 4 | #e6ac00 5 | #d9d9d9 6 | 7 | #ffffb3 8 | #ffdf80 9 | #ffd24d 10 | #d9d9d9 11 | #a2a2a2 12 | #000 13 | #fff 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Notes 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/test/java/com/codingwithmitch/notes/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.codingwithmitch.notes; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.1.3' 11 | 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchtabian/SQLite-for-Beginners-2019/37e37de210a6b801bd0d33931c5a9dc4d1a4c462/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 03 08:04:05 PDT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------