[update] New Icon& UI Theme

This commit is contained in:
acite
2025-09-14 19:59:28 +08:00
parent cc540903d3
commit f7701cc85b
30 changed files with 158 additions and 33 deletions

View File

@@ -26,7 +26,7 @@ _🚀This is the client of the multimedia server Abyss, which can also be extend
- [x] Hide private key after user input - [x] Hide private key after user input
- [x] Optimize API call logic, do not create crashes - [x] Optimize API call logic, do not create crashes
- [x] Fix the issue of freezing when entering the client without configuring the private key - [x] Fix the issue of freezing when entering the client without configuring the private key
- [ ] Replace Android robot icon with custom design - [x] Replace Android robot icon with custom design
- [ ] Configure server baseURL in client settings - [ ] Configure server baseURL in client settings
- [ ] Implement proper access control for directory queries - [ ] Implement proper access control for directory queries

BIN
aether.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@@ -12,9 +12,9 @@
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/aether"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/aether_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Aether" android:theme="@style/Theme.Aether"
android:name=".AetherApp"> android:name=".AetherApp">

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

View File

@@ -275,7 +275,7 @@ fun CardPage(
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(16.dp), .padding(6.dp),
elevation = CardDefaults.cardElevation(4.dp), elevation = CardDefaults.cardElevation(4.dp),
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
colors = CardDefaults.cardColors(containerColor = colorScheme.background) colors = CardDefaults.cardColors(containerColor = colorScheme.background)

View File

@@ -1,6 +1,8 @@
package com.acitelight.aether.service package com.acitelight.aether.service
import android.content.Context import android.content.Context
import com.acitelight.aether.Screen
import com.acitelight.aether.model.Video
import com.acitelight.aether.service.ApiClient.createOkHttp import com.acitelight.aether.service.ApiClient.createOkHttp
import com.tonyodev.fetch2.Download import com.tonyodev.fetch2.Download
import com.tonyodev.fetch2.Fetch import com.tonyodev.fetch2.Fetch
@@ -8,8 +10,10 @@ import com.tonyodev.fetch2.FetchConfiguration
import com.tonyodev.fetch2.FetchListener import com.tonyodev.fetch2.FetchListener
import com.tonyodev.fetch2.Request import com.tonyodev.fetch2.Request
import com.tonyodev.fetch2.Status import com.tonyodev.fetch2.Status
import com.tonyodev.fetch2core.Extras
import com.tonyodev.fetch2okhttp.OkHttpDownloader import com.tonyodev.fetch2okhttp.OkHttpDownloader
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.File
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@@ -76,10 +80,26 @@ class FetchManager @Inject constructor(
} ?: callback?.invoke() } ?: callback?.invoke()
} }
private fun enqueue(request: Request, onEnqueued: ((Request) -> Unit)? = null, onError: ((com.tonyodev.fetch2.Error) -> Unit)? = null) {
// enqueue helper if needed
fun enqueue(request: Request, onEnqueued: ((Request) -> Unit)? = null, onError: ((com.tonyodev.fetch2.Error) -> Unit)? = null) {
if (fetch == null) init() if (fetch == null) init()
fetch?.enqueue(request, { r -> onEnqueued?.invoke(r) }, { e -> onError?.invoke(e) }) fetch?.enqueue(request, { r -> onEnqueued?.invoke(r) }, { e -> onError?.invoke(e) })
} }
private fun getVideosDirectory() {
val appFilesDir = context.filesDir
val videosDir = File(appFilesDir, "videos")
if (!videosDir.exists()) {
val created = videosDir.mkdirs()
}
}
fun startVideoDownload(video: Video)
{
val path = File(context.filesDir, "videos/${video.klass}/${video.id}")
val request = Request(video.getVideo(), path.path).apply {
extras = Extras(mapOf("name" to video.video.name, "id" to video.id, "class" to video.klass))
}
enqueue(request)
}
} }

View File

