├── .gitignore
├── AndroidManifest.xml
├── README
├── build.properties
├── build.xml
├── default.properties
├── proguard.cfg
├── res
├── drawable
│ └── icon.png
├── layout
│ ├── note_edit.xml
│ ├── notes_list.xml
│ └── notes_row.xml
└── values
│ └── strings.xml
└── src
├── NoteEdit.mirah
├── Notepadv3.mirah
└── NotesDbAdapter.mirah
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.bak
3 | bin
4 | gen
5 | local.properties
6 |
7 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This project is intended to help me learn both Android development and Mirah language at the same time.
2 |
3 | It is port of Android Notepad tutorial to Mirah programming language.
4 |
5 | If you have suggestions about coding style, please let me know. Or, better yet, create a fork and send me a pull request.
6 |
--------------------------------------------------------------------------------
/build.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markokocic/android-notepad-mirah/7b91b6c8cefacbf17c8a6b4b3b283f655b78c8c8/build.properties
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
24 |
25 |
27 |
28 |
29 |
31 |
34 |
35 |
36 |
39 |
40 |
41 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | hasCode = false. Skipping...
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | hasCode = false. Skipping...
82 |
83 |
84 |
85 |
86 |
87 |
90 |
91 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Indicates whether an apk should be generated for each density.
11 | split.density=false
12 |
13 | # Project target.
14 | target-version=android-9
15 | target=Google Inc.:Google APIs:9
16 |
--------------------------------------------------------------------------------
/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class * extends android.app.backup.BackupAgentHelper
14 | -keep public class * extends android.preference.Preference
15 | -keep public class com.android.vending.licensing.ILicensingService
16 |
17 | -keepclasseswithmembernames class * {
18 | native ;
19 | }
20 |
21 | -keepclasseswithmembernames class * {
22 | public (android.content.Context, android.util.AttributeSet);
23 | }
24 |
25 | -keepclasseswithmembernames class * {
26 | public (android.content.Context, android.util.AttributeSet, int);
27 | }
28 |
29 | -keepclassmembers enum * {
30 | public static **[] values();
31 | public static ** valueOf(java.lang.String);
32 | }
33 |
34 | -keep class * implements android.os.Parcelable {
35 | public static final android.os.Parcelable$Creator *;
36 | }
37 |
--------------------------------------------------------------------------------
/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markokocic/android-notepad-mirah/7b91b6c8cefacbf17c8a6b4b3b283f655b78c8c8/res/drawable/icon.png
--------------------------------------------------------------------------------
/res/layout/note_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
14 |
18 |
19 |
20 |
23 |
27 |
28 |
32 |
33 |
--------------------------------------------------------------------------------
/res/layout/notes_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/res/layout/notes_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Notepad v3 Mirah
4 | No Notes Yet
5 | Add Note
6 | Delete Note
7 | Title
8 | Body
9 | Confirm
10 | Edit Note
11 |
12 |
--------------------------------------------------------------------------------
/src/NoteEdit.mirah:
--------------------------------------------------------------------------------
1 | package com.android.demo.notepad3
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.view.View
7 | import android.widget.Button
8 | import android.widget.EditText
9 | import android.util.Log
10 |
11 | class NoteEdit < Activity
12 |
13 | def initialize
14 | @titleText = EditText(nil)
15 | @bodyText = EditText(nil)
16 | @rowId = long(0)
17 | @dbHelper = NotesDbAdapter(nil)
18 | end
19 |
20 | $Override
21 | def onCreate(savedInstanceState: Bundle): void
22 | super savedInstanceState
23 | @dbHelper = NotesDbAdapter.new self
24 | @dbHelper.open
25 |
26 | setContentView R.layout.note_edit
27 | # setTitle R.string.edit_note
28 |
29 | @titleText = EditText (findViewById(R.id.title))
30 | @bodyText = EditText (findViewById(R.id.body))
31 |
32 | confirmButton = Button (findViewById(R.id.confirm))
33 |
34 | @rowId = long(0)
35 | if !savedInstanceState.nil?
36 | @rowId = savedInstanceState.getLong NotesDbAdapter.KEY_ROWID
37 | end
38 | if @rowId == 0
39 | extras = getIntent().getExtras
40 | if !extras.nil?
41 | @rowId = extras.getLong NotesDbAdapter.KEY_ROWID
42 | end
43 | end
44 |
45 | populateFields
46 |
47 | this = self
48 | confirmButton.setOnClickListener do | view |
49 | this.setResult Activity.RESULT_OK
50 | this.finish
51 | end
52 | end
53 |
54 | $Override
55 | def onSaveInstanceState(outState: Bundle): void
56 | super outState
57 | saveState
58 | outState.putLong NotesDbAdapter.KEY_ROWID, @rowId
59 | end
60 |
61 | $Override
62 | def onPause(): void
63 | super
64 | saveState
65 | end
66 |
67 | $Override
68 | def onResume(): void
69 | super
70 | populateFields
71 | end
72 |
73 | def saveState: void
74 | title = @titleText.getText().toString
75 | body = @bodyText.getText().toString
76 |
77 | if @rowId == 0
78 | id = @dbHelper.createNote title, body
79 | if id > 0
80 | @rowId = id
81 | end
82 | else
83 | @dbHelper.updateNote @rowId, title, body
84 | end
85 | end
86 |
87 | def populateFields
88 | if @rowId > 0
89 | note = @dbHelper.fetchNote @rowId
90 | startManagingCursor note
91 | @titleText.setText note.getString(note.getColumnIndexOrThrow NotesDbAdapter.KEY_TITLE)
92 | @bodyText.setText note.getString(note.getColumnIndexOrThrow NotesDbAdapter.KEY_BODY)
93 | end
94 | end
95 |
96 | end
97 |
98 |
--------------------------------------------------------------------------------
/src/Notepadv3.mirah:
--------------------------------------------------------------------------------
1 | package com.android.demo.notepad3
2 |
3 | import android.app.Activity
4 | import android.app.ListActivity
5 | import android.content.Intent
6 | import android.database.Cursor
7 | import android.os.Bundle
8 | import android.view.ContextMenu
9 | import android.view.Menu
10 | import android.view.MenuItem
11 | import android.view.View
12 | import android.view.ContextMenu.ContextMenuInfo
13 | import android.widget.AdapterView.AdapterContextMenuInfo
14 | import android.widget.ListView
15 | import android.widget.SimpleCursorAdapter
16 |
17 |
18 | class Notepadv3 < ListActivity
19 |
20 | def self.initialize: void
21 | @@ACTIVITY_CREATE = 0
22 | @@ACTIVITY_EDIT = 1
23 |
24 | @@INSERT_ID = Menu.FIRST
25 | @@DELETE_ID = Menu.FIRST + 1
26 | end
27 |
28 | def initialize
29 | @noteNumber = 1
30 | end
31 |
32 | ## Called when the activity is first created.
33 | $Override
34 | def onCreate(savedInstanceState: Bundle): void
35 | super savedInstanceState
36 | setContentView R.layout.notes_list
37 | @dbHelper = NotesDbAdapter.new self
38 | @dbHelper.open
39 | fillData
40 | registerForContextMenu (getListView)
41 | end
42 |
43 | $Override
44 | def onCreateOptionsMenu(menu: Menu): boolean
45 | result = super menu
46 | menu.add 0, @@INSERT_ID, 0, R.string.menu_insert
47 | true
48 | end
49 |
50 | $Override
51 | def onMenuItemSelected(featureId: int, item: MenuItem): boolean
52 | if item.getItemId == @@INSERT_ID
53 | createNote
54 | return true
55 | end
56 | super featureId, item
57 | end
58 |
59 | def fillData: void
60 | notesCursor = @dbHelper.fetchAllNotes
61 | startManagingCursor notesCursor
62 |
63 | from = String[1]; from[0] = NotesDbAdapter.KEY_TITLE
64 | to = int[1]; to[0] = R.id.text1
65 |
66 | notes = SimpleCursorAdapter.new self, R.layout.notes_row, notesCursor, from, to
67 | setListAdapter notes
68 | end
69 |
70 | $Override
71 | def onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo): void
72 | super menu, v, menuInfo
73 | menu.add 0, @@DELETE_ID, 0, R.string.menu_delete
74 | end
75 |
76 | $Override
77 | def onContextItemSelected(item: MenuItem): boolean
78 | if item.getItemId == @@DELETE_ID
79 | info = item.getMenuInfo
80 | @dbHelper.deleteNote AdapterContextMenuInfo(info).id
81 | fillData
82 | return true
83 | end
84 | super item
85 | end
86 |
87 | def createNote()
88 | intent = Intent.new self, NoteEdit.class
89 | startActivityForResult intent, @@ACTIVITY_CREATE
90 | end
91 |
92 | $Override
93 | def onListItemClick(l: ListView, v: View, position: int, id: long): void
94 | super l, v, position, id
95 | i = Intent.new self, NoteEdit.class
96 | i.putExtra NotesDbAdapter.KEY_ROWID, id
97 | startActivityForResult i, @@ACTIVITY_EDIT
98 | end
99 |
100 | $Override
101 | def onActivityResult(requestCode: int, resultCode: int, intent: Intent): void
102 | super requestCode, resultCode, intent
103 | fillData
104 | end
105 | end
106 |
--------------------------------------------------------------------------------
/src/NotesDbAdapter.mirah:
--------------------------------------------------------------------------------
1 | package com.android.demo.notepad3
2 |
3 | import android.content.ContentValues
4 | import android.content.Context
5 | import android.database.Cursor
6 | import android.database.SQLException
7 | import android.database.sqlite.SQLiteDatabase
8 | import android.database.sqlite.SQLiteDatabase.CursorFactory
9 | import android.database.sqlite.SQLiteOpenHelper
10 | import android.util.Log
11 |
12 | ## Simple notes database access helper class. Defines the basic CRUD operations
13 | ## for the notepad example, and gives the ability to list all notes as well as
14 | ## retrieve or modify a specific note.
15 |
16 | ## This has been improved from the first version of this tutorial through the
17 | ## addition of better error handling and also using returning a Cursor instead
18 | ## of using a collection of inner classes (which is less scalable and not
19 | ## recommended).
20 |
21 | class NotesDbAdapter
22 |
23 | def self.initialize: void
24 | @@DATABASE_TABLE = "notes"
25 | @@KEY_TITLE = "title"
26 | @@KEY_BODY = "body"
27 | @@KEY_ROWID = "_id"
28 | end
29 |
30 | ## Constructor - takes the context to allow the database to be
31 | ## opened/created
32 | ##
33 | ## @param ctx the Context within which to work
34 | def initialize (ctx: Context)
35 | @ctx = ctx
36 | @db = SQLiteDatabase(nil)
37 | @dbHelper = DatabaseHelper(nil)
38 | # @db: SQLiteDatabase = nil
39 | # @dbHelper: DatabaseHelper = nil
40 | end
41 |
42 | ## Open the notes database. If it cannot be opened, try to create a new
43 | ## instance of the database. If it cannot be created, throw an exception to
44 | ## signal the failure
45 | ##
46 | ## @return this (self reference, allowing this to be chained in an
47 | ## initialization call)
48 | ## @throws SQLException if the database could be neither opened or created
49 | def open: NotesDbAdapter
50 | @dbHelper = DatabaseHelper.new @ctx
51 | @db = @dbHelper.getWritableDatabase
52 | self
53 | end
54 |
55 | def close(): void
56 | @dbHelper.close
57 | end
58 |
59 | def self.KEY_ROWID
60 | @@KEY_ROWID
61 | end
62 |
63 | def self.KEY_TITLE
64 | @@KEY_TITLE
65 | end
66 |
67 | def self.KEY_BODY
68 | @@KEY_BODY
69 | end
70 |
71 | ## Create a new note using the title and body provided. If the note is
72 | ## successfully created return the new rowId for that note, otherwise return
73 | ## a -1 to indicate failure.
74 | ##
75 | ## @param title the title of the note
76 | ## @param body the body of the note
77 | ## @return rowId or -1 if failed
78 | def createNote(title: String, body: String): long
79 | initialValues = ContentValues.new
80 | initialValues.put @@KEY_TITLE, title
81 | initialValues.put @@KEY_BODY, body
82 |
83 | return @db.insert @@DATABASE_TABLE, null, initialValues
84 | end
85 |
86 | ## Delete the note with the given rowId
87 | ##
88 | ## @param rowId id of note to delete
89 | ## @return true if deleted, false otherwise
90 | def deleteNote(rowId: long) : boolean
91 | (@db.delete @@DATABASE_TABLE, @@KEY_ROWID + "=" + rowId, null) > 0
92 | end
93 |
94 | def toStringArray(list: java.util.List): String[]
95 | strings = String[list.size]
96 | list.size.times { |i| strings[i] = String(list.get(i)) }
97 | strings
98 | end
99 |
100 | ## Return a Cursor over the list of all notes in the database
101 | ##
102 | ## @return Cursor over all notes
103 | def fetchAllNotes() : Cursor
104 | return @db.query @@DATABASE_TABLE, toStringArray([@@KEY_ROWID, @@KEY_TITLE, @@KEY_BODY]), null, null, null, null, null
105 | end
106 |
107 | ## Return a Cursor positioned at the note that matches the given rowId
108 | ##
109 | ## @param rowId id of note to retrieve
110 | ## @return Cursor positioned to matching note, if found
111 | ## @throws SQLException if note could not be found/retrieved
112 | def fetchNote(rowId: long): Cursor
113 | mCursor = @db.query true, @@DATABASE_TABLE, toStringArray([@@KEY_ROWID, @@KEY_TITLE, @@KEY_BODY]), @@KEY_ROWID + "=" + rowId, null, null, null, null, null
114 | if !mCursor.nil?
115 | mCursor.moveToFirst
116 | end
117 | mCursor
118 | end
119 |
120 | ## Update the note using the details provided. The note to be updated is
121 | ## specified using the rowId, and it is altered to use the title and body
122 | ## values passed in
123 | ##
124 | ## @param rowId id of note to update
125 | ## @param title value to set note title to
126 | ## @param body value to set note body to
127 | ## @return true if the note was successfully updated, false otherwise
128 | def updateNote(rowId: long, title: String, body: String): boolean
129 | args = ContentValues.new
130 | args.put @@KEY_TITLE, title
131 | args.put @@KEY_BODY, body
132 | return (@db.update @@DATABASE_TABLE, args, @@KEY_ROWID + "=" + rowId, null) > 0;
133 | end
134 | end
135 |
136 | class DatabaseHelper < SQLiteOpenHelper
137 |
138 | def self.initialize: void
139 | @@TAG = "NotesDbAdapter"
140 | ## Database creation sql statement
141 | @@DATABASE_CREATE = "create table notes (_id integer primary key autoincrement, " + "title text not null, body text not null);"
142 | @@DATABASE_NAME = "data"
143 | @@DATABASE_VERSION = 2
144 | end
145 |
146 | def initialize (context: Context)
147 | super context, @@DATABASE_NAME, CursorFactory(nil), @@DATABASE_VERSION
148 | end
149 |
150 | def onCreate(db: SQLiteDatabase):void
151 | db.execSQL @@DATABASE_CREATE
152 | end
153 |
154 | def onUpgrade(db: SQLiteDatabase, oldVersion: int, newVersion: int): void
155 | Log.w @@TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"
156 | db.execSQL "DROP TABLE IF EXISTS notes"
157 | onCreate db
158 | end
159 | end
160 |
161 |
--------------------------------------------------------------------------------