よく忘れるのでタイトルに書いたルールがあることをここに残しておく
サウナにハマるきっかけになった温泉:箱根湯寮
この記事は「サウナAdvent Calendar 2023」の12日目の記事です。
箱根湯寮
箱根湯寮とは箱根湯本にある温泉です。
箱根湯本駅からも割りと近いのですが、激坂を登った先にあるため駅からシャトルバスで行くことをおすすめします。
温泉自体はアルカリ性の単純温泉のため肌の弱い自分にも優しく入りやすい温泉です。
一通り温泉を楽しんだらあとはサウナですね。私は以前、せまく暑苦しい空間でじっとしていないといけないことがよく理解できず、その後キンキンに冷えた水風呂に浸かるのもヒートショックになるじゃんと思っていたためサウナ自体を避けていましたが、箱根湯寮のサウナに入ってその思い込みが見事に崩れ去りサウナにハマりました。
ロウリュウサービス
箱根湯寮のサウナにはロウリュウサービスがあります。 日替わりで楽しめるアロマ水をサウナ石にかけ、一気に温度が上がったところで熱波師が大きな団扇で我々を仰ぎ始めます。
自分がロウリュウを受けた時は梅のフレーバーのアロマ水をかけていましたが、すぅっと心地よいアロマを感じた直後に浴びる熱風が素晴らしいですね。
一度にかけるアロマ水の量がそもそも多いのですが「アロマ水をかける→うちわで扇ぐ」を1セットとして何度もこのセットを繰り返すので、どんどん仕上がっていきます。 希望すればおかわりも可能です(が限界が来たらいつでもすぐに飛び出しましょう)。
水風呂
アツアツのサウナのあとの水風呂も気持ちよく、沢の水を引いてきているため季節によって水温は前後しますが、だいたい16度~18度くらい。 正直13度とか14度とかのキンキンに冷えた水風呂は未だに慣れないので、箱根湯寮くらいの水温がサウナにハマるにはちょうどよかったのかもしれません。
水風呂のあと更にサウナに行くと、ロウリュウサービスのアロマがまだこってり残っているので引き続き仕上がりを感じられます。
初めてサウナで整う感覚を得られたような気がして、以後温泉に行ったらサウナにも行くようになりました。
Jetpack Compose TextField の横幅を n 文字分だけ確保したい
View の仕組みでは、 TextView のプロパティとして ems が定義してあり、これを利用するとTextView の横幅を ems で指定した文字数分の横幅にしてくれます。
Jetpack Compose では Text や TextField にそのものズバリな引数や Modifier はないので、自分で計算します。
TextMeasurer で横幅を計算する
TextMeasurer はその名の通り文字を描画するのに必要な領域を計算するクラスです。テキストスタイルや親コンポーネントの縦横の大きさを制約として与えることで、テキストが領域内に収まり切るかどうかも計算可能です。
今回は TextField の横幅を常に一定に保つため、あらかじめダミーの文字列を用意して TextMeasurer に食わせて横幅を計算します。これでダミーの文字列の長さの分だけ横幅を確保することになります。 次の例では数字6文字分の横幅を計算します。
// 数字6文字分を TextField の横幅にするときの、数字6文字分の横幅を計算 val measurer = rememberTextMeasurer() val measureResult = measurer.measure( text = "000000", maxLines = 1, )
TextField の PaddingValues を求める
TextField は内部で PaddingValues を設定しており、自動でスペースをつけています。
このスペースの大きさは TextField のスタイルによって異なります。
OutlinedTextField ならば outlinedTextFieldPadding() で、TextField の場合は label があるときは textFieldWithLabelPadding()、label がないときは textFieldWithoutLabelPadding() が標準の PaddingValues です。
TextMeasurer で計算した横幅と PaddingValues の水平方向の padding を足し合わせる
TextMeasurer で計算した横幅と PaddingValue の水平方向の padding を足し合わせると、TextField の横幅が計算できます。 TextMeasurer で計算した横幅は px なのに対し、PaddingValues が持つスペースは dp を単位にしているので、TextMeasurer で計算した横幅を dp になおす必要があります。
val measurer = rememberTextMeasurer() val measureResult = measurer.measure( text = "000000", maxLines = 1, ) val padding = textFieldWithoutLabelPadding() TextField( modifier = Modifier.width( with(LocalDensity.current) { measureResult.size.width.toDp() + padding.calculateStartPadding(LocalLayoutDirection.current) + padding.calculateEndPadding(LocalLayoutDirection.current) } ) )
注意点
今回は数字のみで文字列の横幅を計算しましたが、全角文字を入れたりするとまた計算が変わってきそうです。 TextMeasure#measure はフォントの種類や文字の大きさなども考慮して横幅を計算できますが、今回のように与えられた文字数に必要な横幅を計算するために予め決め打ちした文字で計算すると、実際に入力した文字によってはどうしてもズレが出ます。
近況2023
この記事は「mhidakaが2つ目を建立したAdvent Calendar 2023」の10日目の記事です。近況を報告せよとのことだったので、なんとなく今年のハイライト的な記事を書いておきます。
今年たのしかったこと
桜のAACR
AACRとは長野県の安曇野市周辺で開催される自転車のロングライドイベントです。レースではなく、設定されたチェックポイントを各々のペースで巡るイベントです。 以前にも参加したことはありますが、コロナ禍が始まって以降は開催も久しぶりでした。
AACRは年に2度開催され、桜と銘打ったAACRは4月中旬、緑と銘打ったAACRは5月中旬に開催されます。 今回は桜のAACRということで4月の安曇野を駆け巡りましたが、当日は近年稀に見る極寒のAACRとなりました。4月も半ばだというのに朝は真冬の寒さで震えながらのスタートでした。