@@ -130,8 +130,8 @@ fun generateColorScheme(primaryColor: Color, isDarkMode: Boolean): ColorScheme {
} }
} }
private val DarkColorScheme = generateColorScheme(Color(0xFFFF4081), isDarkMode = true) private val DarkColorScheme = generateColorScheme(Color(0xFF2F4F8F), isDarkMode = true)
private val LightColorScheme = generateColorScheme(Color(0xFFFF4081), isDarkMode = false) private val LightColorScheme = generateColorScheme(Color(0xFF2F4F8F), isDarkMode = false)
@Composable @Composable
fun AetherTheme( fun AetherTheme(

View File

@@ -81,7 +81,6 @@ private fun DownloadCard(
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text(text = model.fileName, style = MaterialTheme.typography.titleMedium) Text(text = model.fileName, style = MaterialTheme.typography.titleMedium)
Text(text = model.url, style = MaterialTheme.typography.displayMedium, modifier = Modifier.padding(top = 4.dp))
} }
// progress percentage // progress percentage

View File

@@ -128,6 +128,7 @@ fun BiliStyleSlider(
onValueChange: (Float) -> Unit, onValueChange: (Float) -> Unit,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f valueRange: ClosedFloatingPointRange<Float> = 0f..1f
) { ) {
val colorScheme = MaterialTheme.colorScheme
val thumbRadius = 6.dp val thumbRadius = 6.dp
val trackHeight = 3.dp val trackHeight = 3.dp
@@ -137,8 +138,8 @@ fun BiliStyleSlider(
valueRange = valueRange, valueRange = valueRange,
modifier = modifier, modifier = modifier,
colors = SliderDefaults.colors( colors = SliderDefaults.colors(
thumbColor = Color(0xFFFFFFFF), // B站粉色 thumbColor = Color(0xFFFFFFFF),
activeTrackColor = Color(0xFFFF6699), activeTrackColor = colorScheme.primary,
inactiveTrackColor = Color.LightGray.copy(alpha = 0.4f) inactiveTrackColor = Color.LightGray.copy(alpha = 0.4f)
), ),
@@ -154,7 +155,7 @@ fun BiliStyleSlider(
.align(Alignment.CenterStart) .align(Alignment.CenterStart)
.fillMaxWidth(value) .fillMaxWidth(value)
.fillMaxHeight() .fillMaxHeight()
.background(Color(0xFFFF6699), RoundedCornerShape(50)) .background(colorScheme.primary, RoundedCornerShape(50))
) )
} }
} }
@@ -169,6 +170,7 @@ fun BiliMiniSlider(
onValueChange: (Float) -> Unit, onValueChange: (Float) -> Unit,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f valueRange: ClosedFloatingPointRange<Float> = 0f..1f
) { ) {
val colorScheme = MaterialTheme.colorScheme
val thumbRadius = 6.dp val thumbRadius = 6.dp
val trackHeight = 3.dp val trackHeight = 3.dp
@@ -178,8 +180,8 @@ fun BiliMiniSlider(
valueRange = valueRange, valueRange = valueRange,
modifier = modifier, modifier = modifier,
colors = SliderDefaults.colors( colors = SliderDefaults.colors(
thumbColor = Color(0xFFFFFFFF), // B站粉色 thumbColor = Color(0xFFFFFFFF),
activeTrackColor = Color(0xFFFF6699), activeTrackColor = colorScheme.primary,
inactiveTrackColor = Color.LightGray.copy(alpha = 0.4f) inactiveTrackColor = Color.LightGray.copy(alpha = 0.4f)
), ),
thumb = { thumb = {
@@ -197,7 +199,7 @@ fun BiliMiniSlider(
.align(Alignment.CenterStart) .align(Alignment.CenterStart)
.fillMaxWidth(value) .fillMaxWidth(value)
.fillMaxHeight() .fillMaxHeight()
.background(Color(0xFFFF6699), RoundedCornerShape(50)) .background(colorScheme.primary, RoundedCornerShape(50))
) )
} }
} }
@@ -450,9 +452,8 @@ fun PortalCorePlayer(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewMo
} }
} }
if(cover > 0.0f) if(cover > 0.0f)
Spacer(Modifier.background(Color(0x00FF6699 - 0x00222222 + ((0x000000FF * cover).toLong() shl 24) )).fillMaxSize()) Spacer(Modifier.background(MaterialTheme.colorScheme.primary.copy(cover)).fillMaxSize())
androidx.compose.animation.AnimatedVisibility( androidx.compose.animation.AnimatedVisibility(
visible = !videoPlayerViewModel.planeVisibility, visible = !videoPlayerViewModel.planeVisibility,
@@ -704,6 +705,7 @@ fun VideoPlayerPortal(videoPlayerViewModel: VideoPlayerViewModel, navController:
@Composable @Composable
fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel) fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
{ {
val colorScheme = MaterialTheme.colorScheme
Row( Row(
modifier, modifier,
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
@@ -760,7 +762,7 @@ fun SocialPanel(modifier: Modifier, videoPlayerViewModel: VideoPlayerViewModel)
modifier = Modifier.size(28.dp), modifier = Modifier.size(28.dp),
imageVector = Icons.Filled.Star, imageVector = Icons.Filled.Star,
contentDescription = "Star", contentDescription = "Star",
tint = if(videoPlayerViewModel.star) Color(0xFFFF6699) else Color.Gray tint = if(videoPlayerViewModel.star) colorScheme.primary else Color.Gray
) )
} }
} }

View File

