-
-
Notifications
You must be signed in to change notification settings - Fork 2
Android 16のLive Update(ProgressStyle通知)に対応 #5387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
7f16ed4
Android 16のLive Update(ProgressStyle通知)に対応
claude a38a6f4
boundStationNameの「方面」二重付与と英語混在を修正
claude 16263f8
LiveUpdateModuleのnull安全性を強化
claude ce9e209
ReadableMapの防御的な拡張関数を追加してキー欠損時のクラッシュを防止
claude 38d9501
通知のcontentTextに種別+方面、subTextに路線名のみを表示するよう変更
claude d8c7229
ProgressStyleのトラッカーアイコンをラインカラー塗りつぶし+白ボーダーの円に変更
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
152 changes: 152 additions & 0 deletions
152
android/app/src/main/java/me/tinykitten/trainlcd/LiveUpdateModule.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| package me.tinykitten.trainlcd | ||
|
|
||
| import android.app.Notification | ||
| import android.app.NotificationChannel | ||
| import android.app.NotificationManager | ||
| import android.app.PendingIntent | ||
| import android.content.Context | ||
| import android.graphics.Color | ||
| import android.graphics.drawable.Icon | ||
| import android.os.Build | ||
| import com.facebook.react.bridge.ReactApplicationContext | ||
| import com.facebook.react.bridge.ReactContextBaseJavaModule | ||
| import com.facebook.react.bridge.ReactMethod | ||
| import com.facebook.react.bridge.ReadableMap | ||
|
|
||
| class LiveUpdateModule(reactContext: ReactApplicationContext) : | ||
| ReactContextBaseJavaModule(reactContext) { | ||
|
|
||
| companion object { | ||
| private const val CHANNEL_ID = "live_update" | ||
| private const val NOTIFICATION_ID = 49152 | ||
| private const val MAX_PROGRESS = 1000 | ||
| } | ||
|
|
||
| override fun getName() = "LiveUpdateModule" | ||
|
|
||
| private fun getNotificationManager(): NotificationManager = | ||
| reactApplicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | ||
|
|
||
| private fun ensureChannel() { | ||
| val nm = getNotificationManager() | ||
| if (nm.getNotificationChannel(CHANNEL_ID) != null) return | ||
|
|
||
| val channel = NotificationChannel( | ||
| CHANNEL_ID, | ||
| "運行情報", | ||
| NotificationManager.IMPORTANCE_DEFAULT | ||
| ).apply { | ||
| description = "現在の運行状況をリアルタイムで表示します" | ||
| setShowBadge(false) | ||
| lockscreenVisibility = Notification.VISIBILITY_PUBLIC | ||
| } | ||
| nm.createNotificationChannel(channel) | ||
| } | ||
|
|
||
| private fun createContentIntent(): PendingIntent { | ||
| val intent = reactApplicationContext.packageManager | ||
| .getLaunchIntentForPackage(reactApplicationContext.packageName) | ||
| return PendingIntent.getActivity( | ||
| reactApplicationContext, | ||
| 0, | ||
| intent, | ||
| PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE | ||
| ) | ||
| } | ||
|
|
||
| @ReactMethod | ||
| fun startLiveUpdate(state: ReadableMap) { | ||
| if (Build.VERSION.SDK_INT < 36) return | ||
| postProgressNotification(state) | ||
| } | ||
|
|
||
| @ReactMethod | ||
| fun updateLiveUpdate(state: ReadableMap) { | ||
| if (Build.VERSION.SDK_INT < 36) return | ||
| postProgressNotification(state) | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| @ReactMethod | ||
| fun stopLiveUpdate() { | ||
| getNotificationManager().cancel(NOTIFICATION_ID) | ||
| } | ||
|
|
||
| @Suppress("NewApi") | ||
| private fun postProgressNotification(state: ReadableMap) { | ||
| ensureChannel() | ||
|
|
||
| val stationName = state.getString("stationName") ?: "" | ||
| val nextStationName = state.getString("nextStationName") ?: "" | ||
| val approaching = state.getBoolean("approaching") | ||
| val stopped = state.getBoolean("stopped") | ||
| val lineName = state.getString("lineName") ?: "" | ||
| val lineColor = state.getString("lineColor") ?: "#000000" | ||
| val progress = state.getDouble("progress") | ||
| val trainTypeName = state.getString("trainTypeName") ?: "" | ||
| val boundStationName = state.getString("boundStationName") ?: "" | ||
| val passingStationName = state.getString("passingStationName") ?: "" | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| val parsedColor = try { | ||
| Color.parseColor(lineColor) | ||
| } catch (_: Exception) { | ||
| Color.BLACK | ||
| } | ||
|
|
||
| val progressInt = (progress * MAX_PROGRESS).toInt().coerceIn(0, MAX_PROGRESS) | ||
|
|
||
| val contentTitle = when { | ||
| passingStationName.isNotEmpty() -> "$passingStationName 通過中" | ||
| stopped -> stationName | ||
| approaching -> "まもなく $nextStationName" | ||
| else -> "$stationName → $nextStationName" | ||
| } | ||
|
|
||
| val contentText = if (boundStationName.isNotEmpty()) { | ||
| "${boundStationName}方面" | ||
| } else { | ||
| "" | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| val subText = buildString { | ||
| if (trainTypeName.isNotEmpty()) { | ||
| append(trainTypeName) | ||
| append(" ") | ||
| } | ||
| append(lineName) | ||
| } | ||
|
|
||
| val trackerIcon = Icon.createWithResource( | ||
| reactApplicationContext, | ||
| R.drawable.ic_notification_live_update | ||
| ) | ||
|
|
||
| val progressStyle = Notification.ProgressStyle() | ||
| .setStyledByProgress(true) | ||
| .setProgress(progressInt) | ||
| .setProgressTrackerIcon(trackerIcon) | ||
| .setProgressSegments( | ||
| listOf( | ||
| Notification.ProgressStyle.Segment(MAX_PROGRESS).setColor(parsedColor) | ||
| ) | ||
| ) | ||
| .setProgressPoints( | ||
| listOf( | ||
| Notification.ProgressStyle.Point(0).setColor(parsedColor), | ||
| Notification.ProgressStyle.Point(MAX_PROGRESS).setColor(parsedColor) | ||
| ) | ||
| ) | ||
|
|
||
| val notification = Notification.Builder(reactApplicationContext, CHANNEL_ID) | ||
| .setSmallIcon(R.drawable.ic_notification_live_update) | ||
| .setContentTitle(contentTitle) | ||
| .setContentText(contentText) | ||
| .setSubText(subText) | ||
| .setStyle(progressStyle) | ||
| .setContentIntent(createContentIntent()) | ||
| .setOngoing(true) | ||
| .setOnlyAlertOnce(true) | ||
| .build() | ||
|
|
||
| getNotificationManager().notify(NOTIFICATION_ID, notification) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
android/app/src/main/res/drawable/ic_notification_live_update.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="24dp" | ||
| android:height="24dp" | ||
| android:viewportWidth="24" | ||
| android:viewportHeight="24"> | ||
| <path | ||
| android:fillColor="#FFFFFF" | ||
| android:pathData="M12,2c-4,0 -8,0.5 -8,4v9.5C4,17.43 5.57,19 7.5,19L6,20.5v0.5h2l2,-2h4l2,2h2v-0.5L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5V6c0,-3.5 -3.58,-4 -8,-4zM7.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,14 7.5,14s1.5,0.67 1.5,1.5S8.33,17 7.5,17zM11,10L6,10V6h5v4zM13,10v-4h5v4h-5zM16.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/> | ||
| </vector> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { NativeModules } from 'react-native'; | ||
| import { IS_LIVE_UPDATE_ELIGIBLE_PLATFORM } from '../../../constants'; | ||
|
|
||
| const { LiveUpdateModule } = NativeModules; | ||
|
|
||
| type LiveUpdateState = { | ||
| stationName: string; | ||
| nextStationName: string; | ||
| stationNumber: string; | ||
| nextStationNumber: string; | ||
| approaching: boolean; | ||
| stopped: boolean; | ||
| lineName: string; | ||
| lineColor: string; | ||
| passingStationName: string; | ||
| passingStationNumber: string; | ||
| progress: number; | ||
| boundStationName: string; | ||
| trainTypeName: string; | ||
| }; | ||
|
|
||
| export const startLiveUpdate = (state?: LiveUpdateState) => { | ||
| if (IS_LIVE_UPDATE_ELIGIBLE_PLATFORM) { | ||
| LiveUpdateModule?.startLiveUpdate?.(state); | ||
| } | ||
| }; | ||
|
|
||
| export const updateLiveUpdate = (state: LiveUpdateState) => { | ||
| if (IS_LIVE_UPDATE_ELIGIBLE_PLATFORM) { | ||
| LiveUpdateModule?.updateLiveUpdate?.(state); | ||
| } | ||
| }; | ||
|
|
||
| export const stopLiveUpdate = () => { | ||
| if (IS_LIVE_UPDATE_ELIGIBLE_PLATFORM) { | ||
| LiveUpdateModule?.stopLiveUpdate?.(); | ||
| } | ||
| }; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.