diff --git a/README.md b/README.md
new file mode 100644
index 0000000..97fc0dd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# JetPackCompose_Basic
+This repository useful to learn basic to intermediate level of Jetpack compose. Jetpack compose(JC) is a modern ui development toolkit. It serves as a beginner-friendly project, providing an introduction to Jetpack Compose for newcomers and go upto Intermediate level.
+
+# Jetpacl Glance
+
+Jetpack Glance is a framework built on top of the Jetpack Compose runtime that lets you develop and design app widgets using Kotlin APIs. App widgets are miniature application views that can be embedded in other applications and receive periodic updates.
+
+
+Glance provides a set of composables to help you build responsive widgets for the home screen quickly and with less code. The pages in this doc set describe how to use Glance to build app widgets.
diff --git a/app/build.gradle b/app/build.gradle
index 75677b5..9017aae 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -5,12 +5,12 @@ plugins {
android {
namespace 'com.lahsuak.apps.jetpackcomposebasic'
- compileSdk 33
+ compileSdk 34
defaultConfig {
applicationId "com.lahsuak.apps.jetpackcomposebasic"
minSdk 23
- targetSdk 33
+ targetSdk 34
versionCode 1
versionName "1.0"
@@ -27,17 +27,17 @@ android {
}
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = '1.8'
+ jvmTarget = '17'
}
buildFeatures {
compose true
}
composeOptions {
- kotlinCompilerExtensionVersion '1.1.1'
+ kotlinCompilerExtensionVersion '1.4.0'
}
packagingOptions {
resources {
@@ -48,16 +48,19 @@ android {
dependencies {
- implementation 'androidx.core:core-ktx:1.9.0'
- implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
- implementation 'androidx.activity:activity-compose:1.6.1'
+ implementation 'androidx.core:core-ktx:1.10.1'
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
+ implementation 'androidx.activity:activity-compose:1.7.2'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
- implementation 'androidx.compose.material3:material3:1.1.0-alpha03'
+ implementation 'androidx.compose.material3:material3:1.2.0-alpha03'
testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.4'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
+
+ implementation 'androidx.glance:glance:1.0.0-beta01'
+ implementation "androidx.glance:glance-appwidget:1.0.0-beta01"
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5ebfd06..f9f7962 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,7 +15,6 @@
@@ -27,6 +26,14 @@
android:name="android.app.lib_name"
android:value="" />
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt
index 187ee32..8c2dc49 100644
--- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt
+++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt
@@ -1,16 +1,34 @@
package com.lahsuak.apps.jetpackcomposebasic
import android.os.Bundle
+import android.text.format.DateFormat
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme
+import kotlinx.coroutines.delay
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -22,29 +40,50 @@ class MainActivity : ComponentActivity() {
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
- Greeting("Android")
+ Clock()
}
}
}
}
}
-/***
-Composable functions :
-A composable function is a regular function annotated with @Composable.
-This enables your function to call other @Composable functions within it.
-You can see how the Greeting function is marked as @Composable.
-This function will produce a piece of UI hierarchy displaying the given input,
-String. Text is a composable function provided by the library.
-***/
+
@Composable
-fun Greeting(name: String) {
- Text(text = "Hello $name!")
+fun Clock() {
+ var date by remember {
+ mutableStateOf(
+ DateFormat.format("hh:mm:ss a", System.currentTimeMillis())
+ )
+ }
+ LaunchedEffect(Unit) {
+ while (true) {
+ delay(1000L)
+ date = DateFormat.format("hh:mm:ss a", System.currentTimeMillis())
+ }
+ }
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color.DarkGray),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ text = "Widget Demo", style = TextStyle(color = Color.White, fontSize = 24.sp)
+ )
+ Spacer(modifier = Modifier.height(48.dp))
+ AnimatedContent(targetState = date) {
+ Text(
+ text = it.toString(),
+ style = TextStyle(color = Color.White, fontSize = 48.sp)
+ )
+ }
+ }
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
JetPackComposeBasicTheme {
- Greeting("Android")
+ Clock()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/widget/CounterWidget.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/widget/CounterWidget.kt
new file mode 100644
index 0000000..6c47cd2
--- /dev/null
+++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/widget/CounterWidget.kt
@@ -0,0 +1,133 @@
+package com.lahsuak.apps.jetpackcomposebasic.widget
+
+import android.content.Context
+import android.text.format.DateFormat
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableLongStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.datastore.preferences.core.intPreferencesKey
+import androidx.glance.Button
+import androidx.glance.GlanceId
+import androidx.glance.GlanceModifier
+import androidx.glance.action.ActionParameters
+import androidx.glance.appwidget.GlanceAppWidget
+import androidx.glance.appwidget.GlanceAppWidgetReceiver
+import androidx.glance.appwidget.action.ActionCallback
+import androidx.glance.appwidget.action.actionRunCallback
+import androidx.glance.appwidget.provideContent
+import androidx.glance.appwidget.state.updateAppWidgetState
+import androidx.glance.background
+import androidx.glance.currentState
+import androidx.glance.layout.Alignment
+import androidx.glance.layout.Column
+import androidx.glance.layout.Row
+import androidx.glance.layout.Spacer
+import androidx.glance.layout.fillMaxSize
+import androidx.glance.layout.height
+import androidx.glance.layout.width
+import androidx.glance.text.FontWeight
+import androidx.glance.text.Text
+import androidx.glance.text.TextStyle
+import androidx.glance.unit.ColorProvider
+import kotlinx.coroutines.delay
+
+private const val DATE_FORMAT = "hh:mm:ss a"
+private const val COUNT_KEY = "count"
+
+object CounterWidget : GlanceAppWidget() {
+ val countKey = intPreferencesKey(COUNT_KEY)
+ override suspend fun provideGlance(context: Context, id: GlanceId) {
+ provideContent {
+ var date by remember {
+ mutableLongStateOf(
+ System.currentTimeMillis()
+ )
+ }
+ val count = currentState(key = countKey) ?: 0
+ Column(
+ modifier = GlanceModifier
+ .fillMaxSize()
+ .background(Color.DarkGray),
+ verticalAlignment = Alignment.Vertical.CenterVertically,
+ horizontalAlignment = Alignment.Horizontal.CenterHorizontally
+ ) {
+ LaunchedEffect(date) {
+ while (true) {
+ delay(1000L)
+ date = System.currentTimeMillis()
+ }
+ }
+ Text(
+ text = DateFormat.format(DATE_FORMAT, date).toString(),
+ style = TextStyle(color = ColorProvider(Color.White), fontSize = 24.sp)
+ )
+ Spacer(modifier = GlanceModifier.height(8.dp))
+ Text(
+ text = count.toString(),
+ style = TextStyle(
+ fontWeight = FontWeight.Medium,
+ color = ColorProvider(Color.White),
+ fontSize = 26.sp
+ )
+ )
+ Row {
+ Button(
+ text = "+",
+ onClick = actionRunCallback(IncrementActionCallback::class.java)
+ )
+ Spacer(modifier = GlanceModifier.width(8.dp))
+ Button(
+ text = "-",
+ onClick = actionRunCallback(DecrementActionCallback::class.java)
+ )
+ }
+ }
+ }
+ }
+}
+
+class CounterWidgetReceiver : GlanceAppWidgetReceiver() {
+ override val glanceAppWidget: GlanceAppWidget
+ get() = CounterWidget
+}
+
+class IncrementActionCallback : ActionCallback {
+ override suspend fun onAction(
+ context: Context,
+ glanceId: GlanceId,
+ parameters: ActionParameters
+ ) {
+ updateAppWidgetState(context, glanceId) { prefs ->
+ val currentCount = prefs[CounterWidget.countKey]
+ if (currentCount != null) {
+ prefs[CounterWidget.countKey] = currentCount + 1
+ } else {
+ prefs[CounterWidget.countKey] = 1
+ }
+ }
+ CounterWidget.update(context, glanceId)
+ }
+}
+
+class DecrementActionCallback : ActionCallback {
+ override suspend fun onAction(
+ context: Context,
+ glanceId: GlanceId,
+ parameters: ActionParameters
+ ) {
+ updateAppWidgetState(context, glanceId) { prefs ->
+ val currentCount = prefs[CounterWidget.countKey]
+ if (currentCount != null) {
+ prefs[CounterWidget.countKey] = currentCount - 1
+ } else {
+ prefs[CounterWidget.countKey] = 1
+ }
+ }
+ CounterWidget.update(context, glanceId)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/xml/counter_widget_info.xml b/app/src/main/res/xml/counter_widget_info.xml
new file mode 100644
index 0000000..89dc664
--- /dev/null
+++ b/app/src/main/res/xml/counter_widget_info.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index e868fc8..13d8630 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,10 +1,10 @@
buildscript {
ext {
- compose_version = '1.3.2'
+ compose_version = '1.4.3'
}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id 'com.android.application' version '7.3.0' apply false
- id 'com.android.library' version '7.3.0' apply false
- id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
+ id 'com.android.application' version '8.0.2' apply false
+ id 'com.android.library' version '8.0.2' apply false
+ id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
}
\ No newline at end of file