Skip to content

Commit 37f0bc1

Browse files
committed
add full timeline item and icons
1 parent e266c2e commit 37f0bc1

File tree

6 files changed

+381
-10
lines changed

6 files changed

+381
-10
lines changed

src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/Timeline.kt

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,6 @@ class TimelineItem(
122122
}
123123

124124
class Attribute() : StructMappable() {
125-
enum class Timeline(val id: UByte) {
126-
Sender(0x01u),
127-
Subject(0x02u),
128-
Message(0x03u),
129-
Icon(0x04u),
130-
BackgroundCol(0x1Cu)
131-
}
132-
133125
val attributeId = SUByte(m)
134126
val length = SUShort(m, endianness = '<')
135127
val content = SBytes(m, 0)
@@ -236,6 +228,43 @@ open class TimelineAction(message: Message) : PebblePacket(endpoint) {
236228
}
237229
}
238230

231+
enum class TimelineAttribute(val id: UByte, val maxLength: Int = -1) {
232+
Title(0x01u, 64),
233+
Subtitle(0x02u, 64),
234+
Body(0x03u, 512),
235+
TinyIcon(0x04u),
236+
SmallIcon(0x05u),
237+
LargeIcon(0x06u),
238+
ANCSAction(0x07u),
239+
CannedResponse(0x08u, 512),
240+
ShortTitle(0x09u, 64),
241+
LocationName(0x0Bu, 64),
242+
Sender(0x0Cu, 64),
243+
LaunchCode(0x0Du),
244+
LastUpdated(0x0Eu),
245+
RankAway(0x0Fu),
246+
RankHome(0x10u),
247+
NameAway(0x11u),
248+
NameHome(0x12u),
249+
RecordAway(0x13u),
250+
RecordHome(0x14u),
251+
ScoreAway(0x15u),
252+
ScoreHome(0x16u),
253+
SportsGameState(0x17u),
254+
Broadcaster(0x18u),
255+
Headings(0x19u, 128),
256+
Paragraphs(0x1Au, 1024),
257+
ForegroundColor(0x1Bu),
258+
PrimaryColor(0x1Cu),
259+
SecondaryColor(0x1Du),
260+
DisplayRecurring(0x1Fu),
261+
ShortSubtitle(0x24u),
262+
Timestamp(0x25u),
263+
DisplayTime(0x26u),
264+
SubtitleTemplateString(0x2Fu, 150),
265+
Icon(0x30u),
266+
}
267+
239268
fun timelinePacketsRegister() {
240269
PacketRegistry.register(
241270
TimelineAction.endpoint,
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.rebble.libpebblecommon.packets.blobdb
2+
3+
enum class TimelineIcon(val id: UInt) {
4+
NotificationReminder(3u),
5+
HockeyGame(30u),
6+
PayBill(38u),
7+
NotificationLinkedIn(115u),
8+
NotificationGoogleInbox(61u),
9+
GenericQuestion(63u),
10+
NotificationFlag(4u),
11+
GenericSms(45u),
12+
WatchDisconnected(48u),
13+
TvShow(73u),
14+
Basketball(74u),
15+
GenericWarning(28u),
16+
LightRain(32u),
17+
NotificationFacebook(11u),
18+
IncomingPhoneCall(78u),
19+
NotificationGoogleMessenger(76u),
20+
NotificationTelegram(7u),
21+
NotificationFacetime(110u),
22+
ArrowDown(99u),
23+
NotificationOutlook(64u),
24+
NoEvents(57u),
25+
AudioCassette(12u),
26+
Sunset(85u),
27+
NotificationTwitter(6u),
28+
Sunrise(84u),
29+
HeavyRain(52u),
30+
NotificationMailbox(60u),
31+
AmericanFootball(20u),
32+
CarRental(24u),
33+
CricketGame(26u),
34+
NotificationWeChat(71u),
35+
NotificationGeneric(1u),
36+
NotificationSkype(68u),
37+
CloudyDay(25u),
38+
DuringPhoneCallCentered(95u),
39+
NotificationLine(67u),
40+
HotelReservation(31u),
41+
NotificationFacebookMessenger(10u),
42+
NotificationLighthouse(81u),
43+
TimelineEmptyCalendar(96u),
44+
NotificationIosPhotos(114u),
45+
ResultDeleted(43u),
46+
NotificationGmail(9u),
47+
TimelineMissedCall(2u),
48+
Sleep(101u),
49+
ResultMute(46u),
50+
NotificationAmazon(111u),
51+
ThumbsUp(97u),
52+
ScheduledFlight(54u),
53+
Settings(83u),
54+
PartlyCloudy(37u),
55+
StocksEvent(42u),
56+
NotificationGoogleMaps(112u),
57+
RewardGood(103u),
58+
NotificationYahooMail(72u),
59+
BirthdayEvent(23u),
60+
GenericEmail(19u),
61+
ResultDismissed(51u),
62+
NotificationGooglePhotos(113u),
63+
TideIsHigh(50u),
64+
NotificationViber(70u),
65+
LightSnow(33u),
66+
NewsEvent(36u),
67+
GenericConfirmation(55u),
68+
TimelineSports(17u),
69+
NotificationSlack(116u),
70+
CheckInternetConnection(44u),
71+
Activity(100u),
72+
NotificationHipChat(77u),
73+
NotificationInstagram(59u),
74+
TimelineBaseball(22u),
75+
RewardBad(102u),
76+
ReachedFitnessGoal(66u),
77+
DaySeparator(56u),
78+
TimelineCalendar(21u),
79+
RainingAndSnowing(65u),
80+
RadioShow(39u),
81+
DismissedPhoneCall(75u),
82+
ArrowUp(98u),
83+
RewardAverage(104u),
84+
MusicEvent(35u),
85+
NotificationSnapchat(69u),
86+
NotificationBlackberryMessenger(58u),
87+
NotificationWhatsapp(5u),
88+
Location(82u),
89+
SoccerGame(41u),
90+
ResultFailed(62u),
91+
ResultUnmute(86u),
92+
ScheduledEvent(40u),
93+
TimelineWeather(14u),
94+
TimelineSun(16u),
95+
NotificationGoogleHangouts(8u),
96+
DuringPhoneCall(49u),
97+
NotificationKik(80u),
98+
ResultUnmuteAlt(94u),
99+
MovieEvent(34u),
100+
GlucoseMonitor(29u),
101+
ResultSent(47u),
102+
AlarmClock(13u),
103+
HeavySnow(53u),
104+
DinnerReservation(27u),
105+
NotificationKakaoTalk(79u);
106+
107+
companion object {
108+
fun fromId(id: UInt): TimelineIcon {
109+
return entries.firstOrNull { it.id == id }
110+
?: error("Unknown timeline icon id: $id")
111+
}
112+
}
113+
}

src/commonMain/kotlin/io/rebble/libpebblecommon/protocolhelpers/ProtocolEndpoint.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ enum class ProtocolEndpoint(val value: UShort) {
3838
INVALID_ENDPOINT(0xffffu);
3939

4040
companion object {
41-
private val values = values()
41+
private val values = entries.toTypedArray()
4242
fun getByValue(value: UShort) = values.firstOrNull { it.value == value }
4343
?: INVALID_ENDPOINT.also {
4444
Logger.e {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.rebble.libpebblecommon.util
2+
3+
data class PebbleColor(
4+
val alpha: UByte,
5+
val red: UByte,
6+
val green: UByte,
7+
val blue: UByte
8+
)
9+
10+
fun PebbleColor.toProtocolNumber() =
11+
((alpha / 85u) shl 6) or
12+
((red / 85u) shl 4) or
13+
((green / 85u) shl 2) or
14+
(blue / 85u)
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package io.rebble.libpebblecommon.util
2+
3+
import io.rebble.libpebblecommon.packets.blobdb.TimelineAttribute
4+
import io.rebble.libpebblecommon.packets.blobdb.TimelineIcon
5+
import io.rebble.libpebblecommon.packets.blobdb.TimelineItem
6+
import io.rebble.libpebblecommon.structmapper.SFixedList
7+
import io.rebble.libpebblecommon.structmapper.SUInt
8+
import io.rebble.libpebblecommon.structmapper.StructMapper
9+
import kotlin.math.round
10+
11+
object TimelineAttributeFactory {
12+
private fun createAttribute(attributeId: UByte, content: UByteArray, contentEndianness: Char = '|'): TimelineItem.Attribute {
13+
return TimelineItem.Attribute(attributeId, content, contentEndianness)
14+
}
15+
16+
private fun createTextAttribute(type: TimelineAttribute, text: String): TimelineItem.Attribute {
17+
require(type.maxLength != -1) { "Attribute type $type is not a text attribute" }
18+
return createAttribute(type.id, text.encodeToByteArrayTrimmed(type.maxLength).toUByteArray())
19+
}
20+
21+
private fun createStringListAttribute(type: TimelineAttribute, list: List<String>): TimelineItem.Attribute {
22+
val content = list.joinToString("\u0000")
23+
.encodeToByteArrayTrimmed(type.maxLength).toUByteArray()
24+
return createAttribute(type.id, content)
25+
}
26+
27+
private fun createUByteAttribute(type: TimelineAttribute, value: UByte): TimelineItem.Attribute {
28+
val content = byteArrayOf(value.toByte()).toUByteArray()
29+
return createAttribute(type.id, content)
30+
}
31+
32+
private fun createUIntAttribute(type: TimelineAttribute, value: UInt): TimelineItem.Attribute {
33+
val content = SUInt(StructMapper(), value, '<').toBytes()
34+
return createAttribute(type.id, content)
35+
}
36+
37+
fun title(text: String, ellipsis: Boolean = true): TimelineItem.Attribute {
38+
return createTextAttribute(TimelineAttribute.Title, text)
39+
}
40+
41+
fun subtitle(text: String, ellipsis: Boolean = true): TimelineItem.Attribute {
42+
return createTextAttribute(TimelineAttribute.Subtitle, text)
43+
}
44+
45+
fun body(text: String, ellipsis: Boolean = true): TimelineItem.Attribute {
46+
return createTextAttribute(TimelineAttribute.Body, text)
47+
}
48+
49+
fun tinyIcon(icon: TimelineIcon, offsetId: Boolean = true): TimelineItem.Attribute {
50+
val id = if (offsetId) {
51+
icon.id or 0x80000000u
52+
} else {
53+
icon.id
54+
}
55+
return createUIntAttribute(TimelineAttribute.TinyIcon, id)
56+
}
57+
58+
fun smallIcon(icon: TimelineIcon, offsetId: Boolean = true): TimelineItem.Attribute {
59+
val id = if (offsetId) {
60+
icon.id or 0x80000000u
61+
} else {
62+
icon.id
63+
}
64+
return createUIntAttribute(TimelineAttribute.SmallIcon, id)
65+
}
66+
67+
fun largeIcon(icon: TimelineIcon, offsetId: Boolean = true): TimelineItem.Attribute {
68+
val id = if (offsetId) {
69+
icon.id or 0x80000000u
70+
} else {
71+
icon.id
72+
}
73+
return createUIntAttribute(TimelineAttribute.LargeIcon, id)
74+
}
75+
76+
fun ancsAction(action: UInt): TimelineItem.Attribute {
77+
return createUIntAttribute(TimelineAttribute.ANCSAction, action)
78+
}
79+
80+
fun cannedResponse(responses: List<String>): TimelineItem.Attribute {
81+
return createStringListAttribute(TimelineAttribute.CannedResponse, responses)
82+
}
83+
84+
fun shortTitle(text: String): TimelineItem.Attribute {
85+
return createTextAttribute(TimelineAttribute.ShortTitle, text)
86+
}
87+
88+
fun locationName(text: String): TimelineItem.Attribute {
89+
return createTextAttribute(TimelineAttribute.LocationName, text)
90+
}
91+
92+
fun sender(text: String): TimelineItem.Attribute {
93+
return createTextAttribute(TimelineAttribute.Sender, text)
94+
}
95+
96+
fun launchCode(code: UInt): TimelineItem.Attribute {
97+
return createUIntAttribute(TimelineAttribute.LaunchCode, code)
98+
}
99+
100+
fun lastUpdated(msSinceEpoch: Int): TimelineItem.Attribute {
101+
return createUIntAttribute(TimelineAttribute.LastUpdated, round(msSinceEpoch / 1000f).toUInt())
102+
}
103+
104+
fun rankAway(rank: String): TimelineItem.Attribute {
105+
return createTextAttribute(TimelineAttribute.RankAway, rank)
106+
}
107+
108+
fun rankHome(rank: String): TimelineItem.Attribute {
109+
return createTextAttribute(TimelineAttribute.RankHome, rank)
110+
}
111+
112+
fun nameAway(name: String): TimelineItem.Attribute {
113+
return createTextAttribute(TimelineAttribute.NameAway, name)
114+
}
115+
116+
fun nameHome(name: String): TimelineItem.Attribute {
117+
return createTextAttribute(TimelineAttribute.NameHome, name)
118+
}
119+
120+
fun recordAway(record: String): TimelineItem.Attribute {
121+
return createTextAttribute(TimelineAttribute.RecordAway, record)
122+
}
123+
124+
fun recordHome(record: String): TimelineItem.Attribute {
125+
return createTextAttribute(TimelineAttribute.RecordHome, record)
126+
}
127+
128+
fun scoreAway(score: String): TimelineItem.Attribute {
129+
return createTextAttribute(TimelineAttribute.ScoreAway, score)
130+
}
131+
132+
fun scoreHome(score: String): TimelineItem.Attribute {
133+
return createTextAttribute(TimelineAttribute.ScoreHome, score)
134+
}
135+
136+
fun sportsGameState(state: UByte): TimelineItem.Attribute {
137+
return createUByteAttribute(TimelineAttribute.SportsGameState, state)
138+
}
139+
140+
fun broadcaster(text: String): TimelineItem.Attribute {
141+
return createTextAttribute(TimelineAttribute.Broadcaster, text)
142+
}
143+
144+
fun headings(headings: List<String>): TimelineItem.Attribute {
145+
return createStringListAttribute(TimelineAttribute.Headings, headings)
146+
}
147+
148+
fun paragraphs(paragraphs: List<String>): TimelineItem.Attribute {
149+
return createStringListAttribute(TimelineAttribute.Body, paragraphs)
150+
}
151+
152+
fun foregroundColor(color: PebbleColor): TimelineItem.Attribute {
153+
return createUIntAttribute(TimelineAttribute.ForegroundColor, color.toProtocolNumber())
154+
}
155+
156+
fun primaryColor(color: PebbleColor): TimelineItem.Attribute {
157+
return createUIntAttribute(TimelineAttribute.PrimaryColor, color.toProtocolNumber())
158+
}
159+
160+
fun secondaryColor(color: PebbleColor): TimelineItem.Attribute {
161+
return createUIntAttribute(TimelineAttribute.SecondaryColor, color.toProtocolNumber())
162+
}
163+
164+
fun displayRecurring(recurring: Boolean): TimelineItem.Attribute {
165+
return createUByteAttribute(TimelineAttribute.DisplayRecurring, if (recurring) 1u else 0u)
166+
}
167+
168+
fun shortSubtitle(text: String): TimelineItem.Attribute {
169+
return createTextAttribute(TimelineAttribute.ShortSubtitle, text)
170+
}
171+
172+
fun timestamp(timestamp: UInt): TimelineItem.Attribute {
173+
return createUIntAttribute(TimelineAttribute.LastUpdated, timestamp / 1000u)
174+
}
175+
176+
fun displayTime(displayTime: Boolean): TimelineItem.Attribute {
177+
return createUByteAttribute(TimelineAttribute.DisplayRecurring, if (displayTime) 1u else 0u)
178+
}
179+
180+
fun subtitleTemplateString(text: String): TimelineItem.Attribute {
181+
return createTextAttribute(TimelineAttribute.SubtitleTemplateString, text)
182+
}
183+
184+
fun icon(icon: TimelineIcon): TimelineItem.Attribute {
185+
return createUIntAttribute(TimelineAttribute.Icon, icon.id)
186+
}
187+
}

0 commit comments

Comments
 (0)