独自で作ったブランチモデルの一通りのメモ
友達と一緒にHexoを使ったメディアを作ろうと言う話になった
Gitで管理して、リモートはGitHub、デプロイにはNetlifyを使う
迷ったときに見返す、完璧自分用メモ
Media-Flow
今回自分で作ってみたブランチモデル
過去に一度もブランチモデルなんて使ったことないのだが
メディアとして一般公開する予定だし、8ヶ月ほどの運営は確実なので使おうということになった
GitFlowとGitHub-Flowを参考にした
masterブランチ
Netlifyには、このブランチをデプロイするように設定してある
リリース用の、完全品質を保証するブランチ
develop
とpost
からのmergeのみで更新される
また、develop
からmergeするときにTagをつける
Tagをつける時以外、直接操作してはいけない
(Tag付けも自動で行いたい…)
developブランチ
開発用ブランチ
一般公開はまだしてないけど、ほぼ確定している
別途テスト用Netlifyサイトを用意し、そこに繋げる
開発者だけじゃない人たちでも、アクセスして確認ができる
Netlifyにはサイトにパスワードをかける機能があるので、それを使って身内限定にする
どうやら有料プランのようなので、URLを身内限定で共有するということにしておく
topicブランチのmergeのみで更新される
直接操作してはいけない
postブランチ
記事を投稿/変更/削除するためのブランチ
masterから派生している
HexoはMarkdownで記事がかける
そのmdファイルをPushする
Topic ブランチ
機能の追加/修正を行うブランチ
develop
から派生している
ブランチ名は{issue番号} {内容、スネークケース}
完成したら、develop
へプルリク
mergeされたdevelop
が、master
にmergeされたら
master
にmergeした人が削除する
感想
過去にブランチモデルを利用したことがない&さっき運用を始めた
なので、使い心地がどうとかはわからない
ただ、自分で作って、自分たちで使ったことによって
より一層Gitの使い方がわかった気がする
近いうちに使ってみた感想とか書きたい
参考記事
Dialogと仲良くなる その1
先日、RecyclerViewと仲良くなった(気がする)
次はDialogと仲良くなってみる
参考サイト
ひたすら公式
Android Developersに載っているコードをほぼまんま写した
公式を見る際に、日本語で見るとKotlinのコードが表示されない
なので、英語が苦手な方は英語と日本語交互に見ながらやるとよいだろう
(なんで日本語のはないんだろう・・・)
Fragment Dialog
公式より、Dialogを使うときはFragmentDialogを使いなさいと言われている
Fragmentか〜って感じではあるが、かのGoogle様直々のお願いなので守らなくてはいけない
どうやらFragmentを使うことにより、サイクルが確保される模様
お断り
Dialogには様々な種類がある
この記事では、全てのDialogを扱うわけではない
扱うDialog
Alert dialog
-> Alert dialogs interrupt users with urgent information, details, or actions.
Simple dialog
-> Simple dialogs display a list of items that take immediate effect when selected.
Confirmation dialog
-> Confirmation dialogs require users to confirm a choice before the dialog is dismissed.
扱わないDialog
Full-screen dialog
-> Full-screen dialogs fill the entire screen, containing actions that require a series of tasks to complete.
Date/Time PickerDialog
-> A dialog with a pre-defined UI that allows the user to select a date or time.
Custom Dialog
-> Dialogに表示するレイアウトをカスタマイズしたもの
Custom DialogとPickerDialogの説明以外は全てここから引用
PickerDialogはリファレンスより
また、今回利用するDialogは全てサポートライブラリのDialogである
コピっててなんかエラーが出るってなったらまずはimport文を見よう
下準備
MainActivtyのレイアウトと、Simple,Confirmationで扱うArrayListの定義は特筆することがないのでコードだけ
あとSnackbarを使うのでADSLも忘れずに
Android Design Support Library
これ入れとくだけでナウくなるからいっぱい好き
implementation 'com.android.support:design:27.1.1'
activity_main.xml
Dialogを呼び出すためのButtonを用意する
今回は5種類ほどDialogを実装する
<LinearLayout android:id="@+id/container" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:id="@+id/bt_basic" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Basic Dialog" android:layout_marginBottom="8dp" android:textAllCaps="false"/> <Button android:id="@+id/bt_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button Dialog" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:textAllCaps="false"/> <Button android:id="@+id/bt_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="List Dialog" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:textAllCaps="false"/> <Button android:id="@+id/bt_check" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="CheckBox Dialog" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:textAllCaps="false"/> <Button android:id="@+id/bt_radio" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="RadioBox Dialog" android:layout_marginTop="8dp" android:textAllCaps="false"/> </LinearLayout>
完成図
values/array.xml
ちゃんとリソースファイルを使う癖を付けなな〜とか思いつついつもサボる
<?xml version="1.0" encoding="utf-8"?> <resources> <array name="items"> <item>Item1</item> <item>Item2</item> <item>Item3</item> <item>Item4</item> <item>Item5</item> </array> </resources>
本題
では、実装していく
今回はDialogs
というパッケージを作って、そこにバコバコ入れていく
Basic Dialog
最も基本的なDialog
ただ文字を表示するだけ、正直使いどころはない
でも、基本を学ぶにはシンプルでちょうどいい
package net.oldbigbuddha.sample.sampledialog.Dialogs import android.app.Dialog import android.os.Bundle import android.support.v4.app.DialogFragment import android.support.v7.app.AlertDialog class BasicDialogFragment : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { val builder = AlertDialog.Builder(it) builder.setTitle("Basic Dialog") .setMessage("This is Basic Alert Dialog") builder.create() } ?: throw IllegalAccessError("Activity cannot be null") } }
本当に最小限の構成
onCreateDialog()
でAlertDialogを生成し、返り値にしてやる
ただそれだけ
Builderを作って、色々設定を加えて、create()
してやれば出来上がり
let{}
is何ってこは”Kotlin スコープ関数”で検索
MainActivityで呼び出し処理を書く
bt_basic.setOnClickListener { BasicDialogFragment().show(supportFragmentManager, "basic") }
setTitle()
で一番上のTitle部分に文字列をセットし
setMessage()
でメイン部分(Supporting text)に文字列をセットする
これはデザイン的な話になるが
GoogleはTitle部分に曖昧な文言を設定することを推奨していない
例えば”Are you sure?”である
なるべく読み取れる意味を絞れってはなしですな
Button Dialog
公式的には”Alert Dialog”らしい
右下にボタンがついてるDialog
ココらへんから使いどころがでてくるかな
PositiveButton(OKやAgreeなど)は必ず右側に置かないといけない(自動で置かれるので気にする必要はない)
package net.oldbigbuddha.sample.sampledialog.Dialogs import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.support.v4.app.DialogFragment import android.support.v7.app.AlertDialog class ButtonDialogFragment: DialogFragment() { lateinit var onClickPositive: DialogInterface.OnClickListener lateinit var onClickNegative: DialogInterface.OnClickListener override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { val builder = AlertDialog.Builder(it) builder.setTitle("Button Dialog") .setMessage("This is Button Dialog") .setPositiveButton("OK", onClickPositive) .setNegativeButton("cancel", onClickNegative) builder.create() } ?: throw IllegalAccessError("Activity cannot be null") } }
Listenerを利用して、タップされた時の処理を外で書くようにする
setPositiveButton()
で肯定的なアクションを
setNegativeButton()
で否定的なアクションを設定する
第一引数でボタンに表示する文字列を設定する(リソースファイルぅ)
MainActivityで呼び出す
bt_button.setOnClickListener { val fragment = ButtonDialogFragment() fragment.onClickPositive = DialogInterface.OnClickListener { _, _ -> Snackbar.make(container, "OnClick 'OK'", Snackbar.LENGTH_SHORT).show() } fragment.onClickNegative = DialogInterface.OnClickListener {_, _ -> Snackbar.make(container, "OnClick 'cancel'", Snackbar.LENGTH_SHORT).show() } fragment.show(supportFragmentManager, "button") }
まぁ、タップしたらSnackbarがでてくるというもの
たまに”OK”、”Cancel”ときて、第三のButton”Learn more”がでてくるDialogがある
material.io曰く、第三のButtonは本来不要で、他の場所で補うべきだと述べている
Rather than adding a third action, an inline expansion can display more information. If more extensive information is needed, provide it prior to entering the dialog.
List Dialog
公式的には”Simple Dialog”
Listを表示するDialog
タップした内容を取得できる
package net.oldbigbuddha.sample.sampledialog.Dialogs import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.support.v4.app.DialogFragment import android.support.v7.app.AlertDialog import android.util.Log import net.oldbigbuddha.sample.sampledialog.R class ListDialogFragment: DialogFragment() { lateinit var onSelectedItem: DialogInterface.OnClickListener override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { val builder = AlertDialog.Builder(it) builder.setTitle("List Dialog") .setItems(R.array.items, onSelectedItem) builder.create() } ?: throw IllegalAccessError("Activity cannot be null") } }
setItems()
で配列とListenerを投げてやる
MainActivityの方で、タップした位置を取得することができる
bt_list.setOnClickListener { val fragment = ListDialogFragment() fragment.onSelectedItem = DialogInterface.OnClickListener {_, index -> resources?.let { val item = it.getStringArray(R.array.items)[index] Snackbar.make(container, "Selected $item", Snackbar.LENGTH_SHORT).show() } } fragment.show(supportFragmentManager, "list") }
(仮引数の名前をindex
としているが、position
のほうがいいかもしれない)
特別変なことはしていない
let関数
の中で自身を指定する場合はit
を使う
それぐらい?
Resource周りは勉強しといたほうが良い(人のこと言えない)
図は、item2を選択した場合のSnackbar
RadioBox Dialog
公式的には”Confirmation Dialog”
リファレンスを見ると、setSingleChoiceItems()
を利用しているので
Single Choice Dialogっていうのが一番正しい名前なのかね
package net.oldbigbuddha.sample.sampledialog.Dialogs import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.support.v4.app.DialogFragment import android.support.v7.app.AlertDialog import net.oldbigbuddha.sample.sampledialog.R class RadioBoxDialogFragment: DialogFragment() { lateinit var onSelectedItem: DialogInterface.OnClickListener lateinit var onClickPositive: DialogInterface.OnClickListener var selectedIndex = 0 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { val builder = AlertDialog.Builder(it) builder.setTitle("RadioBox Dialog") .setSingleChoiceItems(R.array.items, 0/* default selected */,onSelectedItem) .setPositiveButton("OK", onClickPositive) builder.create() } ?: throw IllegalAccessError("Activity cannot be null") } }
少し個人的には納得していないコード
setSingleChoiceItems()で設定したListener内で、選択されたItemのindexが取れる(
fragment.selectedIndex = index`)
それをフィールドで保存してやり、MainActivityで呼び出すことで選択されたItemを取れるようにしている
bt_radio.setOnClickListener { val fragment = RadioBoxDialogFragment() fragment.onSelectedItem = DialogInterface.OnClickListener { _, index -> resources?.let { fragment.selectedIndex = index } } fragment.onClickPositive = DialogInterface.OnClickListener{ _, _ -> resources?.let { val item = it.getStringArray(R.array.items)[fragment.selectedIndex] Snackbar.make(container, "Selected $item", Snackbar.LENGTH_SHORT).show() } } fragment.show(supportFragmentManager, "radio") }
ちなみにsetSingleChoiceItems()
の第二引数に-1を設定すると標準で無選択になる
CheckBox Dialog
本記事最後のDialog、公式的には”Confirmation Dialog”
さっきのがsetSingleChoiceItems()
だったのに対し、これはsetMultiChoiceItems()
を使う
う〜ん、わかりやすい
package net.oldbigbuddha.sample.sampledialog.Dialogs import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.support.v4.app.DialogFragment import android.support.v7.app.AlertDialog import net.oldbigbuddha.sample.sampledialog.R class CheckBoxDialogFragment: DialogFragment() { lateinit var onClickPositive: DialogInterface.OnClickListener lateinit var onClickNegative: DialogInterface.OnClickListener lateinit var onMultiSelected: DialogInterface.OnMultiChoiceClickListener override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { val builder = AlertDialog.Builder(it) builder.setTitle("CheckBox Dialog") .setMultiChoiceItems(R.array.items, null/* default selected */,onMultiSelected) .setPositiveButton("OK", onClickPositive) .setNegativeButton("cancel", onClickNegative) builder.create() } ?: throw IllegalAccessError("Activity cannot be null") } }
さっきのSingle同様リスナーを渡します
setMultiChoiceItems()
の第二引数はbooleanの配列です
trueのところを選択状態にしてくれます
bt_check.setOnClickListener { val fragment = CheckBoxDialogFragment() val mSelectedItems = ArrayList<Int>() // Where we track the selected items fragment.onMultiSelected = DialogInterface.OnMultiChoiceClickListener { _, index, isChecked -> if (isChecked) { mSelectedItems.add(index) } else if (mSelectedItems.contains(index)) { mSelectedItems.remove( Integer.valueOf(index) ) } } fragment.onClickPositive = DialogInterface.OnClickListener { _, _ -> resources?.apply { val mSelectedItemContents = ArrayList<String>() mSelectedItems.forEach { mSelectedItemContents.add(this.getStringArray(R.array.items)[it]) } Snackbar.make(container, "Selected $mSelectedItemContents", Snackbar.LENGTH_SHORT).show() } } fragment.show(supportFragmentManager, "checkbox") }
う〜ん、長い
そしてキモい(forEach in スコープ関数
ということでthisが使えるapplyで対処した)
まぁ、大体CheckBox
を実装するときと同じですな
タップされたものがFalseならTrueに、TrueならFalseへ
OnMultiChoiceClickListener()
で取れたTrace配列はInt型ですので
中の数値ををIndexとしてItem配列から選択されたItemをとりだします
まさかこんなところでforEach()
に出会うとは、、、(やぎにぃに感謝)
さぁ、これで全てが出揃った
個人的にはDialogととりあえずは仲良くなれたように思える
あとはFull-ScreenとCustomとPicker、、、
ま、のんびりやっていきます
今回のコードのまとめはこちらから見ることができます
意味わかんねぇよとか、ここエラーでたんですけどとかあったらTwitterでメンション投げてください
@OJI_1941です(ごめんなさいDM閉じてるんで最初はメンションでお願いします)
ありがとうございました
RecyclerViewと仲良くなる
いや今更かよっていう話ではある
しかしながら、私はRecylerViewといつまで経っても仲良くなれず
非常に悶々とした日々をすごした過去を持つ
たまたま久々にAndroidを触り、RecyclerViewと戯れる機会を得たので
真摯に向き合ってみると案外難しくはなかった
てことでちょこっとだけ説明を加えたSample
ゴール
今回はTODOリストもどきを作っていく
アプリを閉じると内容は削除されるし、ソートとかもないので
本当にガワだけである
EdiText
に入力された内容がRecyclerView
に表示される流れに重きを置く
右側の+
ボタンを押すとEditTextの内容が下のRecyclerViewに表示される
Item(一行)の右側のー
ボタンを押すとそのItemが削除される
下準備
とりあえずプロジェクトを新規作成
minSdkは23、targetSdkは27
1.Android Support Design Library
そしてbuild.gradleにADSLを追加
RecyclerView単体もあるが、TextInputLayoutだったりSnackbarを使いたかったので
implementation 'com.android.support:design:27.1.1'
2.ボタン素材(Googleに感謝)
続いて素材を追加
AndroidStudioからGoogleが公開しているMatrial Iconが利用できるので
+
と-
をVectorで取ってくる
ファイル名はic_add_black_24dp.xml
とic_remove_black_24dp.xml
(File -> New -> Vector Asset
で追加できる)
3.Itemのレイアウトを作成
続いて一行一行をレイアウトするためにファイルを作成する
res > layout
にitem.xml
を作成
レイアウトを組んでいく
今回必要なのは
- EditTextに入力された内容を表示するTextView
- 作成日時を表示するTextView
- RemoveをするImageButton
以上3つ
以下そのレイアウト
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="60dp"> <TextView android:id="@+id/tv_name" android:layout_height="match_parent" android:layout_width="0dp" android:layout_weight="4" android:textSize="18sp" android:textColor="#000" android:gravity="center|start" android:paddingStart="4dp" /> <TextView android:id="@+id/tv_created_at" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="3" android:text="XXXX/XX/XX" android:textSize="12sp" android:gravity="bottom|end" android:paddingStart="8dp" android:paddingEnd="24dp" android:paddingBottom="16dp"/> <ImageButton android:id="@+id/bt_remove_item" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:src="@drawable/ic_remove_black_24dp" android:background="#000f" android:layout_gravity="center" /> </LinearLayout>
各値はお好みで
ここで特徴なのが親のLinearLayout
の高さが固定であるということ
wrap_content
でも良いのだが、Buttonが小さくなって誤タップが生じてしまうため
ある程度の高さを用意してあげる
ImageButton
は背景をRGBAで透明にしてあげる
本番
Adapter
RecyclerView
はAdapter
にかかっていると言っても過言ではない
RecyclerView
に関する操作は全てAdapter
で行う
某所でAdapter
はRecyclerView
にデータを渡す橋渡し役だと習った
そんな橋渡し役のコードがこちら
package net.oldbigbuddha.sample.sample_recyclerview import android.content.Context import android.support.v7.widget.RecyclerView import android.text.format.DateFormat import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageButton import android.widget.TextView import kotlinx.android.synthetic.main.item.view.* class ItemAdapter( private val mItems: ArrayList<Item>, private val mContext: Context ): RecyclerView.Adapter<ItemAdapter.ViewHolder>() { override fun getItemCount(): Int = mItems.size // Itemを追加する fun addItem(item: Item) { mItems.add(item) notifyDataSetChanged() // これを忘れるとRecyclerViewにItemが反映されない } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item, parent, false)) // Itemを削除する private fun removeItem(position: Int) { mItems.removeAt(position) notifyItemRemoved(position) notifyDataSetChanged() // これを忘れるとRecyclerViewにItemが反映されない } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.tvName.text = mItems[position].mName // reference: Y.A.M の 雑記帳: SimpleDateFormat ではなく android.text.format.DateFormat を使おう - http://bit.ly/2OybKLu holder.tvCreatedAt.text = DateFormat.format("yyyy/MM/dd kk:mm:ss", mItems[position].mCreatedAt).toString() holder.btRemoveItem.setOnClickListener { removeItem(position) } } class ViewHolder(view: View): RecyclerView.ViewHolder(view) { val tvName: TextView = view.tv_name val tvCreatedAt: TextView = view.tv_created_at val btRemoveItem: ImageButton = view.bt_remove_item } }
RecyclerViewの特徴の1つに必ずViewHolderを実装しないといけないというものがある
ViewHolder is 何 という方はここでは詳しく説明しないのでググっろう
findViewById()
は結構実行コストが高いので、一度findしてきたものを保持しておく
だからHolderにViewを入れておく
そんな感じ
私がRecyclerViewと仲良くなれなかった一番最初の原因は
クラスを書いてる間最初しばらくはエラーが出ること
以下の順番で書くとよい
class ~~: RecyclerView.Adapter<~~.ViewHolder>() {}
を書く- ViewHolderをぱぱっと書く(kotlin-android-extensionsのお陰で簡単に書けるようになった)
onCreateViewHolder
とonBindViewHolder
をoverrideする- あとは適当に書いていく
Ctrl-OでOverrideできるメソッド一覧がでるので、活用すると良い
notifyDataSetChanged()
を忘れると更新されないので注意(これ結構やられる)
MainActivity
あとはひょろひょろ〜と書いていく
- ちゃんと
Toolbar
を設定すること - RecyclerViewにAdapterを設定すること
この2つを忘れなければハマることはない(はず)
package net.oldbigbuddha.sample.sample_recyclerview import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.support.design.widget.Snackbar import android.support.v7.widget.LinearLayoutManager import android.text.TextUtils import kotlinx.android.synthetic.main.activity_main.* import java.util.ArrayList class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Set Toolbar setSupportActionBar(my_toolbar) // my_toolbar.inflateMenu(R.menu.menu_main) // Initialize RecyclerView recycler_items.layoutManager = LinearLayoutManager(this) // Initialize Adapter val adapter = ItemAdapter(ArrayList(), this) bt_add_item.setOnClickListener { if ( !TextUtils.isEmpty( et_item.text.toString() ) ) { val task = Item( mName = et_item.text.toString() ) adapter.addItem(task) } else { Snackbar.make(container, "Task is empty", Snackbar.LENGTH_SHORT).show(); } et_item.setText("") } recycler_items.adapter = adapter } }
Toolbarに色々仕込みたい場合はsrc > menu
を作って
よしなに書いてinflateしてあげれば良い
ちゃんとEditTextの中身は検査しよう
これで無事動く
最後に
今回のサンプルコードはここからまとめて見れます
たまに更新するかもしれない
もしわからなかったらTwitterで@OJI_1941にメンション投げてください
すぐ食いつきます(すみませんDMは基本閉じてます)
aptでDebianにYarnをインストールした
少し前にDebianにNode.jsを突っ込む記事を書いた
その後しばらくnpmを使っていたのだが
どうやらYarnという素晴らしいものがあるらしい
友人が使え使えと言ってくるので、とりあえずインストールしてみた
その時のメモ
実は上記の記事通りcURLでスクリプトを取ってきて実行すると
最後にこんな記述がある
## Run `sudo apt-get install -y nodejs` to install Node.js 8.x LTS Carbon and npm
## You may also need development tools to build native addons:
sudo apt-get install gcc g++ make
## To install the Yarn package manager, run:
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
記事を書いた当時はYarnなんて一切興味がなかったので
スルーしていたのだが、たまたまNode.jsを別機にいれる時に発見
早速コピペしてみる
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg |\
sudo apt-key add
echo "deb https://dl.yarnpkg.com/debian/ stable main" | \
sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install yarn
入ったかを確認
yarn --version
1.10.1
無事インストールできた
AndroidのStatusbarの背景色を変更する
TwitterとかSlackのアプリを開いてみると
上のステータスバー(時間とか電力が表示いされてる所)の色が
ちゃんとActivityに合っている
でも、いざ自分で作ってみると当然自動的に合うわけがない
ステータスバーの色をこちら側で固定するメモ
思ったより簡単
以下のコードで無事好きな色を設定することができる
// Hide Statusbar
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = ContextCompat.getColor(this, R.color.theme)
ContextCompat.getColor()
を使うことがコツ
これを使えばcolor.xmlで定義してるコードを簡単に使うことができる
確かAPI21以降対応してたはず
今回はこれまで
Debian9にNode.jsのLTS版を入れる
更新 2018/11/12
10がLTSになったので、10に更新しました
すでに8や6をインストールされている方は一度アンインストールをされることをオススメします
==追記以上==
何も考えずに
sudo apt install nodejs
なんてすると悲しい結果になる
(実行コマンドがnodejsになり、かつバージョンが古い)
てことで2018/04/12 2018/11/12時点の最新LTS及びnpmを導入する手順をメモ
参考サイトは以下
linuxconfig.orgココに書いてある内容が 8 10系になっただけ
インストール
以下のコマンドをコピって貼っつける
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
後は普通にaptでインストールするだけ
まぁ簡単
sudo apt install nodejs build-essential libssl-dev
最後にバージョンを確認して終わり
node -v
-> v10.13.0
npm -v
-> 6.4.1
Bot職人にでもなりましょうかね〜
Debian9のキーボード配列を変える
状況
キーボード入力ではFcitxを使用して管理をしている
USに組み替えた後にしっかり変更したはずなのになんか一部ずれた挙動をする
どうすればいいのだろうと調べてたら以下の記事を見つけたのでDebianでやってみる
やってみる
sudo dpkg-reconfigure keyboard-configuration
これでコンフィグ画面が現れるのだが
言語設定がおかしいのか、めでたく文字化け
こういうミスるとヤバそうな設定画面がしっかり読めないのは痛い
先述の記事のスクショを信用してことを運ぶ
文字数的に選択している行は「標準 102 キー (国際) PC」
これを選択して次へ
ここまで化けられると何もわからなくて心配になる
先頭の「英語 (US)」を選択
AltGrってなんぞやってことでググってみる
どうやら装飾キーの一種で、欧州のほうの文字を入力する際に用いるらしい
もし今後欧州の文字を入力する機会がある場合はここをいじれば良いのか
(果たして機会は・・・)
今は縁がないのでデフォルトでスルー
わからないときはデフォルトですな
Compose Keyってなんぞやってことで再度ググる
さっきと一緒で装飾キーの一種
二打鍵で一つの文字を入力する時に使うらしい
欧州の方は大変ですな
コンポーズキー (Compose, Comp)
後続のアルファベットとアクセント記号(と似た形の記号)を合成するよう指示するためのキー。たとえば、「Compose」「a」「'」の順に入力すると「á」が入力される。
from 修飾キー - Wikipedia
最後にX Serverが死んだ時に強制終了するショートカットを追加するかどうか
まぁ、なしでいいでしょう(適当)
以上で設定は終了
無事正しい配列認識になりました
これでようやくまともにコーディングができる