Add TODO app
This commit is contained in:
parent
1da5250b9a
commit
04dabcb418
18 changed files with 774 additions and 28 deletions
|
@ -11,8 +11,8 @@ android {
|
||||||
applicationId = "uk.kagurach.android101"
|
applicationId = "uk.kagurach.android101"
|
||||||
minSdk = 31
|
minSdk = 31
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 132
|
versionCode = 140
|
||||||
versionName = "1.3.2"
|
versionName = "1.4.0"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
@ -33,16 +33,50 @@ android {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "17"
|
jvmTarget = "17"
|
||||||
}
|
}
|
||||||
|
buildFeatures {
|
||||||
|
compose = true
|
||||||
|
viewBinding = true
|
||||||
|
}
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.5.1"
|
||||||
|
}
|
||||||
|
androidResources {
|
||||||
|
generateLocaleConfig = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
implementation(libs.material)
|
implementation(libs.material)
|
||||||
implementation(libs.androidx.activity)
|
implementation(libs.androidx.activity)
|
||||||
implementation(libs.androidx.constraintlayout)
|
implementation(libs.androidx.constraintlayout)
|
||||||
|
implementation(libs.androidx.core.ktx)
|
||||||
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
|
implementation(libs.androidx.activity.compose)
|
||||||
|
implementation(platform(libs.androidx.compose.bom))
|
||||||
|
implementation(libs.androidx.ui)
|
||||||
|
implementation(libs.androidx.ui.graphics)
|
||||||
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
|
implementation(libs.androidx.material3)
|
||||||
|
implementation(libs.androidx.room.common)
|
||||||
|
implementation(libs.androidx.room.ktx)
|
||||||
|
implementation(libs.androidx.constraintlayout)
|
||||||
|
implementation(libs.androidx.navigation.fragment.ktx)
|
||||||
|
implementation(libs.androidx.navigation.ui.ktx)
|
||||||
|
implementation(libs.androidx.activity)
|
||||||
|
implementation(libs.androidx.annotation)
|
||||||
|
implementation(libs.androidx.lifecycle.livedata.ktx)
|
||||||
|
implementation(libs.androidx.lifecycle.viewmodel.ktx)
|
||||||
|
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
|
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
|
|
||||||
|
androidTestImplementation(platform(libs.androidx.compose.bom))
|
||||||
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
|
|
||||||
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
}
|
}
|
|
@ -14,15 +14,6 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Android101"
|
android:theme="@style/Theme.Android101"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
|
||||||
android:name=".Page4"
|
|
||||||
android:exported="false" />
|
|
||||||
<activity
|
|
||||||
android:name=".Page3"
|
|
||||||
android:exported="false" />
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity2"
|
|
||||||
android:exported="false" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
@ -32,6 +23,37 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".Page4"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".Page3"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity2"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".todoList.AddPage"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/title_activity_add_page"
|
||||||
|
android:theme="@style/Theme.TODOList" />
|
||||||
|
<activity
|
||||||
|
android:name=".todoList.MainActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="todoListMain"
|
||||||
|
android:theme="@style/Theme.TODOList">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="android.app.shortcuts"
|
||||||
|
android:resource="@xml/shortcuts" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -1,9 +1,15 @@
|
||||||
package uk.kagurach.android101;
|
package uk.kagurach.android101;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ShortcutInfo;
|
||||||
|
import android.content.pm.ShortcutManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
@ -17,6 +23,8 @@ import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
PageHelper pageHelper;
|
PageHelper pageHelper;
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,6 +37,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||||
return insets;
|
return insets;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,6 +59,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
101);
|
101);
|
||||||
}
|
}
|
||||||
textViewAppendString(tv,"Check Finished");
|
textViewAppendString(tv,"Check Finished");
|
||||||
|
textViewAppendString(tv,"提示:常桉有惊喜");
|
||||||
}
|
}
|
||||||
textViewAppendString(tv,"*************************\nfinished");
|
textViewAppendString(tv,"*************************\nfinished");
|
||||||
|
|
||||||
|
@ -58,10 +68,8 @@ public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
Button button = findViewById(R.id.Page1NextPage);
|
Button button = findViewById(R.id.Page1NextPage);
|
||||||
button.setEnabled(true);
|
button.setEnabled(true);
|
||||||
}
|
button.setOnClickListener(pageHelper.pageButtonHandler);
|
||||||
|
button.setOnLongClickListener(new LongClickHandler(this));
|
||||||
public void jumpToNext(View view) {
|
|
||||||
pageHelper.goNext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void textViewAppendString(@NonNull TextView tv, String s){
|
private void textViewAppendString(@NonNull TextView tv, String s){
|
||||||
|
@ -72,4 +80,41 @@ public class MainActivity extends AppCompatActivity {
|
||||||
last += s;
|
last += s;
|
||||||
tv.setText(last);
|
tv.setText(last);
|
||||||
}
|
}
|
||||||
|
private final class LongClickHandler implements View.OnLongClickListener
|
||||||
|
{
|
||||||
|
LongClickHandler(Context ctx){
|
||||||
|
context = ctx;
|
||||||
|
}
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v){
|
||||||
|
CreateShortcut(context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void CreateShortcut(Context context) {
|
||||||
|
ShortcutManager shortcutManager =
|
||||||
|
this.getSystemService(ShortcutManager.class);
|
||||||
|
if (shortcutManager.isRequestPinShortcutSupported()) {
|
||||||
|
ShortcutInfo pinShortcutInfo;
|
||||||
|
try {
|
||||||
|
pinShortcutInfo =
|
||||||
|
new ShortcutInfo.Builder(context, "start_TODO").build();
|
||||||
|
}catch (Exception e){
|
||||||
|
Log.e("ShortCutManager", Arrays.toString(e.getStackTrace()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent pinnedShortcutCallbackIntent =
|
||||||
|
shortcutManager.createShortcutResultIntent(pinShortcutInfo);
|
||||||
|
|
||||||
|
PendingIntent successCallback = PendingIntent.getBroadcast(context, 0,
|
||||||
|
pinnedShortcutCallbackIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||||
|
|
||||||
|
shortcutManager.requestPinShortcut(pinShortcutInfo,
|
||||||
|
successCallback.getIntentSender());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -62,7 +62,7 @@ public class MainActivity2 extends AppCompatActivity {
|
||||||
|
|
||||||
public void setColor(View view) {
|
public void setColor(View view) {
|
||||||
TextView t = findViewById(R.id.test2strview);
|
TextView t = findViewById(R.id.test2strview);
|
||||||
EditText r_edit = findViewById(R.id.R);
|
EditText r_edit = findViewById(R.id.EditText_R);
|
||||||
EditText g_edit = findViewById(R.id.G);
|
EditText g_edit = findViewById(R.id.G);
|
||||||
EditText b_edit = findViewById(R.id.B);
|
EditText b_edit = findViewById(R.id.B);
|
||||||
|
|
||||||
|
|
185
app/src/main/java/uk/kagurach/android101/todoList/AddPage.kt
Normal file
185
app/src/main/java/uk/kagurach/android101/todoList/AddPage.kt
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
package uk.kagurach.android101.todoList
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.icu.util.Calendar
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material3.DatePicker
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.FabPosition
|
||||||
|
import androidx.compose.material3.FloatingActionButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.material3.TimePicker
|
||||||
|
import androidx.compose.material3.TimePickerState
|
||||||
|
import androidx.compose.material3.rememberDatePickerState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import uk.kagurach.android101.R
|
||||||
|
import uk.kagurach.android101.todoList.ui.theme.LightBlue100
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
|
|
||||||
|
class AddPage() : ComponentActivity() {
|
||||||
|
var item: TodoItem? = null
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setContent {
|
||||||
|
// A surface container using the 'background' color from the theme
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
AddPageLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix Input Method
|
||||||
|
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
||||||
|
if (currentFocus != null) {
|
||||||
|
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
imm.hideSoftInputFromWindow(currentFocus!!.windowToken, 0)
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun AddPageLayout(){
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
var title by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
when (item){
|
||||||
|
null -> ""
|
||||||
|
else -> item!!.title
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val c = Calendar.getInstance()
|
||||||
|
|
||||||
|
val timePickerState by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
when (item){
|
||||||
|
null -> TimePickerState(c.get(Calendar.HOUR_OF_DAY),c.get(Calendar.MINUTE),true)
|
||||||
|
else -> TimePickerState(
|
||||||
|
item!!.dueDate.split(" ")[1].split(":")[0].toInt(),
|
||||||
|
item!!.dueDate.split(" ")[1].split(":")[1].toInt(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val datePickerState = rememberDatePickerState(
|
||||||
|
initialDisplayedMonthMillis = System.currentTimeMillis(),
|
||||||
|
yearRange = 2024..2099
|
||||||
|
)
|
||||||
|
Scaffold (
|
||||||
|
topBar = {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(50.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = context.getText(R.string.edit_page_title).toString(),
|
||||||
|
fontSize = 30.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
content = { padding ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(padding)
|
||||||
|
) {
|
||||||
|
TextField(
|
||||||
|
value = title,
|
||||||
|
onValueChange = { title = it },
|
||||||
|
label = { Text(context.getText(R.string.enter_title).toString()) },
|
||||||
|
maxLines = 1,
|
||||||
|
modifier = Modifier
|
||||||
|
.height(80.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(top = 15.dp, bottom = 15.dp),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
DatePicker(state = datePickerState)
|
||||||
|
}
|
||||||
|
TimePicker(
|
||||||
|
state = timePickerState,
|
||||||
|
modifier = Modifier.padding(start = 70.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
floatingActionButtonPosition = FabPosition.End,
|
||||||
|
floatingActionButton = {
|
||||||
|
Submit {
|
||||||
|
if (title.isBlank()||datePickerState.selectedDateMillis==null){
|
||||||
|
Toast.makeText(context,"Please Fill Every field",Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
return@Submit
|
||||||
|
}
|
||||||
|
val loader = TodoItemLoader(context)
|
||||||
|
val sdf = SimpleDateFormat("yyyy-MM-dd")
|
||||||
|
|
||||||
|
|
||||||
|
val todoItem = TodoItem(
|
||||||
|
loader.getLastId()+1,
|
||||||
|
title.replace("\t"," "),
|
||||||
|
sdf.format(datePickerState.selectedDateMillis) + " " +
|
||||||
|
timePickerState.hour.toString() + ":" +
|
||||||
|
timePickerState.minute.toString()
|
||||||
|
)
|
||||||
|
loader.changeItem(todoItem)
|
||||||
|
val myIntent = Intent(context, MainActivity::class.java)
|
||||||
|
ContextCompat.startActivity(context, myIntent, null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Submit(onClick: () -> Unit) {
|
||||||
|
FloatingActionButton(
|
||||||
|
onClick = { onClick() },
|
||||||
|
containerColor = LightBlue100
|
||||||
|
) {
|
||||||
|
Icon(Icons.Filled.Add, "Submit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package uk.kagurach.android101.todoList
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.FabPosition
|
||||||
|
import androidx.compose.material3.FloatingActionButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import uk.kagurach.android101.todoList.ui.theme.LightBlue100
|
||||||
|
|
||||||
|
class MainActivity : ComponentActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
val loader = TodoItemLoader(this)
|
||||||
|
val tmpList = loader.getTodoItems()
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContent {
|
||||||
|
LayOut(tmpList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun LayOut(tmpList : List<TodoItem>?) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
Scaffold (
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Simple TODO ^_^") }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
content = {
|
||||||
|
padding ->
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.padding(padding)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
if (tmpList != null) {
|
||||||
|
Column {
|
||||||
|
for (i in tmpList) {
|
||||||
|
TodoItemView(todoItem = i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
floatingActionButtonPosition = FabPosition.End,
|
||||||
|
floatingActionButton = {
|
||||||
|
NextPage {
|
||||||
|
val myIntent = Intent(context, AddPage::class.java)
|
||||||
|
ContextCompat.startActivity(context, myIntent, null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NextPage(onClick: () -> Unit) {
|
||||||
|
FloatingActionButton(
|
||||||
|
onClick = { onClick() },
|
||||||
|
containerColor = LightBlue100
|
||||||
|
) {
|
||||||
|
Icon(Icons.Filled.Add, "Floating action button.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package uk.kagurach.android101.todoList
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
data class TodoItem(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
val id: Int,
|
||||||
|
|
||||||
|
var title: String,
|
||||||
|
var dueDate: String,
|
||||||
|
|
||||||
|
var isCompleted:Boolean = false,
|
||||||
|
|
||||||
|
var MarkDeleted:Boolean = false
|
||||||
|
)
|
|
@ -0,0 +1,106 @@
|
||||||
|
package uk.kagurach.android101.todoList
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileWriter
|
||||||
|
|
||||||
|
class TodoItemLoader(private val context: Context) {
|
||||||
|
private val db = File(context.filesDir,"db")
|
||||||
|
|
||||||
|
public fun getTodoItems(): List<TodoItem>?{
|
||||||
|
if (!db.exists()){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val lines = db.readLines()
|
||||||
|
if (lines.isEmpty()){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
var list: List<TodoItem> = listOf()
|
||||||
|
for (line in lines){
|
||||||
|
val split = line.split("\t")
|
||||||
|
val item: TodoItem
|
||||||
|
try {
|
||||||
|
item = TodoItem(split[0].toInt(),split[1],split[2], split[3].toBooleanStrict())
|
||||||
|
list = list + item
|
||||||
|
} catch (e: Exception){
|
||||||
|
Log.e("DB Error", e.printStackTrace().toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (list.isNotEmpty()){
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun saveTodoItems(list:List<TodoItem>){
|
||||||
|
var result = ""
|
||||||
|
for (i in list){
|
||||||
|
if(!i.MarkDeleted) {
|
||||||
|
result += "%s\t%s\t%s\t%s\n".format(
|
||||||
|
i.id.toString(),
|
||||||
|
i.title,
|
||||||
|
i.dueDate,
|
||||||
|
i.isCompleted.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val fileWriter = FileWriter(db)
|
||||||
|
fileWriter.write(result)
|
||||||
|
fileWriter.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun getLastId():Int{
|
||||||
|
val items = getTodoItems();
|
||||||
|
return if (items==null){
|
||||||
|
0
|
||||||
|
}else{
|
||||||
|
var max = 0
|
||||||
|
for (i in items){
|
||||||
|
if (i.id>max){
|
||||||
|
max = i.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun changeItem(todoItem: TodoItem){
|
||||||
|
var items = getTodoItems()
|
||||||
|
var changeFlag = false
|
||||||
|
if (items != null) {
|
||||||
|
for (i in items){
|
||||||
|
if (i.id==todoItem.id){
|
||||||
|
i.title = todoItem.title
|
||||||
|
i.dueDate = todoItem.dueDate
|
||||||
|
i.MarkDeleted = todoItem.MarkDeleted
|
||||||
|
i.isCompleted = todoItem.isCompleted
|
||||||
|
changeFlag = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!changeFlag){
|
||||||
|
items = items + todoItem
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
items = listOf(todoItem)
|
||||||
|
}
|
||||||
|
saveTodoItems(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun searchItem(id:Int): TodoItem?{
|
||||||
|
val items = getTodoItems();
|
||||||
|
return if (items==null){
|
||||||
|
null
|
||||||
|
}else{
|
||||||
|
for (i in items){
|
||||||
|
if (i.id>id){
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
package uk.kagurach.android101.todoList
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import uk.kagurach.android101.R
|
||||||
|
import uk.kagurach.android101.todoList.ui.theme.Blue100
|
||||||
|
import uk.kagurach.android101.todoList.ui.theme.Green100
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TodoItemView(todoItem: TodoItem) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val loader = TodoItemLoader(context)
|
||||||
|
|
||||||
|
var deleteText by remember {
|
||||||
|
mutableStateOf(context.getText(R.string.first_delete).toString())
|
||||||
|
}
|
||||||
|
var bgColor by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
when (todoItem.isCompleted){
|
||||||
|
true -> Green100
|
||||||
|
false -> Blue100
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var needShow by remember {
|
||||||
|
mutableStateOf(true)
|
||||||
|
}
|
||||||
|
if (!needShow){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentSize()
|
||||||
|
.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(20.dp),
|
||||||
|
color = bgColor
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(
|
||||||
|
start = 10.dp,
|
||||||
|
end = 10.dp
|
||||||
|
)
|
||||||
|
){
|
||||||
|
Text(
|
||||||
|
text = todoItem.title,
|
||||||
|
color = Color.Black,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
fontFamily = FontFamily.Monospace
|
||||||
|
)
|
||||||
|
Row{
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Text(
|
||||||
|
text = todoItem.dueDate,
|
||||||
|
color = Color.Black,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontFamily = FontFamily.SansSerif
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
if (!todoItem.isCompleted){
|
||||||
|
Toast.makeText( context,
|
||||||
|
context.getText(R.string.yes_not_finish)
|
||||||
|
,Toast.LENGTH_SHORT).show()
|
||||||
|
}else{
|
||||||
|
todoItem.isCompleted = false
|
||||||
|
loader.changeItem(todoItem)
|
||||||
|
bgColor = Blue100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(0),
|
||||||
|
modifier = Modifier.width(110.dp)
|
||||||
|
) {
|
||||||
|
Text(text = context.getText(R.string.unfinish).toString())
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(20.dp))
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
if (todoItem.isCompleted){
|
||||||
|
Toast.makeText( context,
|
||||||
|
context.getText(R.string.already_finish)
|
||||||
|
,Toast.LENGTH_SHORT).show()
|
||||||
|
}else{
|
||||||
|
todoItem.isCompleted = true
|
||||||
|
loader.changeItem(todoItem)
|
||||||
|
bgColor = Green100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(0),
|
||||||
|
modifier = Modifier.width(110.dp)
|
||||||
|
) {
|
||||||
|
Text(text = context.getText(R.string.finish).toString())
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(20.dp))
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
when (deleteText){
|
||||||
|
context.getText(R.string.first_delete).toString() ->
|
||||||
|
deleteText=context.getText(R.string.second_delete).toString()
|
||||||
|
else -> {
|
||||||
|
needShow = false
|
||||||
|
todoItem.MarkDeleted = true
|
||||||
|
loader.changeItem(todoItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(0),
|
||||||
|
modifier = Modifier.width(110.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = deleteText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun TodoItemPreview(){
|
||||||
|
val todoItem = TodoItem(
|
||||||
|
0,"Test TODO Item","2024-04-30 11:45",
|
||||||
|
)
|
||||||
|
val todoItem2 = TodoItem(
|
||||||
|
1,"测试喵","2024-11-01 22:33",true
|
||||||
|
)
|
||||||
|
Column {
|
||||||
|
TodoItemView(todoItem)
|
||||||
|
TodoItemView(todoItem2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun NextPage(context:Context,item: TodoItem) {
|
||||||
|
val myIntent = Intent(context, AddPage::class.java)
|
||||||
|
myIntent.putExtra("ITEM",item.id)
|
||||||
|
ContextCompat.startActivity(context, myIntent, null)
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package uk.kagurach.android101.todoList.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
|
||||||
|
val Green100 = Color(0xFFC8E6C9)
|
||||||
|
val Blue100 = Color(0xFFBBDEFB)
|
||||||
|
val Red100 = Color(0xFFFFCDD2)
|
||||||
|
val LightBlue100 = Color(0xFFB2EBF2)
|
||||||
|
val Yellow100 = Color(0xFFFFF9C4)
|
|
@ -86,7 +86,7 @@
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/R"
|
android:id="@+id/EditText_R"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
|
1
app/src/main/res/resources.properties
Normal file
1
app/src/main/res/resources.properties
Normal file
|
@ -0,0 +1 @@
|
||||||
|
unqualifiedResLocale=zh-rCN
|
14
app/src/main/res/values-zh-rCN/strings.xml
Normal file
14
app/src/main/res/values-zh-rCN/strings.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Android 101</string>
|
||||||
|
<string name="already_finish">您已经完成了喵</string>
|
||||||
|
<string name="yes_not_finish">呜呜您还没完成呢</string>
|
||||||
|
<string name="finish">做完了!</string>
|
||||||
|
<string name="unfinish">还没好!</string>
|
||||||
|
<string name="edit_page_title">修改您的TODO任务</string>
|
||||||
|
<string name="enter_title">标题</string>
|
||||||
|
<string name="first_delete">删除</string>
|
||||||
|
<string name="second_delete">确认删除</string>
|
||||||
|
<string name="todo_app">任务清单</string>
|
||||||
|
<string name="todo_app_short_label">启动任务清单</string>
|
||||||
|
</resources>
|
|
@ -1,12 +1,24 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="todo_app">TODO List</string>
|
||||||
|
<string name="already_finish">You have already finished❤️</string>
|
||||||
|
<string name="yes_not_finish">You haven\'t finished😇</string>
|
||||||
|
<string name="finish">Finish</string>
|
||||||
|
<string name="unfinish">Not Finish</string>
|
||||||
|
<string name="title_activity_add_page" translatable="false">add_page</string>
|
||||||
|
<string name="edit_page_title">Edit Your TODO Item Here</string>
|
||||||
|
<string name="enter_title">Enter Title</string>
|
||||||
|
<string name="first_delete">Delete</string>
|
||||||
|
<string name="second_delete">Delete!!</string>
|
||||||
|
|
||||||
<string name="app_name">Android101</string>
|
<string name="app_name">Android101</string>
|
||||||
<string name="hello_world">你好,世界!</string>
|
<string name="hello_world" translatable="false">你好,世界!</string>
|
||||||
<string name="next_page">下一页</string>
|
<string name="next_page" translatable="false">下一页</string>
|
||||||
<string name="two_way_page">单击下一页,长按上一页</string>
|
<string name="two_way_page" translatable="false">单击下一页,长按上一页</string>
|
||||||
<string name="test_str">测试文本</string>
|
<string name="test_str" translatable="false">测试文本</string>
|
||||||
<string name="set_color">设置颜色</string>
|
<string name="set_color" translatable="false">设置颜色</string>
|
||||||
<string name="set">设置</string>
|
<string name="set" translatable="false">设置</string>
|
||||||
<string name="setText">设置文本</string>
|
<string name="setText" translatable="false">设置文本</string>
|
||||||
<string name="kaculate">弱智计算器</string>
|
<string name="kaculate" translatable="false">弱智计算器</string>
|
||||||
<string name="Backspace">退格</string>
|
<string name="Backspace" translatable="false">退格</string>
|
||||||
|
<string name="todo_app_short_label">Open TODO</string>
|
||||||
</resources>
|
</resources>
|
|
@ -13,4 +13,8 @@
|
||||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
</style>
|
</style>
|
||||||
|
<style name="Theme.TODOList" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="Base.Theme.TODOList" parent="Theme.Material3.DayNight.NoActionBar"/>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
17
app/src/main/res/xml/shortcuts.xml
Normal file
17
app/src/main/res/xml/shortcuts.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="start_TODO"
|
||||||
|
android:enabled="true"
|
||||||
|
android:icon="@drawable/ic_launcher_background"
|
||||||
|
android:shortcutShortLabel="@string/todo_app_short_label"
|
||||||
|
android:shortcutLongLabel="@string/todo_app"
|
||||||
|
android:shortcutDisabledMessage="@string/todo_app">
|
||||||
|
<intent
|
||||||
|
android:action="android.intent.action.VIEW"
|
||||||
|
android:targetPackage="uk.kagurach.android101"
|
||||||
|
android:targetClass="uk.kagurach.android101.todoList.MainActivity" />
|
||||||
|
<categories android:name="android.shortcut.conversation" />
|
||||||
|
<capability-binding android:key="actions.intent.CREATE_MESSAGE" />
|
||||||
|
</shortcut>
|
||||||
|
</shortcuts>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. For more details, visit
|
# This option should only be used with decoupled projects. For more details, visit
|
||||||
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
||||||
|
|
|
@ -9,6 +9,16 @@ appcompat = "1.6.1"
|
||||||
material = "1.11.0"
|
material = "1.11.0"
|
||||||
activity = "1.8.0"
|
activity = "1.8.0"
|
||||||
constraintlayout = "2.1.4"
|
constraintlayout = "2.1.4"
|
||||||
|
lifecycleRuntimeKtx = "2.7.0"
|
||||||
|
activityCompose = "1.8.2"
|
||||||
|
composeBom = "2023.08.00"
|
||||||
|
roomCommon = "2.6.1"
|
||||||
|
roomKtx = "2.6.1"
|
||||||
|
navigationFragmentKtx = "2.6.0"
|
||||||
|
navigationUiKtx = "2.6.0"
|
||||||
|
annotation = "1.6.0"
|
||||||
|
lifecycleLivedataKtx = "2.7.0"
|
||||||
|
lifecycleViewmodelKtx = "2.7.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
@ -19,6 +29,23 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version
|
||||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||||
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||||
|
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
||||||
|
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
|
||||||
|
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
|
||||||
|
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
|
||||||
|
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
||||||
|
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
||||||
|
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
||||||
|
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||||
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
|
androidx-room-common = { group = "androidx.room", name = "room-common", version.ref = "roomCommon" }
|
||||||
|
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "roomKtx" }
|
||||||
|
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
|
||||||
|
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
|
||||||
|
androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" }
|
||||||
|
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
|
||||||
|
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|
Loading…
Reference in a new issue