Medoly ver. 1.4.7

ちょっと時間が出来たので、凄い久しぶりに過去の更新内容詳細についてまとめていきたいと思います…。

変更内容

2014-07-01 Ver. 1.4.7
– ウィジェットに再生アイコンを表示するよう変更
– 画像読込み処理修正
– 検索画面の状態保存処理一部修正
– 再生中の曲情報が更新されない場合がある問題修正

ウィジェットに再生アイコンを表示するよう変更

これ。

画像読込み処理修正

画像の読込み処理を直して、大きな画像を読込んだ時に余分なメモリを消費しないようにしました。

検索画面の状態保存処理一部修正

検索画面を再表示した際に、閉じる前の状態に戻す処理が一部おかしかったので修正。

再生中の曲情報が更新されない場合がある問題修正

タイトルの通り。バグの修正です。

Medoly ver.1.3.5 ~ 1.4.6

物凄い勢いで更新をサボってるので、最近の大雑把に変更点を…。

再生キュー処理の高速化

表面的には変わってませんが、再生キューの動きを高速化しています。いくつか変更を施していますが、主に以下のような変更になります。以前は、再生キューに5000曲ぐらい入れるとまったく使い物になりませんでしたが、これで大分マシになりました。(そんな使い方をする人がいるかどうかはともかく。)

  • 同期的に読込んでいたサムネイル画像を非同期で読込むように変更しました。そのため、スクロールの引っかかりが少なくなっています。
    またそれに伴い、以前は再生キュー登録時にサムネイルの縮小率の計算を行っていましたが、それを削除しました。そのため、再生キューへの登録が大幅に高速化されています。端末のスペックにもよりますが、100曲程度の登録なら一瞬で終わります。
  • タップした再生キュー項目のインデックスを取得する処理を見直してます。これに伴い、タップしてから再生開始までの間隔が短くなっています。
  • 再生キューテーブルの余計なデータを削除し、テーブルを少し修正しました。また、インデックスを追加しました。これにともない、読込処理が少し高速化されています。

早送り・巻き戻し追加

今さらながら、早送り・巻き戻しボタンを追加。設定で表示・非表示可能。
1回のタッチで設定秒数だけシーク、押しっぱなしで早送り・巻き戻しという動作になります。早送り・巻き戻しとは言っても、何かそれっぽく動かしているだけで、実際のところは断続的なシークの繰り返しで擬似的に早送り・巻き戻しをやってるだけです。200ms毎にシークし、押す時間が長いと段々シーク秒数が増えていくような動作になります。一般的な動作がよく分からないので、感覚的に適当に実装しました。

再生キューの削除をダイアログ方式に変更

従来メニューにあった再生キューの削除アクションを、ダイアログ方式にしました。削除までに、メニュー表示→ダイアログ表示→コマンド選択の3アクションになったので、やや煩わしくなったかもしれません。その代わり、いくつかの削除方法を追加しました。また、再生完了メディアの自動削除、エラーメディアの自動削除オプションを追加しています(設定画面にあったものを移動)。

プロパティタブの機能追加

  • プロパティリストにファイル共有処理を追加しています。音楽ファイル、アルバムアート、歌詞ファイルの「共有」ができます。また、歌詞についてはクリップボードへのコピーも可能となっています。 プロパティをタップした時に表示されるメニューから実行できます。
  • プロパティの一部項目から直接Web検索可能としました。
  • 上記アクションを追加したため、分かりやすくするためにプロパティリストに実行可能なアクションを示すアイコンを追加しました。

検索画面のソートアイコン追加

検索画面のソートアイコンを追加しました。(従来、設定画面にあったものと同等です。)
このアイコンをタップすることで、検索内容のソート順を変更できます。ただし、「ストレージ」タブの内容は変化しません。

検索画面の長押しメニュー追加

検索リスト項目を長押した時にメニューを表示し、再生キュー登録の細かい動作を指定することができます。とりあえず、簡単な動作を設定することができます。 このダイアログの設定は、このダイアログ以外の再生キュー追加動作に影響を与えません。

検索画面のストレージ表示状態で、ホームアイコン長押しによるホームパス設定追加

検索画面のストレージタブでホームタブを長押しすると、現在タブに表示されているパスをホームパスに設定できます。ただのオマケ機能です。

英語対応

…とりあえず英語対応させてみましたが、多分酷い英語です。とりあえずツッコミ待ちです。
この変更を行った後に英語でメールを頂いたので、 多少意味があったような気がします。

