Sailfish OS開発:LocalStorageの使用

こんにちは この記事は、モバイルプラットフォームSailfish OSの開発に関する一連の記事の続きです。 今回、私たちはユーザーが収入と支出の日誌を保持できるようにするだけでなく、目標の実装のためにお金を節約できる財務管理アプリケーションについて話すことにしました。 このアプリケーションは、オープンモバイルプラットフォーム会社とFRUCT協会によって組織された、ヤロスラブリのセイルフィッシュOSハッカソンの受賞者の1つであることを言及する価値があります。



説明



このアプリケーションには、2つの別個のモジュールが含まれています。 それらの最初のものは、操作で直接動作するように設計されています。 2番目の方法では、ユーザーが目標を作成し、蓄積の進行状況を追跡できます。



操作を処理するモジュールを使用すると、ユーザーは収入と支出を記録したり、これらの操作をログの形式で表示したりできます。







追加画面のスクリーンショットからわかるように、各操作に対してカテゴリが定義されています。 この分類は、ユーザーがより簡単に財務をナビゲートするのに役立ちます。 標準のカテゴリに加えて、ユーザーは独自のカテゴリを追加して、アプリケーションを自分のライフスタイルに合わせて調整できます。



さらに、アプリケーションはさまざまな期間の統計を表示する機能を提供するため、ユーザーは自分の費用を分析し、将来最適化することができます。







2番目のアプリケーションモジュールは、あらゆる目的のために資金を蓄積するタスクを作成する機能を提供します。 ユーザーは、特定の目的のためにどれだけの資金を確保するかについての情報をアプリケーションに記録できます。

進捗を追跡することで、タスクを完了するようさらに動機付けられます。







データベースを操作する



この記事では、QMLファイルから直接データベースを操作することに焦点を合わせることにしました。 このタスクを実装するために、デバイスに保存されているSQLiteデータベースへのアクセスを整理できるLocalStorageライブラリが使用されました。



データベースを操作するロジックをフォームの要素から分離するために、データにアクセスするためのQMLオブジェクト(データアクセスオブジェクトまたは単にDAO )が作成され、データベースへのすべての接続を管理し、データを操作するためのより便利なインターフェイスを提供します。 データベース接続は、 LocalStorageグローバルシングルトンオブジェクトを使用して開かれますopenDatabaseSync()メソッドを呼び出します。このメソッドは、接続を直接開くか、以前に作成されていない場合はデータベースを作成します。 ガベージコレクション時にすべての接続が自動的に閉じられます。 以下は、Dao.qmlファイルのコードの一部です。



