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
Compose Multiplatform で Bluesky のクライアント作ってみた / ...
Search
Yuki Anzai
April 30, 2023
Technology
0
690
Compose Multiplatform で Bluesky のクライアント作ってみた / Bluesky client with Compose Multiplatform
Bluesky/ATProtocol 勉強会#1
https://428lab.connpass.com/event/280610/
Yuki Anzai
April 30, 2023
Tweet
Share
More Decks by Yuki Anzai
See All by Yuki Anzai
What’s new in Android development tools
yanzm
0
820
Google I/O 2025 Keynote & Developer Keynote Overview
yanzm
0
140
Coding Agent を使って Android アプリを作ってみる / Let's try using coding agent for Android app development
yanzm
0
160
MediaPipe と ML Kit ってどう ちがうの? / What is the difference between MediaPipe and ML Kit?
yanzm
0
1.2k
アプリをリリースできる状態に保ったまま 段階的にリファクタリングするための 戦略と戦術 / Strategies and tactics for incremental refactoring
yanzm
8
5.3k
Kotlinらしいコードを書こう - Convert Java File to Kotlin File のあとにやること / What to do after Convert Java File to Kotlin File
yanzm
1
5.7k
個人アプリ開発 (メンテナンス) 14年の歴史 / My personal app development history
yanzm
1
950
Material 3 やめました / Good-bye M3 design system
yanzm
4
8.8k
Compose Transition Animation
yanzm
3
800
Other Decks in Technology
See All in Technology
生成AI導入の効果を最大化する データ活用戦略
ham0215
0
110
Kiroでインフラ要件定義~テスト を実施してみた
nagisa53
3
300
Agent Development Kitで始める生成 AI エージェント実践開発
danishi
0
120
LLMでAI-OCR、実際どうなの? / llm_ai_ocr_layerx_bet_ai_day_lt
sbrf248
0
430
Findy Freelance 利用シーン別AI活用例
ness
0
290
LIFF CLIとngrokを使ったLIFF/LINEミニアプリのお手軽実機確認
diggymo
0
230
AI関数が早くなったので試してみよう
kumakura
0
120
猫でもわかるQ_CLI(CDK開発編)+ちょっとだけKiro
kentapapa
0
3.4k
製造業の課題解決に向けた機械学習の活用と、製造業特化LLM開発への挑戦
knt44kw
0
150
クマ×共生 HACKATHON - 熊対策を『特別な行動」から「生活の一部」に -
pharaohkj
0
290
Tableau API連携の罠!?脱スプシを夢見たはずが、逆に依存を深めた話
cuebic9bic
3
210
20250807_Kiroと私の反省会
riz3f7
0
130
Featured
See All Featured
Building Applications with DynamoDB
mza
95
6.5k
Scaling GitHub
holman
461
140k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Music & Morning Musume
bryan
46
6.7k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
Six Lessons from altMBA
skipperchong
28
3.9k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
30
2.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.4k
How GitHub (no longer) Works
holman
314
140k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Building a Modern Day E-commerce SEO Strategy
aleyda
43
7.4k
Why You Should Never Use an ORM
jnunemaker
PRO
58
9.5k
Transcript
$PNQPTF.VMUJQMBUGPSNͰ #MVFTLZͷΫϥΠΞϯτ࡞ͬͯΈͨ yanzm
ZBO[NʢΜ͟Ήʣ w !ZBO[NCTLZTPDJBM w ݹʢ͍ʹ͑͠ʣͷ"OESPJEFS w ݄ʹ,PKJSB͞ΜʹটίʔυΒͬͯCMVFTLZ͡Ί·ͨ͠ɻ৽ถͰ ͢ɻ
,PUMJO w ʢͱͱʣ+7.ݴޠ w CFUUFS+BWBతͳ w ͔Β"OESPJEͷެࣜαϙʔτݴޠͷҰͭ
,PUMJO.VMUJQMBUGPSN ,.1 w ,PUMJOͷίʔυΛXFC +T ͱ͔OBUJWF EFTLUPQ ͱ͔ͷόΠφϦʹϏϧυ w ಉ͡,PUMJOͷίʔυͰෳͷ1MBUGPSNʹରԠ
w J04ରԠ w ͨͩ͠ɺ6*ͦΕͧΕͷ1MBUGPSN/BUJWFͳ෦Ͱ࣮
+FUQBDL$PNQPTF w "OESPJEͷωΠςΟϒ6*Λߏங͢ΔͨΊͷ࠷৽ͷπʔϧΩοτ w એݴత6* Row { Icon( imageVector =
Icons.Default.Star, contentDescription = null ) Column { Text( text = "username" ) Text( text = "description" ) } Button( onClick = onClickFollow ) { Text("follow") } }
$PNQPTFGPS%FTLUPQ w ݄ w +FUQBDL$PNQPTFͰ,PUMJO.VMUJQMBUGPSNͷEFTLUPQͷ6*͕࡞ΕΔ
$PNQPTF.VUMJQMBUGPSN6*'SBNFXPSL w IUUQTXXXKFUCSBJOTDPNMQDPNQPTFNVMUJQMBUGPSN w ݄ͷ,PUMJO$POGͰൃද w EFTLUPQ͚ͩ͡Όͳ͘J04 "MQIB ,PUMJO/BUJWF 8FC
&YQFSJNFOUBM ,PUMJO8BTN αϙʔτ
#MVFTLZͷΫϥΠΞϯτΞϓϦΛ $PNQPTF.VMUJQMBUGPSNͰ࡞Δ https://github.com/yanzm/Rayleigh
4UFQϕʔεͷϓϩδΣΫτΛ࡞Δ w +FU#SBJOTͷHJUIVCʹDPNQPTFNVMUJQMBUGPSNͷςϯϓϨʔτ͕͋Δ w IUUQTHJUIVCDPN+FU#SBJOTDPNQPTFNVMUJQMBUGPSNJPTBOESPJE UFNQMBUF
4UFQ௨৴Ͱ͖ΔΑ͏ʹ͢Δ w 4FJVO͞Μ3FUSP fi UΛ͍͚ͬͯͨͲ,.1Ͱ͑ͳ͍ w ,UPS w IUUQTLUPSJP w
,PUMJO$POG`ͷηογϣϯͰग़͖ͯͨ$PNQPTF.VMUJQMBUGPSNͰνϟο τ͢ΔΞϓϦ͕ࢀߟʹͳͬͨ w IUUQTHJUIVCDPNTWUL,$$IBU"QQ w ,UPS ,PUMJOY4FSJBMJ[BUJPOͱ͔
4UFQϩάΠϯը໘ͷ6*Λ࡞Δ
4UFQϩάΠϯը໘ͷ6*Λ࡞Δ w SEQBSUZDMJFOU"QQ1BTTXPSEͰϩάΠϯ͢ΔΑ͏ʹͳ͔ͬͨΒɺΞΧ ϯτͷ࡞ϩάΠϯ"QQ1BTTXPSEͷ࡞ϒϥβΛ։͍ͯIUUQT TUBHJOHCTLZBQQΛද͍ࣔͨ͠ w "OESPJE J04ͦΕͧΕͷQMBUGPSNͷॲཧ͕ඞཁ
@Composable fun App( onOpenBrowser: (String) -> Unit = {} )
{ RayleighTheme { … LoginScreen( viewModel = viewModel, onOpenBrowser = onOpenBrowser, ) } } shared/commonMain
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContent { MainView( onOpenBrowser = { startActivity( Intent(Intent.ACTION_VIEW, Uri.parse(it)) ) } ) } } @Composable fun MainView( onOpenBrowser: (String) -> Unit ) { App( onOpenBrowser = onOpenBrowser ) } androidApp/ shared/androidMain Android
struct ComposeView: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController {
Main_iosKt.MainViewController( onOpenBrowser: { let url = URL(string:$0)! UIApplication.shared.open(url, options: [:], completionHandler: nil) } ) } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } fun MainViewController( onOpenBrowser: (String) -> Unit ) = ComposeUIViewController { App( onOpenBrowser = onOpenBrowser ) } iosApp/iosApp/ContentView.swift shared/iosMain iOS
4UFQϩάΠϯ͢Δ w "1*Λୟ͍ͯฦ͖ͬͯͨUPLFOΛอଘ͠ͳ͍ͱ͍͚ͳ͍ w NVMUJQMBUGPSNTFUUJOHTΛ͏͜ͱʹ͢Δ w IUUQTHJUIVCDPNSVTTIXPMGNVMUJQMBUGPSNTFUUJOHT w ϓϥοτϑΥʔϜ͝ͱʹ4FUUJOHTͷੜΠϯελϯε͕ҟͳΔ w
%*͕ͳ͍ͱͭΒ͍
4UFQ%FQFOEFODZ*OKFDUJPO w "OESPJEͰEBHHFSIJMU͕σϑΝΫτ͕ͩ,.1Ͱ͑ͳ͍ w ,PJO w LPJODPSF,.1ʹରԠ͍ͯ͠Δ͕ w LPJODPNQPTF$PNQPTF.VMUJQMBUGPSNʹ·ͩରԠ͍ͯ͠ͳ͍ w
l$PVMEOPU fi OEJPJOTFSULPJOLPJODPNQPTFJPTBSNzͱౖΒΕ Δ w IUUQTJOTFSULPJOJPEPDTSFGFSFODFLPJODPNQPTFNVMUJQMBUGPSN 8*1
class AppComponent : KoinComponent { val authRepository: AuthRepository by inject()
} shared/commonMain @Composable fun App( appComponent: AppComponent, onOpenBrowser: (String) -> Unit = {} ) { RayleighTheme { val appViewModel = remember { AppViewModel(appComponent.authRepository) } … } }
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContent { MainView( appComponent = AppComponent(), onOpenBrowser = { startActivity( Intent(Intent.ACTION_VIEW, Uri.parse(it)) ) @Composable fun MainView( appComponent: AppComponent, onOpenBrowser: (String) -> Unit ) { App( appComponent = appComponent, onOpenBrowser = onOpenBrowser ) } androidApp/ shared/androidMain Android
struct ComposeView: UIViewControllerRepresentable { let appComponent = AppComponent() func makeUIViewController(context:
Context) -> UIViewController { Main_iosKt.MainViewController( appComponent: appComponent, onOpenBrowser: { let url = URL(string:$0)! UIApplication.shared.open(url, options: [:], completionHandler: nil) } ) } fun MainViewController( appComponent: AppComponent, onOpenBrowser: (String) -> Unit ) = ComposeUIViewController { App( appComponent = appComponent, onOpenBrowser = onOpenBrowser ) } iosApp/iosApp/ContentView.swift shared/iosMain iOS
4UFQλΠϜϥΠϯΛऔಘ͢Δ w ϩάΠϯ࣌ʹऔಘͨ͠5PLFOΛCFBSFSBVUIFOUJDBUJPOʹηοτ͢Δ w ,UPSͷ"VUIQMVHJO͏͚ͩ w IUUQTLUPSJPEPDTCFBSFSDMJFOUIUNM w UZQFͰΦϒδΣΫτ͕มΘΔ3FDPSEͱ͔$MBTTEJTDSJNJOBUPSGPS QPMZNPSQIJTN͏
w IUUQTHJUIVCDPN,PUMJOLPUMJOYTFSJBMJ[BUJPOCMPCNBTUFSEPDT KTPONEDMBTTEJTDSJNJOBUPSGPSQPMZNPSQIJTN
None
·ͱΊࠓޙ w /BWJHBUJPOͲ͏ͨ͠Β͍͍ͷͩʜ w %FDPNQPTF IUUQTHJUIVCDPNBSLJWBOPW%FDPNQPTF w %*͕ͭΒ͍ʜ
w LPJODPNQPTF͕ରԠͨ͠ΒָʹͳΔ͔ʁ w 5FYU'JFMEͷڍಈ͕J044JNVMBUPSͰ͓͔͍͠ʜ w $PNQPTFͰී௨ʹJ04ͷ6*͕Ͱ͖͍ͯ͢͝ͷͰɺ͍Ζ͍ΖΓ͍ͨ