その他

非同期歌詞のスクロール位置を保持するようにするなど、細かい変更はいくつもありますが、とりあえず省略。多分これからも細かい修正は色々行っていきたいと思います。

今回、設定画面の項目をいくつかをメイン画面や検索画面に移動させています。これは、個人的に設定項目は可能な限り設定画面に置かず、操作する対象の近くに置きたいという方針のためです。今後もこうした変更はちょくちょく加えていくと思います。

Medoly ver.1.3.1 & 1.3.2 & 1.3.3

Medoly

ちょっと変更。

Ver. 1.3.1

 

検索画面の検索条件やスクロール位置をなるべく保持させる処理を追加

アプリの再起動時や検索画面に戻った時、検索条件を切り替えた時に、検索条件やスクロール位置を可能な限り保持するようにしました。
「可能な限り」というのは、曲が追加されたり変更された際に、どうしても位置を保持することが難しくなるため、そういった場合はズレが生じてきます。
保持させるタイミングや復帰させるタイミングがかなり入り組んでいて、色々面倒臭い処理になっているため、もしかしたらリセットされる場合があるかもしれません…。

再生キューのトラック・年が隠れないようにレイアウトを変更

再生キューには、アルバム名にディスク/トラック番号、アーティスト名に年が併記されていますが、アルバム名・アーティスト名が長い場合は ディスク/トラック番号・年が枠外に隠れてしまっていました。そんなわけで、 ディスク/トラック番号・年が隠れないようにレイアウトを修正しました。(アルバム名・アーティスト名のみが省略されます。)

Ver. 1.3.2

 

検索画面のアクティビティを再表示させた際、タイトル表示になってしまう問題を修正

Ver.1.3.1の修正ミスです。アクティビティ再表示が上手くいかないバグがありました。

Ver. 1.3.3

 

歌詞の多段表示対応

同じ時間で2行以上の歌詞がアクティブの場合、表示上も同時にアクティブにするようにしました。
2行以上が同時にアクティブになる場合は、行内にタイムタグが設定されている場合です。
例えば、以下のようなKRAファイルがあるとします。
[00:01:00] あ[00:02:00]い[00:03:00]う[00:04:00]え[00:05:00]お[00:06:00]
[00:04:00] か[00:05:00]き[00:06:00]く[00:07:00]け[00:08:00]こ[00:09:00]
上記の場合、再生開始から4~6秒の間は、1行目と2行目が両方アクティブな状態です。
文字単位で見ると、5秒時点では、1行目は「あ、い、う、え、お」が、2行目は「か、き」がアクティブな状態になります。
これは例えば、曲の中でメインボーカルとコーラスが被っている部分を表現する、といった利用を想定しています。

KRA -> LRC, LRC -> KRA 変換スクリプト

歌詞定義フォーマットの、LRCファイルKRAファイル(タイムタグフォーマット)の変換用WSHスクリプト(JScript)を作成したので公開。KRA -> LRC変換と、LRC -> KRA変換の2つ。WSHスクリプトなので、Windows専用。

[使い方]

  1. KRA -> LRC変換スクリプトの場合はKRAファイル(*.kra)をドラッグ&ドロップします。
    LRC -> KRA変換スクリプトの場合はLRCファイル(*.lrc)をドラッグ&ドロップします。
  2. KRAファイルの場合は、同じフォルダ上にLRCファイル(KRAファイル名.lrc)が作成されます。
    LRCファイルの場合は、同様にKRAファイルが作成されます。

[注意事項]

  • 埋め込まれているタグのうち、 タイトル、アーティスト、アルバム、作詞者、曲の長さ、ファイル作成者以外の情報は削除されます。
  • UnicodeのBOMが不要な場合は、コメントアウトしてある「// delete BOM」の辺りをコメント解除すると、BOMが削除されます。
  • あんまり真面目にテストしてないので、きちんと動かない場合があるかもしれません。 
  • とりあえず拡張子固定なので、拡張子lrcでKRAフォーマットにしている人や、拡張子txtでフォーマット定義してる人は知ったこっちゃないです。

KRA -> LRC変換WSHスクリプト

/*==== 設定 ==================================================================*/

var inputExt = /.kra$/i;
var outputExt = ".lrc";
var inputEncoding = "_autodetect_all";
var outputEncoding = "UTF-8";

/*============================================================================*/



/*==== 定数 ==================================================================*/