import QtQuick 2.0 import QtQuick.LocalStorage 2.0 Item { Component.onCompleted: { database = LocalStorage.openDatabaseSync("SaveYourMoneyDatabase", "1.0") } //... }
      
      





データベースを操作する際のトランザクションとクエリは、JSの機能として設計されています。

結果には、操作の完了時に呼び出されるコールバック関数が必要です。 結果の接続オブジェクトで、 readTransaction()およびtransaction()メソッドを呼び出すことができます。これらのメソッドは、データを読み取りまたは変更するトランザクションを作成し、これらのメソッドの引数として指定されたコールバック関数に渡します。 これらの関数内で、SQLクエリを含むexecuteSql()メソッドを呼び出すことができます。



このアプリケーションでは、3つのテーブルを持つデータベースを作成する必要がありました:操作を格納するTransactionsTable 、目標を表すGoalTable 、および操作のカテゴリ表す CategoriesTable



 Component.onCompleted: { database = LocalStorage.openDatabaseSync("SaveYourMoneyDatabase", "1.0") database.transaction(function(tx) { tx.executeSql("CREATE TABLE IF NOT EXISTS TransactionsTable( id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, sum INTEGER, category_id INTEGER, type INTEGER, goal_id INTEGER, description TEXT)"); tx.executeSql("CREATE TABLE IF NOT EXISTS CategoriesTable( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, type INTEGER)"); tx.executeSql("CREATE TABLE IF NOT EXISTS GoalTable( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, sum INTEGER, isFinished INTEGER)"); // ... } }); }
      
      





Daoオブジェクトの作成時に実行するために、データベースの作成および初期化操作をComponent.onCompletedシグナルハンドラー内に配置する必要があることに注意してください。



操作テーブルに新しいレコードを追加する方法は次のとおりです。



 function createTransaction(date, sum, category_id, type, description) { database.transaction(function(tx) { tx.executeSql("INSERT INTO TransactionsTable(date, sum, category_id, type, description) VALUES(?, ?, ?, ?, ?)", [date, sum, category_id, type, description]); }); }
      
      





目標リストを取得するメソッドは次のようになります。



 function retrieveGoals(isFinished, callback) { database = LocalStorage.openDatabaseSync("SaveYourMoneyDatabase", "1.0"); database.readTransaction(function(tx) { var result = tx.executeSql("SELECT * FROM GoalTable WHERE isFinished = ? ORDER BY id ASC", [isFinished]); callback(result.rows) }); }
      
      





ここで、 executeSql()を実行した結果は、すべての結果のレコードのリストを持つrowsプロパティを含むオブジェクトです。 i番目の要素を取得するには、 rows.item(i)メソッドを呼び出すだけです。 エレメントの数は、 rows.lengthプロパティで利用できます。 説明した方法の使用例:



 Dao { id: dao } SilicaListView { id: listView model: GoalListModel { id: goalsListModel } delegate: ListItem { // ... } // ... } function displayGoals() { listView.model.clear(); dao.retrieveGoals(true, function(goals) { for (var i = 0; i < goals.length; i++) { var goal = goals.item(i); listView.model.addGoal(goal.id, goal.name, goal.sum); } }); } Component.onCompleted: displayGoals();
      
      





このコードは、データベースのレコードフィールドの値がオブジェクトvar goal = goal.item(i)のプロパティとして利用可能であることを示しています。 この場合、計算フィールドを使用したクエリは次のようになります。



 function retrieveGoalStatistics(callback) { database = LocalStorage.openDatabaseSync("SaveYourMoneyDatabase", "1.0"); database.readTransaction(function(tx) { var result = tx.executeSql("SELECT SUM(sum) AS goalSum FROM GoalTable WHERE isFinished = 0"); callback(result.rows.item(0).goalSum) }); }
      
      





また、アプリケーションでは、日付によるレコードのフィルタリングが追加されました。 ご存じのように、SQLiteには日付を操作するための標準タイプがありません。 代わりに、SQLiteは5つの日付と時刻の関数をサポートしています。 すべての日付をISO8601形式の文字列としてデータベースに保存します。 最も早い操作の日付を取得するリクエストの例は次のとおりです。



 function retrieveDateOfFirstTransaction(callback) { database = LocalStorage.openDatabaseSync("SaveYourMoneyDatabase", "1.0"); database.readTransaction(function(tx) { var result = tx.executeSql("SELECT MIN(date(date)) as minDate FROM TransactionsTable"); callback(result.rows.item(0).minDate) }); }
      
      





QML側では、日付を操作する場合、JavascriptのDateクラスから継承するQMLクラスDateが使用されます。 クエリ結果の処理を続行するには、次を実行する必要があります。



 dao.retrieveDateOfFirstTransaction(function(result){ startDate = new Date(result); });
      
      





オブジェクトをISO8601形式の文字列に戻すには、 toISOString()メソッドを使用する必要があります。



おわりに



その結果、ユーザーの財務に関する情報を保存できるアプリケーションが作成されました。 このアプリは、Jolla HarborアプリストアでSave Your moneyという名前で公開され、誰でもダウンロードできます。 アプリケーションソースはBitbucketで入手できます。



技術的な問題は、ロシア語を話すコミュニティのSailfish OSのTelegramまたはVKontakteグループチャネルでも議論できます。



著者:ダリア・ロイチコワ



All Articles