@@ -191,6 +191,66 @@ async function atomicRenderPng(path, svg) {
191191 }
192192}
193193
194+ async function renderAndroidForeground ( sourceRoot ) {
195+ const source = resolve ( sourceRoot , 'compact-transparent.png' )
196+ const metadata = await sharp ( source ) . metadata ( )
197+ invariant (
198+ metadata . format === 'png' && metadata . width === 512 && metadata . height === 512 ,
199+ 'canonical Android launcher source must be a 512 by 512 PNG' ,
200+ )
201+ invariant ( metadata . hasAlpha === true , 'canonical Android launcher source must retain alpha' )
202+
203+ return sharp ( source )
204+ . resize ( 264 , 264 , { fit : 'contain' } )
205+ . extend ( {
206+ top : 84 ,
207+ bottom : 84 ,
208+ left : 84 ,
209+ right : 84 ,
210+ background : { r : 0 , g : 0 , b : 0 , alpha : 0 } ,
211+ } )
212+ . png ( { compressionLevel : 9 , palette : false } )
213+ . toBuffer ( )
214+ }
215+
216+ function renderAdaptiveIcon ( { monochrome } ) {
217+ return `<?xml version="1.0" encoding="utf-8"?>
218+ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
219+ <background android:drawable="@color/launcher_icon_background" />
220+ <foreground android:drawable="@drawable/ic_kurdistan_vpn_foreground" />${
221+ monochrome
222+ ? '\n <monochrome android:drawable="@drawable/ic_kurdistan_vpn_foreground" />'
223+ : ''
224+ }
225+ </adaptive-icon>
226+ `
227+ }
228+
229+ async function syncAndroid ( sourceRoot ) {
230+ validateSource ( sourceRoot )
231+
232+ const resourceRoot = resolve ( repositoryRoot , 'android/app/src/main/res' )
233+ atomicWrite (
234+ resolve ( resourceRoot , 'drawable-nodpi/ic_kurdistan_vpn_foreground.png' ) ,
235+ await renderAndroidForeground ( sourceRoot ) ,
236+ )
237+ atomicWrite (
238+ resolve ( resourceRoot , 'values/launcher_icon_colors.xml' ) ,
239+ `<?xml version="1.0" encoding="utf-8"?>
240+ <resources>
241+ <color name="launcher_icon_background">#F8FAFC</color>
242+ </resources>
243+ ` ,
244+ )
245+
246+ for ( const version of [ 26 , 33 ] ) {
247+ const xml = renderAdaptiveIcon ( { monochrome : version >= 33 } )
248+ for ( const name of [ 'ic_kurdistan_vpn.xml' , 'ic_kurdistan_vpn_round.xml' ] ) {
249+ atomicWrite ( resolve ( resourceRoot , `mipmap-anydpi-v${ version } /${ name } ` ) , xml )
250+ }
251+ }
252+ }
253+
194254function renderSocialSvg ( ) {
195255 return `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630">
196256 <defs>
@@ -267,7 +327,7 @@ function parseArguments(argv) {
267327 for ( let index = 0 ; index < argv . length ; index += 1 ) {
268328 const argument = argv [ index ]
269329
270- if ( argument === '--check' || argument === '--website' ) {
330+ if ( argument === '--check' || argument === '--website' || argument === '--android' ) {
271331 invariant ( ! mode , 'exactly one brand operation is required' )
272332 mode = argument . slice ( 2 )
273333 continue
@@ -283,7 +343,10 @@ function parseArguments(argv) {
283343 throw new Error ( `unknown argument: ${ argument } ` )
284344 }
285345
286- invariant ( mode === 'check' || mode === 'website' , 'use --check or --website' )
346+ invariant (
347+ mode === 'check' || mode === 'website' || mode === 'android' ,
348+ 'use --check, --website, or --android' ,
349+ )
287350 return { mode, sourceRoot }
288351}
289352
@@ -296,8 +359,14 @@ async function main() {
296359 return
297360 }
298361
299- await syncWebsite ( sourceRoot )
300- console . log ( 'BRAND_WEBSITE=SYNCED' )
362+ if ( mode === 'website' ) {
363+ await syncWebsite ( sourceRoot )
364+ console . log ( 'BRAND_WEBSITE=SYNCED' )
365+ return
366+ }
367+
368+ await syncAndroid ( sourceRoot )
369+ console . log ( 'BRAND_ANDROID=SYNCED' )
301370}
302371
303372main ( ) . catch ( ( error ) => {
0 commit comments