// 保存データの種類
// StreamTypeEnum
// http://msdn.microsoft.com/ja-jp/library/cc389884.aspx
var adTypeBinary = 1; // バイナリ
var adTypeText   = 2; // テキスト

// 読み込み方法
// StreamReadEnum
// http://msdn.microsoft.com/ja-jp/library/cc389881.aspx
var adReadAll  = -1; // 全行
var adReadLine = -2; // 一行ごと

// 書き込み方法
// StreamWriteEnum
// http://msdn.microsoft.com/ja-jp/library/cc389886.aspx
var adWriteChar = 0; // 改行なし
var adWriteLine = 1; // 改行あり

// ファイルの保存方法
// SaveOptionsEnum 
// http://msdn.microsoft.com/ja-jp/library/cc389870.aspx
var adSaveCreateNotExist  = 1; // ない場合は新規作成
var adSaveCreateOverWrite = 2; // ある場合は上書き

/*============================================================================*/



var args = WScript.Arguments;
if (args.length == 0) {
 WScript.Echo("引数を指定するか、ファイルをドラッグ&ドロップしてください。");
 WScript.Quit();
}

for (var i = 0; i < args.length; i++) {
 var path = args(i);
 if (path.match(inputExt) != null) {
  writeLyrics(path);
 }
}

function writeLyrics(path) {
 var streamReader = new ActiveXObject("ADODB.Stream");
 var streamWriter = new ActiveXObject("ADODB.Stream");
 try {
  // read
  streamReader.Open();
  streamReader.Type = adTypeText;
  streamReader.Position = 0;
  streamReader.Charset = inputEncoding;
  streamReader.LoadFromFile( path );
  var text = streamReader.ReadText( adReadAll );
  if (text.charCodeAt(0) == 0xFEFF || text.charCodeAt(0) == 0xFFFE) {
   text = text.substr(1); // delete BOM
  }
  
  // replace
  text = text.replace(/(^s+)|(s+$)/g, "");
  text = text.replace(/(rn|n|r|^)[(dd:dd):(dd)]/g, "$1[$2.$3]");
  text = text.replace(/[(dd:dd):(dd)]/g, "<$1.$2>");
  
  text = text.replace(/@Title= *(.*?)(rn|n|r|$)/g, "[ti:$1]$2");
  text = text.replace(/@Artist= *(.*?)(rn|n|r|$)/g, "[ar:$1]$2");
  text = text.replace(/@Album= *(.*?)(rn|n|r|$)/g, "[al:$1]$2");
  text = text.replace(/@Lyricist= *(.*?)(rn|n|r|$)/g, "[au:$1]$2");
  text = text.replace(/@Length= *(.*?)(rn|n|r|$)/g, "[length:$1]$2");
  text = text.replace(/@TaggingBy= *(.*?)(rn|n|r|$)/g, "[by:$1]$2");
  
  var offset = text.match(/@Offset= *(.*?)(rn|n|r|$)/);
  if (offset && offset.length >= 2) {
   text = text.replace(/@Offset= *(.*?)(rn|n|r|$)/, "[offset:" + (offset[1] * -1) + "]$2");
  }
  
  text = text.replace(/(@.*=.*?)(rn|n|r|$)/g, "");
  
  // write
  streamWriter.Type = adTypeText;
  streamWriter.Charset = outputEncoding;
  streamWriter.Open();
  streamWriter.WriteText(text, adWriteChar);
  
  /*
  // delete BOM
  var bomSize = 0;
  if (outputEncoding == "UTF-8") {
   bomSize = 3;
  } else if (outputEncoding.indexOf("UTF-16") == 0) {
   bomSize = 2;
  }
  streamWriter.Position = 0;
  streamWriter.Type = adTypeBinary;
  streamWriter.Position = bomSize;
  var buffer =  streamWriter.Read();
  streamWriter.Position = 0;
  streamWriter.Write(buffer);
  streamWriter.SetEOS();
  */
  
  streamWriter.SaveToFile( path.replace(inputExt, outputExt), adSaveCreateOverWrite );
 } finally {
  if (streamReader != null) streamReader.Close();
  if (streamWriter != null) streamWriter.Close();
 }
}

LRC -> KRA変換WSHスクリプト

/*==== 設定 ==================================================================*/

var inputExt = /.lrc$/i;
var outputExt = ".kra";
var inputEncoding = "_autodetect_all";
var outputEncoding = "UTF-8";

/*============================================================================*/



