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"
|
||||
minSdk = 31
|
||||
targetSdk = 34
|
||||
versionCode = 132
|
||||
versionName = "1.3.2"
|
||||
versionCode = 140
|
||||
versionName = "1.4.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
@ -33,16 +33,50 @@ android {
|
|||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
viewBinding = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.5.1"
|
||||
}
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.material)
|
||||
implementation(libs.androidx.activity)
|
||||
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)
|
||||
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
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:theme="@style/Theme.Android101"
|
||||
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
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
|
@ -32,6 +23,37 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</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>
|
||||
|
||||
</manifest>
|
|
@ -1,9 +1,15 @@
|
|||
package uk.kagurach.android101;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
@ -17,6 +23,8 @@ import androidx.core.graphics.Insets;
|
|||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
PageHelper pageHelper;
|
||||
@Override
|
||||
|
@ -29,6 +37,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||
return insets;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,6 +59,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
101);
|
||||
}
|
||||
textViewAppendString(tv,"Check Finished");
|
||||
textViewAppendString(tv,"提示:常桉有惊喜");
|
||||
}
|
||||
textViewAppendString(tv,"*************************\nfinished");
|
||||
|
||||
|
@ -58,10 +68,8 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
Button button = findViewById(R.id.Page1NextPage);
|
||||
button.setEnabled(true);
|
||||
}
|
||||
|
||||
public void jumpToNext(View view) {
|
||||
pageHelper.goNext();
|
||||
button.setOnClickListener(pageHelper.pageButtonHandler);
|
||||
button.setOnLongClickListener(new LongClickHandler(this));
|
||||
}
|
||||
|
||||
private void textViewAppendString(@NonNull TextView tv, String s){
|
||||
|
@ -72,4 +80,41 @@ public class MainActivity extends AppCompatActivity {
|
|||
last += s;
|
||||
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) {
|
||||
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 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">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/R"
|
||||
android:id="@+id/EditText_R"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
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>
|
||||
<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="hello_world">你好,世界!</string>
|
||||
<string name="next_page">下一页</string>
|
||||
<string name="two_way_page">单击下一页,长按上一页</string>
|
||||
<string name="test_str">测试文本</string>
|
||||
<string name="set_color">设置颜色</string>
|
||||
<string name="set">设置</string>
|
||||
<string name="setText">设置文本</string>
|
||||
<string name="kaculate">弱智计算器</string>
|
||||
<string name="Backspace">退格</string>
|
||||
<string name="hello_world" translatable="false">你好,世界!</string>
|
||||
<string name="next_page" translatable="false">下一页</string>
|
||||
<string name="two_way_page" translatable="false">单击下一页,长按上一页</string>
|
||||
<string name="test_str" translatable="false">测试文本</string>
|
||||
<string name="set_color" translatable="false">设置颜色</string>
|
||||
<string name="set" translatable="false">设置</string>
|
||||
<string name="setText" translatable="false">设置文本</string>
|
||||
<string name="kaculate" translatable="false">弱智计算器</string>
|
||||
<string name="Backspace" translatable="false">退格</string>
|
||||
<string name="todo_app_short_label">Open TODO</string>
|
||||
</resources>
|
|
@ -13,4 +13,8 @@
|
|||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</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>
|
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
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# 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.
|
||||
# This option should only be used with decoupled projects. For more details, visit
|
||||
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
||||
|
|
|
@ -9,6 +9,16 @@ appcompat = "1.6.1"
|
|||
material = "1.11.0"
|
||||
activity = "1.8.0"
|
||||
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]
|
||||
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" }
|
||||
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||
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]
|
||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||
|
|
Loading…
Reference in a new issue