Droidcon Vietnam
超絶弾丸日程のベトナム(ホーチミン)でしたが楽しめました。数ある Droidcon の中でも際立ってチケット代が安い Droidcon Vietnam ですが、参加者は APAC を中心にいろいろなところから来ていて盛り上がりを感じました。 ホーチミンは以前旅行できたことがあるのでなんとなく覚えている場所もありましたが、やはりGrabで気軽に移動できるのが強いですね。
ちなみに次の写真の真ん中らへんに写っているピンクのやつが見た目に反して異様な苦味と辛さを備えていて涙目になりました。結局今もこれが何なのかよくわかっていません。

北海道旅行
人生3度目の北海道旅行です。今回はどうしても運転してみたい車がレンタカーにあるということでそれを乗りつついままで行ったことのない地域に行くという旅行でした。 シルバーウィークにかぶせてDroidKaigi 2023が終わった翌日に北海道に行くという少々おかしな日程を組んでいましたが、北海道についてからも少々おかしな行程で旅行をしました。
初日は新千歳に着陸後すぐ車を確保し、そのまま苫小牧や新冠を経由(わざわざ遠回り)して帯広に行く行程。

2日目は帯広から周辺をうろつきつつ池田町のワイン城を見てから摩周湖や屈斜路湖に行き、北見に至る行程。

3日目は北見から一旦網走に出て、そこから上川に寄り道をしつつ札幌に至る行程。

最終日は札幌から洞爺湖、室蘭に抜けて新千歳に戻る行程。

節子、それ旅行やない!ただのドライブや!!
全部で1300kmほど移動していたらしいですが、元々長距離の運転に苦を感じない(+いい車が借りれたので楽だった)ので、また行きたいという気持ちです。 帯広のハゲ天で食べた天丼と朝イチから並んでいるパン屋さん(ますやパン)、北見のバルで食べたサガリ肉のステーキと余市ワイン、ちょうどいい時期にやっていたさっぽろオータムフェストと、食べ物も一通り楽しみました。
ちなみに借りた車はこちら。スバルのアウトバックです。