/*==== 定数 ==================================================================*/

// 保存データの種類
// StreamTypeEnum
// http://msdn.microsoft.com/ja-jp/library/cc389884.aspx
var adTypeBinary = 1; // バイナリ
var adTypeText   = 2; // テキスト

// 読み込み方法
// StreamReadEnum
// http://msdn.microsoft.com/ja-jp/library/cc389881.aspx
var adReadAll  = -1; // 全行
var adReadLine = -2; // 一行ごと

// 書き込み方法
// StreamWriteEnum
// http://msdn.microsoft.com/ja-jp/library/cc389886.aspx
var adWriteChar = 0; // 改行なし
var adWriteLine = 1; // 改行あり

// ファイルの保存方法
// SaveOptionsEnum 
// http://msdn.microsoft.com/ja-jp/library/cc389870.aspx
var adSaveCreateNotExist  = 1; // ない場合は新規作成
var adSaveCreateOverWrite = 2; // ある場合は上書き

/*============================================================================*/



var args = WScript.Arguments;
if (args.length == 0) {
 WScript.Echo("引数を指定するか、ファイルをドラッグ&ドロップしてください。");
 WScript.Quit();
}

for (var i = 0; i < args.length; i++) {
 var path = args(i);
 if (path.match(inputExt) != null) {
  writeLyrics(path);
 }
}

function writeLyrics(path) {
 var streamReader = new ActiveXObject("ADODB.Stream");
 var streamWriter = new ActiveXObject("ADODB.Stream");
 try {
  // read
  streamReader.Open();
  streamReader.Type = adTypeText;
  streamReader.Position = 0;
  streamReader.Charset = inputEncoding;
  streamReader.LoadFromFile( path );
  var text = streamReader.ReadText( adReadAll );
  if (text.charCodeAt(0) == 0xFEFF || text.charCodeAt(0) == 0xFFFE) {
   text = text.substr(1); // delete BOM
  }
  
  // replace
  text = text.replace(/(^s+)|(s+$)/g, "");
  text = text.replace(/<(dd:dd).(dd)>/g, "[$1:$2]");
  text = text.replace(/[(dd:dd).(dd)]/g, "[$1:$2]");
  
  text = text.replace(/[ti: *(.*?)]/g, "@Title=$1");
  text = text.replace(/[ar: *(.*?)]/g, "@Artist=$1");
  text = text.replace(/[al: *(.*?)]/g, "@Album=$1");
  text = text.replace(/[au: *(.*?)]/g, "@Lyricist=$1");
  text = text.replace(/[length: *(.*?)]/g, "@Length=$1");
  text = text.replace(/[by: *(.*?)]/g, "@TaggingBy=$1");
  
  var offset = text.match(/[offset: *(.*?)]/);
  if (offset && offset.length >= 2) {
   text = text.replace(/[offset: *(.*?)]/, "@Offset=" + (offset[1] * -1));
  }
  
  text = text.replace(/[[^d].*?](r?n)?/, "");
  text = text + "rn@TimeRatio=1rn";
  
  // write
  streamWriter.Type = adTypeText;
  streamWriter.Charset = outputEncoding;
  streamWriter.Open();
  streamWriter.WriteText(text, adWriteChar);
  
  /*
  // delete BOM
  var bomSize = 0;
  if (outputEncoding == "UTF-8") {
   bomSize = 3;
  } else if (outputEncoding.indexOf("UTF-16") == 0) {
   bomSize = 2;
  }
  streamWriter.Position = 0;
  streamWriter.Type = adTypeBinary;
  streamWriter.Position = bomSize;
  var buffer =  streamWriter.Read();
  streamWriter.Position = 0;
  streamWriter.Write(buffer);
  streamWriter.SetEOS();
  */
  
  streamWriter.SaveToFile( path.replace(inputExt, outputExt), adSaveCreateOverWrite );
 } finally {
  if (streamReader != null) streamReader.Close();
  if (streamWriter != null) streamWriter.Close();
 }
}

備考

タイムタグ仕様書(一般者向け)で定義されたフォーマットを「KRAフォーマット」と書いてはいますが、「KRAフォーマット」と言う名称はどこにも定義されてないので、便宜上の名前です。
「タイムタグ」や「タイムタグ歌詞」という名称は、LRC等を含めた歌詞定義フォーマット全般で使われる名称なので、フォーマット名称としてはあまり適切ではないと思います。そんなわけで、主に利用される拡張子「KRA」に基づき「KRAフォーマット」と呼称しています。
LRCは「LRCフォーマット」として定義されているため、迷うことはないのですが…。

