Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Tips and tricks du rebranding de l'app Captain ...
Search
Jeremie Martinez
December 12, 2016
Technology
1
340
Tips and tricks du rebranding de l'app Captain Train
Talk fait au PAUG le 12/12/16 en Français
Jeremie Martinez
December 12, 2016
Tweet
Share
More Decks by Jeremie Martinez
See All by Jeremie Martinez
Gradle, je t'aime, moi non plus…
jeremiemartinez
0
330
The evolution of Android notification
jeremiemartinez
5
4.9k
DevOps sur Android : from one git push to a Play Store release
jeremiemartinez
17
2.6k
See the Truth
jeremiemartinez
0
290
DevOps sur Android : D'un git push à une release Play Store
jeremiemartinez
5
570
Dagger 2 : Back to basics
jeremiemartinez
2
1k
La stack réseau Android, disponible également pour vos backs
jeremiemartinez
0
500
Other Decks in Technology
See All in Technology
フロントエンドも盛り上げたい!フロントエンドCBとAmplifyの軌跡
mkdev10
2
280
ElixirがHW化され、最新CPU/GPU/NWを過去のものとする数万倍、高速+超省電力化されたWeb/動画配信/AIが動く日
piacerex
0
150
AWSLambdaMCPServerを使ってツールとMCPサーバを分離する
tkikuchi
1
3k
生成AIによるCloud Native基盤構築の可能性と実践的ガードレールの敷設について
nwiizo
7
940
ガバクラのAWS長期継続割引 ~次の4/1に慌てないために~
hamijay_cloud
1
240
DETR手法の変遷と最新動向(CVPR2025)
tenten0727
2
1.4k
日経電子版 for Android の技術的課題と取り組み(令和最新版)/android-20250423
nikkei_engineer_recruiting
0
400
SREからゼロイチプロダクト開発へ ー越境する打席の立ち方と期待への応え方ー / Product Engineering Night #8
itkq
2
920
SmartHR プロダクトエンジニア求人ガイド_2025 / PdE job guide 2025
smarthr
0
130
Cross Data Platforms Meetup LT 20250422
tarotaro0129
1
690
Notion x ポストモーテムで広げる組織の学び / Notion x Postmortem
isaoshimizu
1
110
はじめてのSDET / My first challenge as a SDET
bun913
1
260
Featured
See All Featured
Done Done
chrislema
183
16k
Fireside Chat
paigeccino
37
3.4k
YesSQL, Process and Tooling at Scale
rocio
172
14k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.2k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
9
760
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.8k
Documentation Writing (for coders)
carmenintech
69
4.7k
Building Adaptive Systems
keathley
41
2.5k
GraphQLの誤解/rethinking-graphql
sonatard
71
10k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.3k
Being A Developer After 40
akosma
91
590k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
Transcript
@JeremMartinez From Captain Train… … to Trainline
None
Qu’est ce qu’une marque ?
Une icône 1
None
Des couleurs 2
Bonnes pratiques colors.xml Nommer vos couleurs selon le métier Garder
votre palette la plus petite possible Toujours faire des alias
<!-- Official colors --> <color name="accent">#01c3a7</color> <color name="primary">#21314d</color> <color name="primaryDark">#1a273d</color>
<!-- Text variants --> <color name="ct_text_primary">#323e42</color> <color name="ct_text_secondary">#8c9da1</color> <color name="ct_text_accent">#14b69f</color> <!-- Status colors --> <color name="ct_error">#e02007</color> <color name="ct_info">#0375b6</color> <color name="ct_success">#90c25b</color> <color name="ct_warning">#e87619</color>
<!-- Official colors --> <color name="accent">#01c3a7</color> <color name="primary">#21314d</color> <color name="primaryDark">#1a273d</color>
<!-- Text variants --> <color name="ct_text_primary">#323e42</color> <color name="ct_text_secondary">#8c9da1</color> <color name="ct_text_accent">#14b69f</color> <!-- Status colors --> <color name="ct_error">#e02007</color> <color name="ct_info">#0375b6</color> <color name="ct_success">#90c25b</color> <color name="ct_warning">#e87619</color>
<!-- Official colors --> <color name="accent">#01c3a7</color> <color name="primary">#21314d</color> <color name="primaryDark">#1a273d</color>
<!-- Text variants --> <color name="ct_text_primary">#323e42</color> <color name="ct_text_secondary">#8c9da1</color> <color name="ct_text_accent">#14b69f</color> <!-- Status colors --> <color name="ct_error">#e02007</color> <color name="ct_info">#0375b6</color> <color name="ct_success">#90c25b</color> <color name="ct_warning">#e87619</color>
Bonnes pratiques themes.xml Utiliser au maximum les thèmes Séparer vos
fichiers de thèmes : themes.xml styles.xml text_styles.xml
Theme
Theme Theme.CaptainTrain Theme.CaptainTrain.Exchange Theme.CaptainTrain.Cancellation
<style name="Theme.CaptainTrain" parent="Base.Theme.CaptainTrain"> <item name="colorAccent">@color/accent</item> </style> <style name="Theme.CaptainTrain.Cancellation">
<item name="colorAccent">@color/cancellation</item> </style> <style name="Theme.CaptainTrain.Exchange"> <item name="colorAccent">@color/exchange</item> </style>
None
None
<style name="Base.Theme.CaptainTrain"> <item name="colorControlNormal">?attr/colorAccent</item> </style> <style name="Theme.CaptainTrain"> <item name="colorAccent">@color/accent</item> </style>
<style name="Theme.CaptainTrain.Exchange"> <item name="colorAccent">@color/exchange</item> </style>
<style name="Base.Theme.CaptainTrain"> <item name="colorControlNormal">?attr/colorAccent</item> </style> <style name="Theme.CaptainTrain"> <item name="colorAccent">@color/accent</item> </style>
<style name="Theme.CaptainTrain.Exchange"> <item name="colorAccent">@color/exchange</item> </style>
attrs.xml <resources> <attr name="ctColorTextAccent" format="reference|color" /> </resources>
<style name="Theme.CaptainTrain" parent="Base.Theme.CaptainTrain"> <item name="colorAccent">@color/accent</item> <item name="ctColorTextAccent">@color/text_accent</item> </style> <style
name="Theme.CaptainTrain.Cancellation"> <item name="colorAccent">@color/cancellation</item> <item name="ctColorTextAccent">@color/text_cancellation</item> </style> <style name="Theme.CaptainTrain.Exchange"> <item name="colorAccent">@color/exchange</item> <item name="ctColorTextAccent">@color/text_exchange</item> </style> themes.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/disabled" android:state_enabled="false" />
<item android:color="?attr/ctColorTextAccent" /> </selector> text_accent.xml
attrs.xml <resources> <attr name="ctButtonStyle" format="reference" /> </resources>
<style name="Theme.CaptainTrain" parent="Base.Theme.CaptainTrain"> <item name="colorAccent">@color/accent</item> <item name="ctColorTextAccent">@color/text_accent</item> <item name="ctButtonStyle">@style/Button.Action</item> </style>
<style name="Theme.CaptainTrain.Cancellation"> <item name="colorAccent">@color/cancellation</item> <item name="ctColorTextAccent">@color/text_cancellation</item> <item name="ctButtonStyle">@style/Button.Action.Cancellation</item> </style> <style name="Theme.CaptainTrain.Exchange"> <item name="colorAccent">@color/exchange</item> <item name="ctColorTextAccent">@color/text_exchange</item> <item name="ctButtonStyle">@style/Button.Action.Exchange</item> </style>
<Button android:id="@+id/btn_pay" style="?attr/ctButtonStyle" android:layout_width="match_parent" android:layout_height="wrap_content" tools:text="Pay €456.00"/>
Attrs ne fonctionnent pas dans les drawables *Valable pré-Lollipop
Puissant mais pas magique Compile-time vs runtime Rapidement bordélique API
très verrouillée
Des drawables 3
Garder vos raws !
None
Un nom 4
Des empty-states 5
None
None
Des animations 6
None
None
http://jeremie-martinez.com/2016/09/15/train-animations/
Des liens 7
Interne www.captaintrain.com
Interne www.trainline.eu
Interne www.trainline.fr
Interne www.trainline.de
Interne www.trainline.it
Interne www.trainline.es
Integration Deeplinks SmartLock For Password Facebook Sign in Sharing Google
Sign in App Indexing
Un package name 8
No!
None
Une timeline 9
2 semaines avant …
Sur le web
Dans les emails
Le jour J …
None
AndroidManifest.xml <receiver android:enabled="true" android:exported="true" android:name="com.example.ApplicationUpdatedReceiver"> <intent-filter> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> </intent-filter>
</receiver>
AndroidManifest.xml <receiver android:enabled="true" android:exported="true" android:name="com.example.ApplicationUpdatedReceiver"> <intent-filter> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> </intent-filter>
</receiver>
AndroidManifest.xml <receiver android:enabled="true" android:exported="true" android:name="com.example.ApplicationUpdatedReceiver"> <intent-filter> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> </intent-filter>
</receiver>
AndroidManifest.xml <receiver android:enabled="true" android:exported="true" android:name="com.example.ApplicationUpdatedReceiver"> <intent-filter> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> </intent-filter>
</receiver>
AndroidManifest.xml <receiver android:enabled="true" android:exported="true" android:name="com.example.ApplicationUpdatedReceiver"> <intent-filter> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> </intent-filter>
</receiver>
ApplicationUpdatedReceiver public class ApplicationUpdatedReceiver extends BroadcastReceiver { …
} } @Override public void onReceive(Context context, Intent intent) {
ApplicationUpdatedReceiver String action = intent.getAction(); if (TextUtils.isEmpty(action)) { return; }
switch (action) { … break; } } @Override public void onReceive(Context context, Intent intent) { case Intent.ACTION_MY_PACKAGE_REPLACED:
ApplicationUpdatedReceiver case Intent.ACTION_MY_PACKAGE_REPLACED: AppPreferences preferences = AppPreferences.from(context); int version =
preferences. getInt(PREVIOUS_APP_VERSION, VERSION_CODES.NARIM); if (version < VERSION_CODES.ONEILL) { bumpToOneill(context); version = VERSION_CODES.ONEILL; } if (version < VERSION_CODES.PENDERGAST) { bumpToPendergast(context); version = VERSION_CODES.PENDERGAST; } preferences.edit(). putInt(PREVIOUS_APP_VERSION, version). apply();
ApplicationUpdatedReceiver case Intent.ACTION_MY_PACKAGE_REPLACED: AppPreferences preferences = AppPreferences.from(context); int version =
preferences. getInt(PREVIOUS_APP_VERSION, VERSION_CODES.NARIM); if (version < VERSION_CODES.ONEILL) { bumpToOneill(context); version = VERSION_CODES.ONEILL; } if (version < VERSION_CODES.PENDERGAST) { bumpToPendergast(context); version = VERSION_CODES.PENDERGAST; } preferences.edit(). putInt(PREVIOUS_APP_VERSION, version). apply();
ApplicationUpdatedReceiver case Intent.ACTION_MY_PACKAGE_REPLACED: AppPreferences preferences = AppPreferences.from(context); int version =
preferences. getInt(PREVIOUS_APP_VERSION, VERSION_CODES.NARIM); if (version < VERSION_CODES.ONEILL) { bumpToOneill(context); version = VERSION_CODES.ONEILL; } if (version < VERSION_CODES.PENDERGAST) { bumpToPendergast(context); version = VERSION_CODES.PENDERGAST; } preferences.edit(). putInt(PREVIOUS_APP_VERSION, version). apply();
ApplicationUpdatedReceiver case Intent.ACTION_MY_PACKAGE_REPLACED: AppPreferences preferences = AppPreferences.from(context); int version =
preferences. getInt(PREVIOUS_APP_VERSION, VERSION_CODES.NARIM); if (version < VERSION_CODES.ONEILL) { bumpToOneill(context); version = VERSION_CODES.ONEILL; } if (version < VERSION_CODES.PENDERGAST) { bumpToPendergast(context); version = VERSION_CODES.PENDERGAST; } preferences.edit(). putInt(PREVIOUS_APP_VERSION, version). apply();
ApplicationUpdatedReceiver bumpToOneill(context); Notification Sauver un état pour l’écran …
Subir la rage 10
None
None
Conclusion Ça prend du temps Faire le minimum de changements
possible Vous allez oublier des choses Il y aura forcément des déçus
@JeremMartinez Questions ?