心残りがあるとすれば、北海道をウロウロしている間いろいろないい景色を見てきましたが、写真以外はほぼ脳内にしか記録がないこと。次は車載動画もやってみたいところです。
ジャパンカップサイクルロードレース撮影
自転車競技のシーズン終盤に行われる、日本では珍しい国際的な自転車レースです。欧州で活躍するプロがやってきて眼の前を駆け抜けるのでファンの人気も高い。 毎年ひとりで足を運んでカメラ小僧になっていますが、今年は e10dokup さんを誘って行きました。
当初はレースが始まる頃には雨が上がっている予報でしたが、実際にはレースが終わるまで見事に雨。機材を濡らさない強い気持ちはありましたが自分自身は守れませんでした。 でもいい写真が取れたのでOKです。


今年買ってよかったもの
デロンギの自動でコーヒーいれるやつ
最高
Pixel Fold
待望のやつ
上川大雪の日本酒
うまい

ツルヤのPB商品
安定
WorkManager Migration to 2.9.0
AndroidX WorkManager の 2.9.0 がリリースされました。以前のバージョンからこのバージョンに上げるにはマイグレーションが必要です。
https://developer.android.com/jetpack/androidx/releases/work?hl=en#2.9.0
Configuration.Provider の実装
2.8.x 以前は次のような定義でした。
interface Provider { fun getWorkManagerConfiguration(): Configuration }
この定義が 2.9.0 では次のように変わりました。
interface Provider { val workManagerConfiguration: Configuration }
このインタフェースは Application クラスで実装せよとあるので、2.8.x 以前であれば次のような実装になるはずです。
class MyApp : Application(), Configuration.Provider { override fun getWorkManagerConfiguration(): Configuration = Configuration.Builder() .setMinimumLoggingLevel(Log.VERBOSE) // ... do your configuration customization .build() }
2.9.0 へのアップデートでは、次のように書き換わります。
class MyApp : Application(), Configuration.Provider { override val workManagerConfiguration: Configuration = Configuration.Builder() .setMinimumLoggingLevel(Log.VERBOSE) // ... do your configuration customization .build() }
HiltWorkerFactory と組み合わせる
次の記事で紹介した方法で、WorkManager と Hilt を組み合わせることができます。
Hilt は各種 Worker に依存を注入するために独自の WorkerFactory を使います。そのため、Application クラスで次のように WokerFactory を注入して Configuration に渡しているはずです(2.8.x 以前)。
class MyApp : Application(), Configuration.Provider { @Inject lateinit var workerFactory: HiltWorkerFactory override fun getWorkManagerConfiguration(): Configuration = Configuration.Builder() .setWorkerFactory(workerFactory) // ... do your configuration customization .build() }
WorkManager 2.9.0 へアップデートするとき、Hilt と組み合わせている場合は先程の書き換え方をそのまま適用すると workerFactory が注入される前に Configuration を作ってしまうためアプリがクラッシュします。
class MyApp : Application(), Configuration.Provider { @Inject lateinit var workerFactory: HiltWorkerFactory override val workManagerConfiguration: Configuration = Configuration.Builder() .setWorkerFactory(workerFactory) // ... do your configuration customization .build() }
正しく動作するよう書き換えるには次のように getter で Configuration を作成します。
class MyApp : Application(), Configuration.Provider { @Inject lateinit var workerFactory: HiltWorkerFactory override val workManagerConfiguration: Configuration get() = Configuration.Builder() .setWorkerFactory(workerFactory) // ... do your configuration customization .build() }
DEEDS BREWING #BeerAdventCalendar2022
この記事は Beer Advent Calendar 2022 - Adventar の 9 日目の記事です。

これがうめぇんだ!
DEEDS XPA
しっかりとした苦味がありつつ、後味スッキリですいすい飲めます。 最高です。
DEEDS DOUBLE TIME
さっきの XPA の苦味と後味にくわえ、HAZY PALE らしいフルーティーさが合わさった感じですいすい飲めます。 最高です。
DEEDS BREWING #BeerAdventCalendar2022
この記事は Beer Advent Calendar 2022 - Adventar の 9 日目の記事です。

これがうめぇんだ!
DEEDS XPA
しっかりとした苦味がありつつ、後味スッキリですいすい飲めます。 最高です。
DEEDS DOUBLE TIME
さっきの XPA の苦味と後味にくわえ、HAZY PALE らしいフルーティーさが合わさった感じですいすい飲めます。 最高です。