Medoly ver.1.3.0

Medoly

ちょっと変更が多いのでバージョンを飛ばします。

検索画面の検索結果にサムネイル表示

検索画面の検索結果にサムネイルを表示するようにしました。これは、自分の非同期処理の練習も兼ねてます。
画像の表示は非同期処理を行っていますので、表示されるまでにワンテンポ遅れます。非同期処理慣れしてないので、もしかしたらもっと上手く表示できるかもしれませんが、とりあえず今はこんなところで。あと、たまに画像が表示されない場合がありますが、対策がよく分かってないので、とりあえずこのままにします。そのうち何とかします。画像が表示されなくても大した問題はないので…。
ちなみに、同期処理で画像を表示させるとスクロールが非常に遅くなるので不可です。 

検索結果のソート順設定追加

検索結果のソート順序をしていできるようにしました。適用対象はタイトル表示のみです。ストレージの表示や各ディレクトリ(アーティストやアルバム等)の表示には適用されません。
「設定」画面から変更できます。変更後は全ての検索結果に適用されます。
デフォルトのソートは、従来通りタイトル昇順となっています。

ソートが大文字・小文字で区別されていた問題修正

上記のソート順指定処理で気付きましたが、再生キューのソート時に大文字・小文字で区別されていました。本来は大文字・小文字の区別をしないようにしたかったので、ソート仕様を変更します。
 

特定環境でジャンルが表示されないバグ修正

所持しているAndroid 3.2端末(HTC Flyer)で確認したところ、ジャンルの表示が正しく行われていなかったため、修正しました。
これがAndroid 3.2の仕様上の問題なのか、端末固有の問題なのか判断がつかないのですが…。

再生キューの長押しメニュー項目修正

前回削ったと思ってたら削られていなかった「再生」項目を削除しました。
…うっかり何かの拍子に元に戻してしまっていたようです。

文言一部修正

設定画面等の文言を一部修正しました。特に動作には関係ありません。

Medoly ver.1.2.6

Medoly

ちょっと思いついた事を実装。

再生キュー項目の長押しメニュー内容変更

再生キューの曲を長押しした際のメニューに「先頭に移動」と「末尾に移動」を追加。個人的に少しほしかったので。
代わりに「再生」を除外。再生は項目をタップすれば良いだけの話なので必要性は低いかな…と。

検索画面のジャンル表示高速化

検索のジャンル画面の表示を少し高速化しました。
Androidのメディアデータベースは、一つの曲が複数のジャンルを保持できる構成になっています。
各ジャンルに含まれている曲数を表示させるため、今までは各ジャンルそれぞれについて曲数をカウントするという事をやっていたため、やや処理が遅くなっていました。当然、ジャンル数が多いと時間がかかります。
最近ちょっと調べてみたところ、検索URIに「content://media/external/audio/genres/all/members」を用いることで、ジャンルIDと楽曲IDの紐付けを行うテーブルにアクセスできる事が分かりました(ちなみに「audio_genres_map_noid」というビューを参照している。実体は「audio_genres_map」テーブルの模様)。
これをジャンルIDでグループ化して、各グループのカウントを取得することで、ジャンルに含まれる曲数を素早く取得できるようになりました。
ちなみに、プレイリストも同様の処理を行うつもりでしたが、同様ののURIが見当たりません…。

検索画面のストレージ表示高速化

検索のストレージ画面の表示を高速化しました。
これも曲数カウント絡みで、従来はテーブルからカレントディレクトリに含まれるメディアを全て取得し、Javaのコードで項目をカウントするという力業で曲数を取得していました。当然、曲数が増えると処理に時間がかかるようになります。ディレクトリの階層が浅くなり、サブディレクトリに含まれるメディアが増えていくと、それに合わせて表示に時間がかかるようになります。
変更後は、SQLiteのGROUP BYとCOUNT関数を活用するようにしました。ただし、SQLiteは文字列長に合わせた柔軟なグループ化ができない(私が知らない)ので、以下のような感じのSQL処理を行うようにしました。
START = カレントディレクトリパスの文字列長
LENGTH = カレントディレクトリに含まれる最大ファイル・フォルダ文字列長
SELECT [ファイルパス], SUBSTR([ファイルパス], START, LENGTH) AS subpath, COUNT(subpath) as count
FROM [メディアテーブル]
WHERE [ファイルパス] LIKE カレントディレクトリ%
GROUP BY subpath

上記の内容は大雑把なイメージですが、とりあえずSQLで可能な範囲でざっくり纏めてしまうというのが基本的な方針です。もちろん、同一のサブフォルダが複数に分割される場合もありますが、細かいカウントの合計値はJavaの処理で行っています。
なお、この処理の特性上、カレントディレクトリに一つでも長い名前のファイル・フォルダが含まれていると処理の効率が悪くなります。
ただ、ほとんどの場合は表示が高速化されますし、上位ディレクトリに行く程表示が遅くなる従来の問題は無くなります。

検索画面のジャンル・プレイリストのカウントが正しく表示されない問題修正 

これは、カウントする処理が誤っていたバグです。

検索画面で一つでもチェックが入っていた場合に、タップ挙動をチェックの変更とする

検索画面で、リスト上に一つでもチェックが入っていた場合、項目タップの挙動をチェックのON/OFF切換とするようにしました。ディレクトリのタップ動作によりチェックが全てクリアされてしまうため、誤操作により何度もチェックをやり直す羽目になる問題があったためです。

Medoly ver.1.2.5

Medoly

エラー発生時の対応ダイアログ追加

エラーが発生してアプリが終了した際、次の起動時に以下の選択ができるようにしました。
もしアプリが起動できなくなった場合は、再生キューのクリア、または設定のクリアを実行してください。

  • 再生キューをクリア
    再生キューの内容をクリアします。
  • 全ての設定をクリア
    再生キューの内容及び設定を全てクリアし、初期状態に戻します。
  • 何もせずに起動
    そのまま起動します。通常はこれを選択してください。

ウィジェットが更新されない不具合修正

現在の再生曲をクリアした際に、ウィジェットに曲情報が残る不具合があったので修正。
これは、ImageViewの画像をクリアする際に、クリアのやり方が悪くて例外が発生していたためでした。これはAndroid 4.4なら問題なかったのですが、旧バージョンでは発生していました。

ストレージ検索の複数チェック時に検索結果がおかしくなる問題を修正

フォルダ検索で、複数チェックして別の条件を再検索した際に、検索結果が正しくならない場合があったので修正しました。
これは、SQLの検索条件が括弧で囲われていないためでした。
例を挙げると、今までは以下のようなWHERE句になっていました。
WHERE _data=? OR _data = ? AND artist=?

これを修正して、以下のようにWHERE句が組まれるようにしました。
WHERE (_data = ? OR _data = ?) AND artist=?

再生キューのサムネイルが正しく表示されるよう修正

再生キューのサムネイルが正しく表示されない場合があったため修正。
アルバムアートが存在しない場合、再生キューの1個前の画像を拾ってしまう場合があり、これをデフォルトの画像が表示されるように修正しました。

Medoly ver.1.2.3

Medoly – Google Play の Android アプリ

ちょっと試してみたらすぐ出来たので1.2.3へアップデート。
 

再生キューの長押しメニュー追加

再生キューを長押しした際にメニューを表示するようにしました。既に他で代替できるような機能ばかりですが、一応一般的なアプリと同様の操作方法も出来た方が良いかな、と。
とりあえずアップデート内容はそれだけ。
 

Medoly ver.1.2.2

Medoly – Google Play の Android アプリ

すぐ実装できそうだったのでサクッと機能追加。

関連付け処理追加

音楽ファイルが、他のアプリから「共有」や関連付け実行できるようになりました。
音楽ファイルを「共有」もしくは関連付けで実行すると、再生キューに登録されます。オプションから自動的に再生させるようにする事もできます。
試しに作ってみたけど、意外と面倒くさかった…。

Medoly ver.1.2.1

Medoly – Google Play の Android アプリ

いきなり修正。

ソートアイコン変更

ソートアイコンが昇順が下矢印、降順が上矢印だったので修正。何となく、A→Zの感覚で昇順を下矢印にしたけれど、よく考えたら昇順は普通↑や△で表記されることが多い。
とりあえず、Excelのアイコン風にAとZを添えてアイコンを統一。
変更前

変更後

ソート時に画面が更新されない不具合修正

ソート時に画面の更新がされず、ソーとされていないように見える不具合があったので修正。


タイトル検索時に同名タイトルがまとめて表示される不具合修正

検索時に同一タイトル名があった場合、まとめて表示されてしまう不具合があったので修正。