mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-12-22 20:57:54 +01:00
Theming, App bar,Home Screen tabs.
This commit is contained in:
parent
fa2c295a8b
commit
b2c1b57fe0
@ -14,7 +14,7 @@ android {
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.example.composelearn"
|
||||
applicationId "com.shabinder.spotiflyer"
|
||||
minSdkVersion 22
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
@ -75,9 +75,10 @@ dependencies {
|
||||
|
||||
//Compose
|
||||
implementation "androidx.compose.ui:ui:$compose_version"
|
||||
implementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
|
||||
implementation "androidx.compose.material:material:$compose_version"
|
||||
implementation "androidx.compose.material:material-icons-extended:$compose_version"
|
||||
implementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||
|
||||
//Lifecycle
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
|
||||
|
@ -1,24 +0,0 @@
|
||||
package com.example.composelearn
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.example.composelearn", appContext.packageName)
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.composelearn">
|
||||
package="com.shabinder.spotiflyer">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
@ -8,11 +8,11 @@
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.ComposeLearn">
|
||||
android:theme="@style/Theme.SpotiFlyer">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.ComposeLearn">
|
||||
android:theme="@style/Theme.SpotiFlyer">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.example.composelearn
|
||||
package com.shabinder.spotiflyer
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@ -15,11 +15,10 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.setContent
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.WindowCompat
|
||||
import com.example.composelearn.ui.ComposeLearnTheme
|
||||
import com.example.composelearn.ui.appNameStyle
|
||||
import com.shabinder.spotiflyer.home.Home
|
||||
import com.shabinder.spotiflyer.ui.ComposeLearnTheme
|
||||
import com.shabinder.spotiflyer.ui.appNameStyle
|
||||
import dev.chrisbanes.accompanist.insets.ProvideWindowInsets
|
||||
import dev.chrisbanes.accompanist.insets.statusBarsHeight
|
||||
|
||||
@ -33,28 +32,23 @@ class MainActivity : AppCompatActivity() {
|
||||
setContent {
|
||||
ComposeLearnTheme {
|
||||
ProvideWindowInsets {
|
||||
HomeScreen()
|
||||
Column {
|
||||
val appBarColor = MaterialTheme.colors.surface.copy(alpha = 0.87f)
|
||||
|
||||
// Draw a scrim over the status bar which matches the app bar
|
||||
Spacer(Modifier.background(appBarColor).fillMaxWidth().statusBarsHeight())
|
||||
|
||||
AppBar(
|
||||
backgroundColor = appBarColor,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Home()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HomeScreen() {
|
||||
Column {
|
||||
val appBarColor = MaterialTheme.colors.surface.copy(alpha = 0.87f)
|
||||
|
||||
// Draw a scrim over the status bar which matches the app bar
|
||||
Spacer(Modifier.background(appBarColor).fillMaxWidth().statusBarsHeight())
|
||||
|
||||
AppBar(
|
||||
backgroundColor = appBarColor,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -89,10 +83,10 @@ fun AppBar(
|
||||
}
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
//@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun DefaultPreview() {
|
||||
ComposeLearnTheme {
|
||||
HomeScreen()
|
||||
|
||||
}
|
||||
}
|
148
app/src/main/java/com/shabinder/spotiflyer/home/Home.kt
Normal file
148
app/src/main/java/com/shabinder/spotiflyer/home/Home.kt
Normal file
@ -0,0 +1,148 @@
|
||||
package com.shabinder.spotiflyer.home
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.TabDefaults.tabIndicatorOffset
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.InsertLink
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.viewinterop.viewModel
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.shabinder.spotiflyer.R
|
||||
import com.shabinder.spotiflyer.ui.SpotiFlyerTypography
|
||||
import com.shabinder.spotiflyer.ui.colorAccent
|
||||
import com.shabinder.spotiflyer.ui.colorPrimary
|
||||
|
||||
@Composable
|
||||
fun Home(modifier: Modifier = Modifier) {
|
||||
val viewModel: HomeViewModel = viewModel()
|
||||
|
||||
Column(modifier = modifier) {
|
||||
|
||||
AuthenticationBanner(viewModel,modifier)
|
||||
SearchBar(viewModel,modifier)
|
||||
|
||||
val selectedCategory by viewModel.selectedCategory.collectAsState()
|
||||
|
||||
HomeTabBar(
|
||||
selectedCategory,
|
||||
HomeCategory.values(),
|
||||
viewModel::selectCategory,
|
||||
modifier
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AuthenticationBanner(viewModel: HomeViewModel, modifier: Modifier) {
|
||||
val authenticationStatus by viewModel.isAuthenticating.collectAsState()
|
||||
|
||||
if (authenticationStatus) {
|
||||
// TODO show a progress indicator or similar
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HomeTabBar(
|
||||
selectedCategory: HomeCategory,
|
||||
categories: Array<HomeCategory>,
|
||||
selectCategory: (HomeCategory) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val selectedIndex =categories.indexOfFirst { it == selectedCategory }
|
||||
val indicator = @Composable { tabPositions: List<TabPosition> ->
|
||||
HomeCategoryTabIndicator(
|
||||
Modifier.tabIndicatorOffset(tabPositions[selectedIndex])
|
||||
)
|
||||
}
|
||||
|
||||
TabRow(
|
||||
selectedTabIndex = selectedIndex,
|
||||
indicator = indicator,
|
||||
modifier = modifier
|
||||
) {
|
||||
categories.forEachIndexed { index, category ->
|
||||
Tab(
|
||||
selected = index == selectedIndex,
|
||||
onClick = { selectCategory(category) },
|
||||
text = {
|
||||
Text(
|
||||
text = when (category) {
|
||||
HomeCategory.About -> stringResource(R.string.home_about)
|
||||
HomeCategory.History -> stringResource(R.string.home_history)
|
||||
},
|
||||
style = MaterialTheme.typography.body2
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
viewModel: HomeViewModel,
|
||||
modifier: Modifier = Modifier
|
||||
){
|
||||
val link by viewModel.link.collectAsState()
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier.padding(top = 16.dp,bottom = 16.dp)
|
||||
){
|
||||
TextField(
|
||||
leadingIcon = {
|
||||
Icon(Icons.Rounded.InsertLink,tint = Color.LightGray)
|
||||
},
|
||||
label = {Text(text = "Paste Link Here...",color = Color.LightGray)},
|
||||
value = link,
|
||||
onValueChange = { viewModel.updateLink(it) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Uri),
|
||||
modifier = Modifier.padding(12.dp).fillMaxWidth()
|
||||
.border(
|
||||
BorderStroke(2.dp, Brush.horizontalGradient(listOf(colorPrimary, colorAccent))),
|
||||
RoundedCornerShape(30.dp)
|
||||
),
|
||||
backgroundColor = Color.Black,
|
||||
textStyle = AmbientTextStyle.current.merge(TextStyle(fontSize = 20.sp)),
|
||||
shape = RoundedCornerShape(size = 30.dp),
|
||||
activeColor = Color.Transparent,
|
||||
inactiveColor = Color.Transparent
|
||||
)
|
||||
OutlinedButton(
|
||||
modifier = Modifier.padding(12.dp).wrapContentWidth(),
|
||||
onClick = {/*TODO*/},
|
||||
border = BorderStroke(1.dp, Brush.horizontalGradient(listOf(colorPrimary, colorAccent)))
|
||||
){
|
||||
Text(text = "Search",style = SpotiFlyerTypography.h6,modifier = Modifier.padding(4.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
fun HomeCategoryTabIndicator(
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = MaterialTheme.colors.onSurface
|
||||
) {
|
||||
Spacer(
|
||||
modifier.padding(horizontal = 24.dp)
|
||||
.preferredHeight(4.dp)
|
||||
.background(color, RoundedCornerShape(topLeftPercent = 100, topRightPercent = 100))
|
||||
)
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.shabinder.spotiflyer.home
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class HomeViewModel: ViewModel() {
|
||||
|
||||
private val _link = MutableStateFlow("")
|
||||
val link:StateFlow<String>
|
||||
get() = _link
|
||||
|
||||
fun updateLink(s:String) {
|
||||
_link.value = s
|
||||
}
|
||||
|
||||
private val _isAuthenticating = MutableStateFlow(true)
|
||||
val isAuthenticating:StateFlow<Boolean>
|
||||
get() = _isAuthenticating
|
||||
|
||||
fun authenticated(s:Boolean) {
|
||||
_isAuthenticating.value = s
|
||||
}
|
||||
|
||||
private val _selectedCategory = MutableStateFlow(HomeCategory.About)
|
||||
val selectedCategory :StateFlow<HomeCategory>
|
||||
get() = _selectedCategory
|
||||
|
||||
fun selectCategory(s:HomeCategory) {
|
||||
_selectedCategory.value = s
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class HomeCategory {
|
||||
About, History
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.example.composelearn.ui
|
||||
package com.shabinder.spotiflyer.ui
|
||||
|
||||
import androidx.compose.material.Colors
|
||||
import androidx.compose.material.darkColors
|
||||
@ -22,7 +22,9 @@ val SpotiFlyerColors = darkColors(
|
||||
error = colorRedError,
|
||||
onError = Color.Black,
|
||||
surface = darkBackgroundColor,
|
||||
background = darkBackgroundColor
|
||||
background = darkBackgroundColor,
|
||||
onSurface = Color.LightGray,
|
||||
onBackground = Color.LightGray
|
||||
)
|
||||
|
||||
/**
|
@ -1,4 +1,4 @@
|
||||
package com.example.composelearn.ui
|
||||
package com.shabinder.spotiflyer.ui
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Shapes
|
@ -1,4 +1,4 @@
|
||||
package com.example.composelearn.ui
|
||||
package com.shabinder.spotiflyer.ui
|
||||
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
@ -1,11 +1,11 @@
|
||||
package com.example.composelearn.ui
|
||||
package com.shabinder.spotiflyer.ui
|
||||
|
||||
import androidx.compose.material.Typography
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.*
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.composelearn.R
|
||||
import com.shabinder.spotiflyer.R
|
||||
|
||||
private val Montserrat = fontFamily(
|
||||
font(R.font.montserrat_light, FontWeight.Light),
|
||||
@ -110,9 +110,9 @@ val SpotiFlyerTypography = Typography(
|
||||
|
||||
val appNameStyle = TextStyle(
|
||||
fontFamily = pristineFont,
|
||||
fontSize = 42.sp,
|
||||
fontSize = 40.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
lineHeight = 42.sp,
|
||||
letterSpacing = (-0.5).sp,
|
||||
color = Color.White
|
||||
letterSpacing = (1.5).sp,
|
||||
color = Color(0xFFECECEC)
|
||||
)
|
@ -1,3 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">SpotiFlyer</string>
|
||||
<string name="home_about">About</string>
|
||||
<string name="home_history">History</string>
|
||||
</resources>
|
@ -1,9 +1,10 @@
|
||||
<resources>
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.ComposeLearn" parent="Theme.AppCompat.NoActionBar">
|
||||
<style name="Theme.SpotiFlyer" parent="Theme.AppCompat.NoActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
@ -1,17 +0,0 @@
|
||||
package com.example.composelearn
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
21
build.gradle
21
build.gradle
@ -23,12 +23,31 @@ buildscript {
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
subprojects{
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
// Treat all Kotlin warnings as errors
|
||||
//allWarningsAsErrors = true
|
||||
|
||||
freeCompilerArgs += '-Xopt-in=kotlin.RequiresOptIn'
|
||||
|
||||
// Enable experimental coroutines APIs, including Flow
|
||||
freeCompilerArgs += '-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi'
|
||||
freeCompilerArgs += '-Xopt-in=kotlinx.coroutines.FlowPreview'
|
||||
freeCompilerArgs += '-Xopt-in=kotlin.Experimental'
|
||||
|
||||
freeCompilerArgs += "-Xallow-jvm-ir-dependencies"
|
||||
|
||||
// Set JVM target to 1.8
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
@ -1,2 +1,2 @@
|
||||
rootProject.name = "ComposeLearn"
|
||||
rootProject.name = "SpotiFlyer"
|
||||
include ':app'
|
||||
|
Loading…
Reference in New Issue
Block a user