投稿

【Bootstrap+Drawer.js】Drawerメニュー内にBootstrapのNavbarメニューを組み込む

イメージ
表題の通り、Drawer.jsによりスライドインするメニューの中で、Bootstrapのnavbarを使い開閉可能なサブメニューを実装します。 また、Drawer.jsを使うと実機で見たときにスクロールが正しく機能しなくなったので、そのときにとった対応をメモしておきます。 まずはBootstrapのnavbarとDrawer.jsについて簡単に説明します。 はじめに Bootstrap navbarについて Bootstrapのnavbarは開閉式のメニューを作るのに利用します。 公式 : https://getbootstrap.jp/docs/4.2/components/navbar/ メニューの開閉のコントロールをボタンで行っていますが、テキストにすることもできるので「メインメニュー > サブメニュー」のように実装することも可能です。 実装例 [クリックで表示] 上記イメージの実装が以下のようになります。 開閉ボタンにbuttonタグを使用していますが、これは何でもよくてdata-target属性にcollspaceクラスを持つコンテンツのid属性と併せておけばOKです。 <nav class="navbar navbar-light navbar-expand-md p-1"> <div class="navbar-brand sp"></div> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navmenu" aria-controls="navmenu" aria-expanded="false" aria-label="Toggle navigation"&g

【Android】動画プレイヤーのコードを利用して音楽プレイヤーを作る

イメージ
以前作成した動画プレイヤーのソースコードをほぼそのまま使って今度は音楽プレイヤーを作ってみました。 ※動画プレイヤーについては以下の記事を参考 【Android】VideoViewを使って動画再生アプリを作る① -- ストレージへのアクセス権限を取得 -- 【Android】VideoViewを使って動画再生アプリを作る② -- 内部ストレージのファイル検索 -- 【Android】VideoViewを使って動画再生アプリを作る③ -- カスタムリストビュー -- 【Android】VideoViewを使って動画再生アプリを作る④ -- 全画面で動画再生 -- 【Android】VideoViewを使って動画再生アプリを作る -- 不具合修正、軽微な修正 -- 概要 アプリケーションの特徴 アプリケーションの特徴は以下のとおりで、1-2は動画プレイヤーのコードほぼそのままです。 内部ストレージからmp3ファイルを検索してリスト表示する。 チェックボックスで複数選択し、選択アイテムを連続再生する。 再生中画面では音量調節を可能にする。 再生画面でどのファイルを再生中かわかるようにする。 再生中にホーム画面へ戻ってもアプリケーション実行中はバックグラウンドで再生し続ける。 再生中のイメージ 実装 いくつかこのアプリケーションで新たに対応した内容を記載します。 音量調節 レイアウト 音量調節はSeekBarを使って行います。 <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" /> Mp3Activity.java Activity側ではOnSeekBarChangeListenerを設定して、SeekBarのつまみを変更したイベントで音量調節を実行します。 SeekBar seekBar = findViewById(R.id.seekBar); audioManager = (AudioManager)get

【Android】VideoViewを使って動画再生アプリを作る
-- 不具合修正、軽微な修正 --

【Android】VideoViewを使って動画再生アプリを作る で作成したアプリを使っていたところ使いにくい点を発見したのでいくつか改修を入れました。 対応した内容 再生中にスリープモードにしない ファイルサイズを動画の総再生時間に変更 チェックボックスを付けて複数ファイルの再生に対応 再生中にスリープモードにしない この対応は簡単で動画再生するActivityで以下1行入れるだけです。 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); ファイルサイズを動画の総再生時間に変更 これはトップ画面のファイルリストでファイルサイズを表示していましたが、あまり意味が無いので再生時間を取得して表示するようにしました。以下のようにメソッド化したのでFileオブジェクトを渡してやれば秒数が返ってきます。 /** * 動画ファイル再生時間取得 * @return int */ public static int getDuration(File audioFile) { try { MediaPlayer mediaPlayer = new MediaPlayer(); FileInputStream inputStream = new FileInputStream(audioFile);; FileDescriptor fileDescriptor = inputStream.getFD(); mediaPlayer.setDataSource(fileDescriptor); mediaPlayer.prepare(); int length = mediaPlayer.getDuration(); mediaPlayer.release(); return length / 1000; } catch (Exception e) { return 0; } } これで取得した再生時間をAdapterでListViewにセットするときに以下のように分と秒で分けてやり表示

【Android】カスタムリストビューにCheckBoxを追加したとき別の行までチェックされる事象の対応

AndroidでCheckBox付きのカスタムListViewを実装し、動作確認したところチェックした行以外の行までチェックされてしまう謎現象が発生しました。 カスタムListViewの実装については以下参照 【Android】VideoViewを使って動画再生アプリを作る③ -- カスタムリストビュー -- 今回は単純にチェックボックスと単純な名前を一つだけ持ったListを表示しています。 問題のあるコード Adapterクラス public class ListAdapter extends ArrayAdapter<String> { private int resource; private List<String> items; private LayoutInflater inflater; public ListAdapter(Context context, int resource, List<String> items) { super(context, resource, items); this.resource = resource; this.items = items; this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; if (convertView != null) { view = convertView; } else { view = inflater.inflate(resource, null); } TextView itemName = view.findViewById(R.id.item_name)

【Laravel + MySQL】簡単な認証処理を作る

イメージ
前回作成したLaravelアプリケーションに認証処理を実装します。 データベースの作成 ユーザーテーブル作成 Laravel 6.2 にはセットアップした段階で以下の migration 用のコードが入っていますのでこれを実行します。(※今回使用するのはusersテーブルだけです。) 2014_10_12_000000_create_users_table.php 2014_10_12_100000_create_password_resets_table.php 2019_08_19_000000_create_failed_jobs_table.php $ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.41 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.43 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.31 seconds) ※migrationでエラーになるという場合は 【Laravel + Docker】migration で could not find driver が出たときの対応 が参考になるかもしれません。 ユーザーデータの登録 次にseedという機能を使ってデータを登録します。これはテストデータやマスターデータなど、開発するにあたって必要なデータを登録する機能です。 database/seeds/DatabaseSeeder.php DatabaseSeeder クラスは最初からあるコードで、このrunメソッドに記載されている seed が

【Laravel + MySQL】Dockerで開発環境を作る

イメージ
Docker、docker-compose.yml を利用して次の開発環境を作成する手順をまとめました。 WEBサーバー nginx:1.15.6 データベース mysql 5.7 アプリケーション php 7.2 フレームワーク laravel 6.2 構成について まずプロジェクト全体の構成は以下のようになっています。 . ├── docker │   ├── mysql │   │   └── my.cnf │   ├── php │   │   └── Dockerfile │   └── web │   └── default.conf ├── docker-compose.yml └── laravel-app 基本的には docker-compose.yml を用いてビルドしますが、PHPのみDockerfileを使います。 ※後に記載しますが、pdo_mysqlをコンテナにセットアップしたいためです。(これが分からなくて少し嵌りました。) 各ファイルについての詳細 Docker Compose docker-compose.yml docker-compose.yml の内容は以下です。 version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: build: ./docker/php volumes: - .:/var/www/html depends_on: - mysql mysql: image: mysql:5.7 command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci environment:

【Laravel + Docker】migration で could not find driver が出たときの対応

イメージ
Laravel + Dockerの環境を構築し、Laravel導入時から入っているmigrationを実行したところ could not find driver が出てデータベース接続に失敗したのでその際の解決方法をまとめます。 なお、データベースはDockerコンテナにMySQLを作成しています。 環境について Docker docker-compose.yml 環境はウェブサーバー、PHP、データベースでそれぞれコンテナを立てています。 version: '3' services: web: image: nginx:1.15.6 ports: - "8000:80" depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: image: php:7.3-fpm depends_on: - mysql volumes: - .:/var/www/html mysql: image: mysql:5.7 environment: MYSQL_DATABASE: test MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql volumes: mysql-data: migrationエラーについて セットアップ時に入っているmigration Laravelにはセットアップした段階で以下のように3つのmigrationファイルが入っているのでこれを実行してみます。 migrationを実行する $ php artisan migrate --seed Illuminat

【Android】VideoViewを使って動画再生アプリを作る④
-- 全画面で動画再生 --

イメージ
いよいよVideoViewを使って動画ファイルを再生する部分です。 実装 アプリケーションのタイトルバーを消す まずは全画面で表示させるために、アプリケーションのタイトルバーを消します。これにはAndroidManifest.xmlのActivityのテーマ指定を以下のようにします。 AndroidManifest.xml <activity android:name=".Mp4Activity" android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen" /> ナビゲーションバーを消す 次に下段のナビゲーションバー(戻るボタンやホームボタンのバー)を消します。これはActivity内のコードで以下のように制御します。 View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION ); 動画再生 Intentで受け取ったファイルパスをVideoViewに読み込みます。 読み込みの完了をOnPreparedListnerより受け取り、再生を開始します。その際に動画縦幅と横幅を比べて横長の動画の場合、画面の向きを変えて最大サイズで再生できるようにしています。 String path = getIntent().getStringExtra("path"); videoView = findViewById(R.id.videoView); videoView.setVideoPath(path); videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { if (mediaPlayer.getVideoWidt

【Android】VideoViewを使って動画再生アプリを作る③
-- カスタムリストビュー --

イメージ
ListViewコントロールをカスタマイズして、1つのレコードに様々な情報を表示する方法です。 実装 アイテムクラス まずはListViewの1レコードを表すアイテムクラスの定義です。次の属性を持ちます。 ファイル名 ディレクトリ サイズ 最終更新日 Item.java import java.util.Date; public class Item { private String name; private String path; private long size; private Date lastModified; public void setName(String name) { this.name = name; } public String getName() { return name; } public void setPath(String path) { this.path = path; } public String getPath() { return path; } public void setSize(long size) { this.size = size; } public long getSize() { return size; } public void setLastModified(Date lastModified) { this.lastModified = lastModified; } public Date getLastModified() { return lastModified; } } レイアウト 1レコード分のレイアウトを定義します。 layout/list_item.xml <?xml version="1.0" encoding="utf-8"?> <LinearLay

【Android】VideoViewを使って動画再生アプリを作る②
-- 内部ストレージのファイル検索 --

イメージ
内部ストレージのファイル検索について実装します。またファイルの検索中はプログレスダイアログを表示して操作できない状態にします。 実装 プログレスダイアログを表示 後述しますが、ファイル検索は並列処理(マルチスレッド)で行い、プログレスダイアログの表示をメインスレッドで行います。こうしておかないと画面の更新ができないためです。 final ProgressDialog progressDialog = new ProgressDialog(MainActivity.this); progressDialog.setTitle("ファイル検索中"); progressDialog.setMessage("---"); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setCancelable(false); progressDialog.show(); 内部ストレージのパスを取得 まずは検索する場所、内部ストレージのパスは以下で取得できます。また、これはマルチスレッドの中で使うのでfinalで宣言しておきます。 final String path = Environment.getExternalStorageDirectory().getPath(); 並列処理の実装 並列処理は Thread クラスを使用します。なお、通常はスレッド内からメインスレッドのUI (ここではプログレスダイアログ) へのアクセスはできません。これを解決するために Handler クラスを利用します。メインスレッドで定義した Handler クラスの run メソッドによりメインスレッドのUIの操作が可能になります。ここではファイル検索が終了したらメインスレッドのプログレスダイアログを閉じています。 final Handler handler = new Handler(); new Thread(new Runnable() { @Override public void run() { // ファイル検索開始 searchFiles(path);

【Android】VideoViewを使って動画再生アプリを作る①
-- ストレージへのアクセス権限を取得 --

イメージ
小さい子供に動画を見せていると、画面を触って停止してしまったりホーム画面へ戻ってしまったりということがあるので、これを防止した単純な動画再生アプリを作ってみます。 要件 はじめにざっくりとした要件をまとめます。 内部ストレージからmp4ファイルを検索 ※SDカードなどの外部ストレージは今回対象外 動画ファイル名をリスト表示 (できれば動画のイメージを取得してリスト上に表示したい、どうやって取得するんだろう...) ファイル名タップで全画面表示で動画再生 再生中に画面をタップしても何もしない 最後まで再生したら最初に戻って繰り返す 実装については以前作った Json Viewer の大部分が流用できると思うのでこれを改修していく形になります。 https://github.com/s-watanabe-apps/json-viewer.git こちらの実装についての詳細を、次回リスト編と再生編に分けて解説していこうと思います。 実装 内部ストレージからファイルを検索するので、アプリケーションにストレージへのアクセス権限が必要です。 通常権限を取得する場合、Android OSにより以下右のダイアログを出してユーザーに許可を求めます。しかし何のために該当の権限を利用するかこのダイアログだけではわかりません。左画像のように権限の利用目的を明示してあげるのが親切な設計です。 ※アプリケーションから権限の取得方法には以前 記事 にしましたが、今回は以下のように利用目的の表示を明示するようにしました。 権限設定 AndroidManifest.xml AndroidManifest.xmlに以下を追加します。 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 権限の確認と利用目的の説明 まずは権限が許可されているかをチェックし、許可されていない場合(もしくは初回起動のとき)に利用目的をユーザーに明示します。そこでOKを押してもらったときに requestP

【Java】ObjectMapperでJSONデータを変数に取り込む

ObjectMapperを使えばどんな型のjsonデータであっても変数に取り込んだり、またオブジェクトからjsonを出力したりすることができます。 過去に紹介した JSONObjectを使う方法 より全然楽です。 連想配列のJSON JSONデータ JSONデータは以下を使用します。 { "member_id":"1, "name":"Taro", "age":30, "address":"Tokyo" } JSONデータのParse処理 package com.example; import java.util.Map; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; public class App { public static void main(String[] args) { String json = "{\"member_id\":1,\"name\":\"Taro\",\"age\":30,\"address\":\"Tokyo\"}"; try { Map<String, Object> map = new ObjectMapper().readValue( json, new TypeReference<Map<String, Object>>() { }); for(Map.Entry<String, Object> entry : map.entrySet()){ System.out.printl

【Android】Dialog(画面)をスライドして表示する

イメージ
Androidアプリケーションで画面をスライドして表示させる方法のまとめです。 アニメーション定義 まずはスライドアニメーションを定義します。 resディレクトリ配下にanimディレクトリを作成し、以下ファイルを用意します。 res/anim/slide_in.xml <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fillAfter="false" android:fromXDelta="100%" android:fromYDelta="0" android:toXDelta="0" android:toYDelta="0" /> res/anim/slide_out.xml <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fillAfter="false" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100%" android:toYDelta="0" /> durationでスライドの速さを調整します。 スライドインするときはX座標

【Azure】Microsoft Azureについて(認定資格)

AzureはMicrosoftが提供するクラウド型サービスです。 これまでAmazon AWSに触れる機会が多くいくつか記事にもしてきましたが、近年シェアを伸ばしてきているのと、最近仕事で少し触れる機会があったので今後のためのメモとして残していこうと思います。 AWSとAzureのクラウドサービスにおけるシェアと売り上げ増加率   全体のシェア 売り上げ増加率 AWS 31% 48% Azure 18% 89% (2018年時点) これを見るとシェアでこそAWSに劣っていますが、その伸び率はAWSを追い越さんばかりの勢いです。 ※以下記事より抜粋しました。このほかにもAWSとAzureの双方のメリットデメリットが詳しく記載されています。 AWSとAzureの概要と比較!マルチクラウドについても解説 https://business.ntt-east.co.jp/content/cloudsolution/column-06.html 今後の記事が何かの役に立ちましたら幸いです。 認定資格 Microsoft公式のAzure認定資格については以下のようにセクション、およびレベル毎に用意されています。 Azure Fundamentals 受験料 ¥12,500 内容 Cloudの概念を理解 コアな Azure サービスを理解 セキュリティ、プライバシー、コンプライアンス、信用について理解 Azure の料金プランとサポートについて理解 公式ページ https://docs.microsoft.com/ja-jp/learn/certifications/azure-fundamentals Azure Administrator Associate 受験料 ¥21,103 内容 Azure サブスクリプションとリソースを管理する ストレージの作成と管理 仮想マシン(VM)の展開と管理 仮想ネットワーク

【PHP】Amazon SESでEメール送信

aws-sdk-phpを利用してAmazon SESからEメールを送信する方法のまとめです。 ※aws-sdk-phpのセットアップは以下リンク参照 【AWS】S3へファイルアップロード(PHP) 公式の詳細はこちら https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-using-sdk-php.html 実装 名前空間の定義 use \Aws\Credentials\CredentialProvider; use \Aws\Ses\SesClient; use \Aws\Exception\AwsException; 処理 /** * Amazon SES Sendmail * @param string $subject * @param string $body * @param string $to * @param string $from_email * @param string $from_name = null * @return bool * @throw Exception */ public static function send( string $subject, string $body, string $to, string $from_email, string $from_name = null ) : bool { try{ // ① 認証情報を取得 $provider = CredentialProvider::defaultProvider(); // ② SES Clientオブジェクト生成 $client = new SesClient(array( 'region' => 'us-west-2', 'version' => '2010-12-01', 'credentials' => $provid

【PHP, JavaScript】POSTデータが多すぎてエラーになったときにとった対応

画面からユーザーの入力値をPOSTするプログラムで500エラーが発生し、エラーログを確認すると以下のメッセージを吐いていました。 *413 FastCGI sent in stderr: "PHP message: PHP Warning: Unknown: Input variables exceeded nnn. このエラーはユーザーの入力値が多すぎて、submitしたときサーバー側で弾かれているエラーで、しきい値は php.ini の以下で設定できます。 php.ini ; How many GET/POST/COOKIE input variables may be accepted max_input_vars = 100 しかし本来セキュリティの観点から、この値は抑えられている(デフォルトは1000)ケースがあります。その場合は、フロント側で吸収する必要があるためその方法をまとめます。※あくまで一つの例なので他に良い方法があるかもしれません。 今回発生したケースでは、ユーザーや店舗などの設定値を縦に並べて一括で更新するという処理で、100は余裕で超えてしまうため対応を行いました。 POSTデータを入力するView(修正前) (※だいぶ簡単にしたもの) <form method="post" action="/users/index"> <input type="submit" name="regist">更新</input> <?php foreach($users as $user):?> <label><?php echo $user['id'];?></label> <label><?php echo $user['name'];?></label> <input type="text" name="age[<?php echo $user['id'];?&