@@ -1,6 +1,8 @@
package com.acitelight.aether.view package com.acitelight.aether.view
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -41,6 +43,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import coil3.request.ImageRequest import coil3.request.ImageRequest
import com.acitelight.aether.Global import com.acitelight.aether.Global
@@ -63,7 +66,7 @@ fun String.hexToString(charset: Charset = Charsets.UTF_8): String {
} }
@Composable @Composable
fun VideoScreen(videoScreenViewModel: VideoScreenViewModel = viewModel(), navController: NavHostController) fun VideoScreen(videoScreenViewModel: VideoScreenViewModel = hiltViewModel<VideoScreenViewModel>(), navController: NavHostController)
{ {
val tabIndex by videoScreenViewModel.tabIndex; val tabIndex by videoScreenViewModel.tabIndex;
videoScreenViewModel.SetupClient() videoScreenViewModel.SetupClient()
@@ -113,15 +116,20 @@ fun TopRow(videoScreenViewModel: VideoScreenViewModel)
fun VideoCard(video: Video, navController: NavHostController, videoScreenViewModel: VideoScreenViewModel) { fun VideoCard(video: Video, navController: NavHostController, videoScreenViewModel: VideoScreenViewModel) {
val tabIndex by videoScreenViewModel.tabIndex; val tabIndex by videoScreenViewModel.tabIndex;
Card( Card(
shape = RoundedCornerShape(6.dp),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentHeight(), .wrapContentHeight()
onClick = { .combinedClickable(
updateRelate(videoScreenViewModel.classesMap[videoScreenViewModel.classes[tabIndex]] ?: mutableStateListOf(), video) onClick = {
val route = "video_player_route/${ "${video.klass}/${video.id}".toHex() }" updateRelate(videoScreenViewModel.classesMap[videoScreenViewModel.classes[tabIndex]] ?: mutableStateListOf(), video)
navController.navigate(route) val route = "video_player_route/${ "${video.klass}/${video.id}".toHex() }"
} navController.navigate(route)
},
onLongClick = {
videoScreenViewModel.download(video)
}
),
shape = RoundedCornerShape(6.dp),
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier

View File

@@ -69,8 +69,8 @@ class TransmissionScreenViewModel @Inject constructor(
val existing = idToState[download.id] val existing = idToState[download.id]
if (existing != null) { if (existing != null) {
// update fields in-place -> minimal recomposition // update fields in-place -> minimal recomposition
existing.filePath = download.file ?: existing.filePath existing.filePath = download.file
existing.fileName = try { File(existing.filePath).name } catch (_: Exception) { existing.fileName } existing.fileName = download.request.extras.getString("name", "")
existing.url = download.url existing.url = download.url
existing.progress = download.progress existing.progress = download.progress
existing.status = download.status existing.status = download.status
@@ -97,11 +97,11 @@ class TransmissionScreenViewModel @Inject constructor(
} }
} }
private fun downloadToState(download: Download): DownloadItemState { private fun downloadToState(download: Download): DownloadItemState {
val filePath = download.file ?: "" val filePath = download.file
val fileName = try { File(filePath).name } catch (_: Exception) { filePath }
return DownloadItemState( return DownloadItemState(
id = download.id, id = download.id,
fileName = fileName, fileName = download.request.extras.getString("name", ""),
filePath = filePath, filePath = filePath,
url = download.url, url = download.url,
progress = download.progress, progress = download.progress,

View File

@@ -11,6 +11,7 @@ import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import coil3.ImageLoader import coil3.ImageLoader
import coil3.network.okhttp.OkHttpNetworkFetcherFactory import coil3.network.okhttp.OkHttpNetworkFetcherFactory
@@ -18,14 +19,20 @@ import com.acitelight.aether.dataStore
import com.acitelight.aether.helper.insertInNaturalOrder import com.acitelight.aether.helper.insertInNaturalOrder
import com.acitelight.aether.model.Video import com.acitelight.aether.model.Video
import com.acitelight.aether.service.ApiClient.createOkHttp import com.acitelight.aether.service.ApiClient.createOkHttp
import com.acitelight.aether.service.FetchManager
import com.acitelight.aether.service.MediaManager import com.acitelight.aether.service.MediaManager
import com.acitelight.aether.service.MediaManager.queryVideoKlasses import com.acitelight.aether.service.MediaManager.queryVideoKlasses
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject
class VideoScreenViewModel(application: Application) : AndroidViewModel(application) @HiltViewModel
class VideoScreenViewModel @Inject constructor(
private val fetchManager: FetchManager
) : ViewModel()
{ {
private val _tabIndex = mutableIntStateOf(0) private val _tabIndex = mutableIntStateOf(0)
val tabIndex: State<Int> = _tabIndex val tabIndex: State<Int> = _tabIndex
@@ -83,6 +90,11 @@ class VideoScreenViewModel(application: Application) : AndroidViewModel(applicat
} }
} }
fun download(video :Video)
{
fetchManager.startVideoDownload(video)
}
init { init {
viewModelScope.launch { viewModelScope.launch {
init() init()

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/aether_background"/>
<foreground android:drawable="@mipmap/aether_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/aether_background"/>
<foreground android:drawable="@mipmap/aether_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB