Minimal working prototype
This commit is contained in:
parent
de2bdf4b91
commit
5f31ce23d0
29 changed files with 668 additions and 451 deletions
|
@ -1,82 +0,0 @@
|
|||
/**
|
||||
* Copyright 2024 pegasko
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package art.pegasko.yeeemp;
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.provider.CalendarContract;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import art.pegasko.yeeemp.base.Event;
|
||||
import art.pegasko.yeeemp.base.Queue;
|
||||
import art.pegasko.yeeemp.base.Tag;
|
||||
import art.pegasko.yeeemp.impl.QueueMakerImpl;
|
||||
import art.pegasko.yeeemp.impl.TagMakerImpl;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DBImplTest {
|
||||
|
||||
private SQLiteDatabase db;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
db = SQLiteDatabase.create(null);
|
||||
// db = SQLiteDatabase.openDatabase("test.db", SQLiteDatabase.OpenParams);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueueMakerImpl() {
|
||||
SQLiteDatabase db = SQLiteDatabase.create(null);
|
||||
QueueMakerImpl queueMaker = new QueueMakerImpl(db);
|
||||
|
||||
Queue q = queueMaker.create();
|
||||
|
||||
// check initial ID
|
||||
assert q.getId() == 0;
|
||||
|
||||
// check null name
|
||||
assert q.getName() == null;
|
||||
|
||||
// check no events
|
||||
Event[] events = q.getEvents();
|
||||
assert events != null;
|
||||
assert events.length == 0;
|
||||
|
||||
// check no tags
|
||||
Tag[] tags = q.getGlobalTags();
|
||||
assert tags != null;
|
||||
assert tags.length == 0;
|
||||
|
||||
// Check name set
|
||||
q.setName("aboba");
|
||||
assert q.getName() == "aboba";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTagMakerImpl() {
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/**
|
||||
* Copyright 2024 pegasko
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package art.pegasko.yeeemp;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("art.pegasko.yeeemp", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -18,12 +18,20 @@ package art.pegasko.yeeemp.base;
|
|||
|
||||
public interface Event {
|
||||
int getId();
|
||||
|
||||
long getTimestamp();
|
||||
|
||||
void setTimestamp(long timestamp);
|
||||
|
||||
String getComment();
|
||||
|
||||
void setComment(String comment);
|
||||
|
||||
void addTag(Tag tag);
|
||||
|
||||
void removeTag(Tag tag);
|
||||
|
||||
void removeTags();
|
||||
|
||||
Tag[] getTags();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ package art.pegasko.yeeemp.base;
|
|||
|
||||
public interface EventMaker {
|
||||
Event create();
|
||||
|
||||
void delete(Event event);
|
||||
|
||||
Event getById(int id);
|
||||
}
|
||||
|
|
|
@ -18,11 +18,18 @@ package art.pegasko.yeeemp.base;
|
|||
|
||||
public interface Queue {
|
||||
int getId();
|
||||
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
|
||||
Event[] getEvents();
|
||||
|
||||
int getEventCount();
|
||||
|
||||
void addEvent(Event event);
|
||||
|
||||
void removeEvent(Event event);
|
||||
Tag[] getGlobalTags();
|
||||
|
||||
TagStat[] getGlobalTags();
|
||||
}
|
||||
|
|
|
@ -18,7 +18,10 @@ package art.pegasko.yeeemp.base;
|
|||
|
||||
public interface QueueMaker {
|
||||
Queue getById(int id);
|
||||
|
||||
Queue create();
|
||||
|
||||
void delete(Queue queue);
|
||||
|
||||
Queue[] list();
|
||||
}
|
||||
|
|
|
@ -18,5 +18,6 @@ package art.pegasko.yeeemp.base;
|
|||
|
||||
public interface Tag {
|
||||
int getId();
|
||||
|
||||
String getName();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,5 @@
|
|||
package art.pegasko.yeeemp.base;
|
||||
|
||||
public interface TagMaker {
|
||||
/** Get or Create distinct name Tag in Queue */
|
||||
Tag getOrCreateInQueue(Queue queue, String name);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ public abstract class Wrapper {
|
|||
}
|
||||
|
||||
public abstract QueueMaker queueMaker();
|
||||
|
||||
public abstract EventMaker eventMaker();
|
||||
|
||||
public abstract TagMaker tagMaker();
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ public class DBWrapper extends Wrapper {
|
|||
try {
|
||||
new File(context.getFilesDir(), DB_PATH).delete();
|
||||
} catch (Exception e) {
|
||||
Log.wtf(DBWrapper.TAG, e);
|
||||
Log.wtf(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,14 +46,8 @@ public class EventImpl implements Event {
|
|||
@Override
|
||||
public long getTimestamp() {
|
||||
synchronized (this.db) {
|
||||
Cursor cursor = db.query(
|
||||
"event",
|
||||
new String[] { "timestamp" },
|
||||
"id = ?",
|
||||
new String[] { Integer.toString(this.getId()) },
|
||||
null,
|
||||
null,
|
||||
null
|
||||
Cursor cursor = db.query("event", new String[] { "timestamp" }, "id = ?",
|
||||
new String[] { Integer.toString(this.getId()) }, null, null, null
|
||||
);
|
||||
|
||||
if (Utils.findResult(cursor)) {
|
||||
|
@ -69,26 +63,15 @@ public class EventImpl implements Event {
|
|||
synchronized (this.db) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("timestamp", timestamp);
|
||||
db.update(
|
||||
"event",
|
||||
cv,
|
||||
"id = ?",
|
||||
new String[] { Integer.toString(this.getId()) }
|
||||
);
|
||||
db.update("event", cv, "id = ?", new String[] { Integer.toString(this.getId()) });
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
synchronized (this.db) {
|
||||
Cursor cursor = db.query(
|
||||
"event",
|
||||
new String[] { "comment" },
|
||||
"id = ?",
|
||||
new String[] { Integer.toString(this.getId()) },
|
||||
null,
|
||||
null,
|
||||
null
|
||||
Cursor cursor = db.query("event", new String[] { "comment" }, "id = ?",
|
||||
new String[] { Integer.toString(this.getId()) }, null, null, null
|
||||
);
|
||||
|
||||
if (Utils.findResult(cursor)) {
|
||||
|
@ -104,27 +87,18 @@ public class EventImpl implements Event {
|
|||
synchronized (this.db) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("comment", comment);
|
||||
db.update(
|
||||
"event",
|
||||
cv,
|
||||
"id = ?",
|
||||
new String[] { Integer.toString(this.getId()) }
|
||||
);
|
||||
db.update("event", cv, "id = ?", new String[] { Integer.toString(this.getId()) });
|
||||
}
|
||||
}
|
||||
|
||||
/** !synchronized */
|
||||
/**
|
||||
* !synchronized
|
||||
*/
|
||||
protected boolean hasTag(Tag tag) {
|
||||
synchronized (this.db) {
|
||||
Cursor cursor = db.query(
|
||||
"event_tag",
|
||||
new String[] { "1" },
|
||||
"event_id = ? AND tag_id = ?",
|
||||
new String[] { Integer.toString(this.getId()), Integer.toString(tag.getId()) },
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
Cursor cursor = db.query("event_tag", new String[] { "1" }, "event_id = ? AND tag_id = ?", new String[] {
|
||||
Integer.toString(this.getId()), Integer.toString(tag.getId())
|
||||
}, null, null, null);
|
||||
|
||||
return Utils.findResult(cursor);
|
||||
}
|
||||
|
@ -133,11 +107,9 @@ public class EventImpl implements Event {
|
|||
@Override
|
||||
public void addTag(Tag tag) {
|
||||
synchronized (this.db) {
|
||||
if (tag == null)
|
||||
return;
|
||||
if (tag == null) return;
|
||||
|
||||
if (this.hasTag(tag))
|
||||
return;
|
||||
if (this.hasTag(tag)) return;
|
||||
|
||||
try {
|
||||
ContentValues cv = new ContentValues();
|
||||
|
@ -153,18 +125,14 @@ public class EventImpl implements Event {
|
|||
@Override
|
||||
public void removeTag(Tag tag) {
|
||||
synchronized (this.db) {
|
||||
if (tag == null)
|
||||
return;
|
||||
if (tag == null) return;
|
||||
|
||||
if (!this.hasTag(tag))
|
||||
return;
|
||||
if (!this.hasTag(tag)) return;
|
||||
|
||||
try {
|
||||
db.delete(
|
||||
"event_tag",
|
||||
"event_id = ? AND tag_id = ?",
|
||||
new String[] { Integer.toString(this.getId()), Integer.toString(tag.getId()) }
|
||||
);
|
||||
db.delete("event_tag", "event_id = ? AND tag_id = ?", new String[] {
|
||||
Integer.toString(this.getId()), Integer.toString(tag.getId())
|
||||
});
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
}
|
||||
|
@ -175,11 +143,7 @@ public class EventImpl implements Event {
|
|||
public void removeTags() {
|
||||
synchronized (this.db) {
|
||||
try {
|
||||
db.delete(
|
||||
"event_tag",
|
||||
"event_id = ?",
|
||||
new String[] { Integer.toString(this.getId()) }
|
||||
);
|
||||
db.delete("event_tag", "event_id = ?", new String[] { Integer.toString(this.getId()) });
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
}
|
||||
|
@ -189,14 +153,8 @@ public class EventImpl implements Event {
|
|||
@Override
|
||||
public Tag[] getTags() {
|
||||
synchronized (this.db) {
|
||||
Cursor cursor = db.query(
|
||||
"event_tag",
|
||||
new String[] { "tag_id" },
|
||||
"event_id = ?",
|
||||
new String[] { Integer.toString(this.getId()) },
|
||||
null,
|
||||
null,
|
||||
null
|
||||
Cursor cursor = db.query("event_tag", new String[] { "tag_id" }, "event_id = ?",
|
||||
new String[] { Integer.toString(this.getId()) }, null, null, "tag_id desc"
|
||||
);
|
||||
|
||||
if (cursor == null) {
|
||||
|
@ -207,10 +165,7 @@ public class EventImpl implements Event {
|
|||
|
||||
int index = 0;
|
||||
while (cursor.moveToNext()) {
|
||||
tags[index++] = new TagImpl(
|
||||
this.db,
|
||||
cursor.getInt(0)
|
||||
);
|
||||
tags[index++] = new TagImpl(this.db, cursor.getInt(0));
|
||||
}
|
||||
|
||||
return tags;
|
||||
|
|
|
@ -49,8 +49,7 @@ public class EventMakerImpl implements EventMaker {
|
|||
null
|
||||
);
|
||||
|
||||
if (Utils.findResult(cursor))
|
||||
return new EventImpl(this.db, id);
|
||||
if (Utils.findResult(cursor)) return new EventImpl(this.db, id);
|
||||
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
|
@ -67,10 +66,7 @@ public class EventMakerImpl implements EventMaker {
|
|||
ContentValues cv = new ContentValues();
|
||||
cv.put("id", (Integer) null);
|
||||
long rowId = db.insertOrThrow("event", null, cv);
|
||||
return new EventImpl(
|
||||
this.db,
|
||||
(int) rowId
|
||||
);
|
||||
return new EventImpl(this.db, (int) rowId);
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
}
|
||||
|
@ -84,25 +80,13 @@ public class EventMakerImpl implements EventMaker {
|
|||
synchronized (this.db) {
|
||||
try {
|
||||
// Delete queue <-> event
|
||||
db.delete(
|
||||
"queue_event",
|
||||
"event_id = ?",
|
||||
new String[] { Integer.toString(event.getId()) }
|
||||
);
|
||||
db.delete("queue_event", "event_id = ?", new String[] { Integer.toString(event.getId()) });
|
||||
|
||||
// Delete event <-> tag
|
||||
db.delete(
|
||||
"event_tag",
|
||||
"event_id = ?",
|
||||
new String[] { Integer.toString(event.getId()) }
|
||||
);
|
||||
db.delete("event_tag", "event_id = ?", new String[] { Integer.toString(event.getId()) });
|
||||
|
||||
// Delete event
|
||||
db.delete(
|
||||
"event",
|
||||
"id = ?",
|
||||
new String[] { Integer.toString(event.getId()) }
|
||||
);
|
||||
db.delete("event", "id = ?", new String[] { Integer.toString(event.getId()) });
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import androidx.annotation.NonNull;
|
|||
import art.pegasko.yeeemp.base.Event;
|
||||
import art.pegasko.yeeemp.base.Queue;
|
||||
import art.pegasko.yeeemp.base.Tag;
|
||||
import art.pegasko.yeeemp.base.TagStat;
|
||||
import kotlin.NotImplementedError;
|
||||
|
||||
public class QueueImpl implements Queue {
|
||||
|
@ -131,7 +132,9 @@ public class QueueImpl implements Queue {
|
|||
}
|
||||
}
|
||||
|
||||
/** !synchronized */
|
||||
/**
|
||||
* !synchronized
|
||||
*/
|
||||
protected boolean hasEvent(Event event) {
|
||||
synchronized (this.db) {
|
||||
Cursor cursor = db.query(
|
||||
|
@ -190,30 +193,60 @@ public class QueueImpl implements Queue {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Tag[] getGlobalTags() {
|
||||
public TagStat[] getGlobalTags() {
|
||||
synchronized (this.db) {
|
||||
Cursor cursor = db.query(
|
||||
"tag",
|
||||
new String[] { "id" },
|
||||
"queue_id = ?",
|
||||
new String[] { Integer.toString(this.getId()) },
|
||||
null,
|
||||
null,
|
||||
null
|
||||
Cursor cursor = db.rawQuery(
|
||||
"select" +
|
||||
" tag_id,\n" +
|
||||
" count(*) as cnt\n" +
|
||||
"from (\n" +
|
||||
" select\n" +
|
||||
" event_id,\n" +
|
||||
" tag_id\n" +
|
||||
" from (\n" +
|
||||
" select\n" +
|
||||
" event_tag.event_id as event_id,\n" +
|
||||
" event_tag.tag_id as tag_id\n" +
|
||||
" from (\n" +
|
||||
" select\n" +
|
||||
" event_id\n" +
|
||||
" from\n" +
|
||||
" queue_event\n" +
|
||||
" where\n" +
|
||||
" queue_id = ?\n" +
|
||||
" ) as queue_event_temp\n" +
|
||||
" inner join\n" +
|
||||
" event_tag\n" +
|
||||
" on\n" +
|
||||
" (event_tag.event_id = queue_event_temp.event_id)\n" +
|
||||
" )\n" +
|
||||
" group by\n" +
|
||||
" event_id,\n" +
|
||||
" tag_id\n" +
|
||||
")\n" +
|
||||
"group by\n" +
|
||||
" tag_id\n" +
|
||||
"order by\n" +
|
||||
" cnt desc",
|
||||
new String[] { Integer.toString(this.getId()) }
|
||||
);
|
||||
|
||||
if (cursor == null) {
|
||||
return new Tag[0];
|
||||
return new TagStat[0];
|
||||
}
|
||||
|
||||
Tag[] tags = new Tag[cursor.getCount()];
|
||||
TagStat[] tags = new TagStat[cursor.getCount()];
|
||||
|
||||
int index = 0;
|
||||
while (cursor.moveToNext()) {
|
||||
tags[index++] = new TagImpl(
|
||||
TagStat tagStat = new TagStat();
|
||||
tags[index++] = tagStat;
|
||||
|
||||
tagStat.tag = new TagImpl(
|
||||
this.db,
|
||||
cursor.getInt(0)
|
||||
);
|
||||
tagStat.count = cursor.getInt(1);
|
||||
}
|
||||
|
||||
return tags;
|
||||
|
|
|
@ -50,11 +50,16 @@ public class QueueMakerImpl implements QueueMaker {
|
|||
null
|
||||
);
|
||||
|
||||
if (Utils.findResult(cursor))
|
||||
return new QueueImpl(this.db, id);
|
||||
if (Utils.findResult(cursor)) return new QueueImpl(
|
||||
this.db,
|
||||
id
|
||||
);
|
||||
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
Log.wtf(
|
||||
TAG,
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -66,14 +71,24 @@ public class QueueMakerImpl implements QueueMaker {
|
|||
synchronized (this.db) {
|
||||
try {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("id", (Integer) null);
|
||||
long rowId = db.insertOrThrow("queue", null, cv);
|
||||
cv.put(
|
||||
"id",
|
||||
(Integer) null
|
||||
);
|
||||
long rowId = db.insertOrThrow(
|
||||
"queue",
|
||||
null,
|
||||
cv
|
||||
);
|
||||
return new QueueImpl(
|
||||
this.db,
|
||||
(int) rowId
|
||||
);
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
Log.wtf(
|
||||
TAG,
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -117,7 +132,7 @@ public class QueueMakerImpl implements QueueMaker {
|
|||
|
||||
// Drop events
|
||||
try {
|
||||
for (Event event: queue.getEvents()) {
|
||||
for (Event event : queue.getEvents()) {
|
||||
db.delete(
|
||||
"event",
|
||||
"id = ?",
|
||||
|
@ -125,7 +140,10 @@ public class QueueMakerImpl implements QueueMaker {
|
|||
);
|
||||
}
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
Log.wtf(
|
||||
TAG,
|
||||
e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -137,7 +155,10 @@ public class QueueMakerImpl implements QueueMaker {
|
|||
new String[] { Integer.toString(queue.getId()) }
|
||||
);
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
Log.wtf(
|
||||
TAG,
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
// Drop queue
|
||||
|
@ -148,7 +169,10 @@ public class QueueMakerImpl implements QueueMaker {
|
|||
new String[] { Integer.toString(queue.getId()) }
|
||||
);
|
||||
} catch (SQLiteException e) {
|
||||
Log.wtf(TAG, e);
|
||||
Log.wtf(
|
||||
TAG,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
|
||||
public class Utils {
|
||||
public static boolean findResult(Cursor cursor) {
|
||||
if (cursor == null)
|
||||
return false;
|
||||
if (cursor == null) return false;
|
||||
cursor.moveToFirst();
|
||||
return cursor.getCount() != 0;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package art.pegasko.yeeemp.okand.base;
|
||||
package art.pegasko.yeeemp.okand.base;
|
||||
|
||||
public abstract class Potato {
|
||||
private static Potato instance;
|
||||
|
@ -28,6 +28,8 @@ public abstract class Potato {
|
|||
}
|
||||
|
||||
public abstract Event getById(int id);
|
||||
|
||||
public abstract void save(Event container);
|
||||
|
||||
public abstract void delete(Event container);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package art.pegasko.yeeemp.okand.impl;
|
||||
package art.pegasko.yeeemp.okand.impl;
|
||||
|
||||
import art.pegasko.yeeemp.okand.base.Event;
|
||||
import art.pegasko.yeeemp.okand.base.Potato;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package art.pegasko.yeeemp.ui.activity;
|
||||
package art.pegasko.yeeemp.ui.activity;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
|
@ -24,9 +24,14 @@ import android.content.Intent;
|
|||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.TimeUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.MultiAutoCompleteTextView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
|
@ -39,12 +44,16 @@ import java.time.LocalDateTime;
|
|||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import art.pegasko.yeeemp.base.Queue;
|
||||
import art.pegasko.yeeemp.base.Tag;
|
||||
import art.pegasko.yeeemp.base.TagStat;
|
||||
import art.pegasko.yeeemp.databinding.ActivityEventEditBinding;
|
||||
|
||||
import art.pegasko.yeeemp.R;
|
||||
|
@ -59,8 +68,11 @@ public class EventEditActivity extends AppCompatActivity {
|
|||
private Event event;
|
||||
private EventContainer eventContainer;
|
||||
private ActivityEventEditBinding binding;
|
||||
private TagStat[] tagStat;
|
||||
|
||||
/** Store values for edited or new event */
|
||||
/**
|
||||
* Store values for edited or new event
|
||||
*/
|
||||
private static class EventContainer {
|
||||
public String comment;
|
||||
public long timestamp;
|
||||
|
@ -82,21 +94,33 @@ public class EventEditActivity extends AppCompatActivity {
|
|||
// Get Queue ID from Intent
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras == null) {
|
||||
Log.e(TAG, "Missing Intent arguments (queue_id)");
|
||||
Log.e(
|
||||
TAG,
|
||||
"Missing Intent arguments (queue_id)"
|
||||
);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
int queue_id = extras.getInt("queue_id", -1);
|
||||
int queue_id = extras.getInt(
|
||||
"queue_id",
|
||||
-1
|
||||
);
|
||||
if (queue_id == -1) {
|
||||
Log.e(TAG, "Missing Intent arguments (queue_id)");
|
||||
Log.e(
|
||||
TAG,
|
||||
"Missing Intent arguments (queue_id)"
|
||||
);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
queue = Wrapper.getQueueMaker().getById(queue_id);
|
||||
if (queue == null) {
|
||||
Log.e(TAG, "Missing Intent arguments (queue_id)");
|
||||
Log.e(
|
||||
TAG,
|
||||
"Missing Intent arguments (queue_id)"
|
||||
);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
@ -107,12 +131,15 @@ public class EventEditActivity extends AppCompatActivity {
|
|||
// Get Event ID from Intent (optional)
|
||||
extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
int event_id = extras.getInt("event_id", -1);
|
||||
int event_id = extras.getInt(
|
||||
"event_id",
|
||||
-1
|
||||
);
|
||||
if (event_id != -1) {
|
||||
this.event = Wrapper.getEventMaker().getById(event_id);
|
||||
this.eventContainer.timestamp = this.event.getTimestamp();
|
||||
this.eventContainer.comment = this.event.getComment();
|
||||
for (Tag tag: this.event.getTags()) {
|
||||
for (Tag tag : this.event.getTags()) {
|
||||
this.eventContainer.tags.add(tag.getName());
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +148,8 @@ public class EventEditActivity extends AppCompatActivity {
|
|||
binding = ActivityEventEditBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
setSupportActionBar(binding.toolbar);
|
||||
getSupportActionBar().setTitle(getSupportActionBar().getTitle() + " / " + (event == null ? "Create" : "Edit") + " Event");
|
||||
getSupportActionBar().setTitle(
|
||||
getSupportActionBar().getTitle() + " / " + (event == null ? "Create" : "Edit") + " Event");
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||
|
||||
|
@ -131,6 +159,17 @@ public class EventEditActivity extends AppCompatActivity {
|
|||
if (this.eventContainer.comment != null)
|
||||
binding.eventEditContent.eventEditComment.setText(this.eventContainer.comment);
|
||||
|
||||
/* Comment Listeners */
|
||||
|
||||
// Request focus on click
|
||||
this.binding.eventEditContent.eventEditContainerComment.setOnClickListener((View view) -> {
|
||||
this.binding.eventEditContent.eventEditComment.requestFocus();
|
||||
this.binding.eventEditContent.eventEditComment.setSelection(
|
||||
EventEditActivity.this.binding.eventEditContent.eventEditComment.getText().length());
|
||||
});
|
||||
|
||||
/* Timestamp Listeners */
|
||||
|
||||
binding.eventEditContent.eventEditContainerTimestamp.setOnClickListener((View view) -> {
|
||||
Date date;
|
||||
if (this.eventContainer.timestamp != 0)
|
||||
|
@ -153,21 +192,34 @@ public class EventEditActivity extends AppCompatActivity {
|
|||
newDate.setSeconds(0);
|
||||
|
||||
this.eventContainer.timestamp = newDate.getTime();
|
||||
binding.eventEditContent.eventEditTimestamp.setText(Utils.formatTs(this.eventContainer.timestamp));
|
||||
binding.eventEditContent.eventEditTimestamp.setText(
|
||||
Utils.formatTs(this.eventContainer.timestamp));
|
||||
},
|
||||
date.getHours(), date.getMinutes(), true
|
||||
date.getHours(),
|
||||
date.getMinutes(),
|
||||
true
|
||||
);
|
||||
timePickerDialog.show();
|
||||
}, date.getYear() + 1900, date.getMonth(), date.getDate()
|
||||
},
|
||||
date.getYear() + 1900,
|
||||
date.getMonth(),
|
||||
date.getDate()
|
||||
);
|
||||
datePickerDialog.show();
|
||||
});
|
||||
|
||||
/* FAB Listeners */
|
||||
binding.fab.setOnLongClickListener((View view) -> {
|
||||
Snackbar.make(view, "Save Event", Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(
|
||||
view,
|
||||
"Save Event",
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAnchorView(R.id.fab)
|
||||
.setAction("Action", null).show();
|
||||
.setAction(
|
||||
"Action",
|
||||
null
|
||||
).show();
|
||||
|
||||
return true;
|
||||
});
|
||||
|
@ -175,20 +227,75 @@ public class EventEditActivity extends AppCompatActivity {
|
|||
// Finalize values
|
||||
this.eventContainer.comment = this.binding.eventEditContent.eventEditComment.getText().toString().trim();
|
||||
|
||||
String[] tags = EventEditActivity.this.binding.eventEditContent.eventEditTags.getText().toString().split(
|
||||
",");
|
||||
tags = Utils.orderedDeduplicateIgnoreCaseAndTrim(tags);
|
||||
this.eventContainer.tags.clear();
|
||||
for (String tag : tags) {
|
||||
this.eventContainer.tags.add(tag);
|
||||
}
|
||||
|
||||
// Fill event
|
||||
boolean hasEvent = this.event != null;
|
||||
if (this.event == null)
|
||||
this.event = Wrapper.getEventMaker().create();
|
||||
|
||||
this.event.setTimestamp(this.eventContainer.timestamp);
|
||||
this.event.removeTags();
|
||||
for (String tag: this.eventContainer.tags) {
|
||||
this.event.addTag(Wrapper.getTagMaker().getOrCreateInQueue(this.queue, tag));
|
||||
for (String tag : this.eventContainer.tags) {
|
||||
this.event.addTag(Wrapper.getTagMaker().getOrCreateInQueue(
|
||||
this.queue,
|
||||
tag
|
||||
));
|
||||
}
|
||||
this.event.setComment(this.eventContainer.comment);
|
||||
|
||||
if (!hasEvent) {
|
||||
this.queue.addEvent(event);
|
||||
}
|
||||
|
||||
finish();
|
||||
});
|
||||
|
||||
/* Tags list + input */
|
||||
this.tagStat = this.queue.getGlobalTags();
|
||||
|
||||
ArrayAdapter<TagStat> adapter = new EventEditTagsAdapter(
|
||||
this,
|
||||
android.R.layout.simple_dropdown_item_1line,
|
||||
0,
|
||||
new ArrayList<>(Arrays.asList(this.tagStat))
|
||||
);
|
||||
this.binding.eventEditContent.eventEditTags.setAdapter(adapter);
|
||||
this.binding.eventEditContent.eventEditTags.setThreshold(1);
|
||||
this.binding.eventEditContent.eventEditTags.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
|
||||
this.binding.eventEditContent.eventEditTags.setOnItemClickListener((parent, view, position, id) -> {
|
||||
String[] tags = EventEditActivity.this.binding.eventEditContent.eventEditTags.getText().toString().split(
|
||||
",");
|
||||
tags = Utils.orderedDeduplicateIgnoreCaseAndTrim(tags);
|
||||
|
||||
EventEditActivity.this.binding.eventEditContent.eventEditTags.setText(String.join(
|
||||
", ",
|
||||
tags
|
||||
));
|
||||
EventEditActivity.this.binding.eventEditContent.eventEditTags.setSelection(
|
||||
EventEditActivity.this.binding.eventEditContent.eventEditTags.getText().length());
|
||||
});
|
||||
|
||||
// Request focus on click
|
||||
this.binding.eventEditContent.eventEditContainerTags.setOnClickListener((View view) -> {
|
||||
this.binding.eventEditContent.eventEditTags.requestFocus();
|
||||
this.binding.eventEditContent.eventEditTags.setSelection(
|
||||
EventEditActivity.this.binding.eventEditContent.eventEditTags.getText().length());
|
||||
});
|
||||
|
||||
// Fill
|
||||
this.binding.eventEditContent.eventEditTags.setText(String.join(
|
||||
", ",
|
||||
this.eventContainer.tags
|
||||
));
|
||||
this.binding.eventEditContent.eventEditTags.setSelection(
|
||||
EventEditActivity.this.binding.eventEditContent.eventEditTags.getText().length());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* Copyright 2024 pegasko
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package art.pegasko.yeeemp.ui.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Filter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import art.pegasko.yeeemp.base.TagStat;
|
||||
|
||||
public class EventEditTagsAdapter extends ArrayAdapter<TagStat> {
|
||||
public static final String TAG = EventEditTagsAdapter.class.getSimpleName();
|
||||
|
||||
private ArrayList<TagStat> items;
|
||||
private ArrayList<TagStat> itemsAll;
|
||||
private ArrayList<TagStat> suggestions;
|
||||
private int viewResourceId;
|
||||
private int viewFieldId;
|
||||
private LayoutInflater inflater;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EventEditTagsAdapter(Context context, int viewResourceId, int viewFieldId, ArrayList<TagStat> items) {
|
||||
super(context, viewResourceId, items);
|
||||
this.items = items;
|
||||
this.itemsAll = (ArrayList<TagStat>) items.clone();
|
||||
this.suggestions = new ArrayList<TagStat>();
|
||||
this.viewResourceId = viewResourceId;
|
||||
this.viewFieldId = viewFieldId;
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) convertView = inflater.inflate(this.viewResourceId, parent, false);
|
||||
|
||||
TextView text;
|
||||
try {
|
||||
if (this.viewFieldId == 0) {
|
||||
text = (TextView) convertView;
|
||||
} else {
|
||||
text = convertView.findViewById(this.viewFieldId);
|
||||
}
|
||||
|
||||
if (text == null) {
|
||||
Log.e(TAG, "Failed attach text to view");
|
||||
throw new RuntimeException("Failed attach text to view");
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
Log.e(TAG, "You must supply a resource ID for a TextView");
|
||||
throw new RuntimeException("You must supply a resource ID for a TextView");
|
||||
}
|
||||
|
||||
text.setText(items.get(position).tag.getName() + " (" + Integer.toString(items.get(position).count) + ")");
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
return nameFilter;
|
||||
}
|
||||
|
||||
Filter nameFilter = new Filter() {
|
||||
public String convertResultToString(Object resultValue) {
|
||||
String str = ((TagStat) (resultValue)).tag.getName();
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FilterResults performFiltering(CharSequence constraint) {
|
||||
if (constraint != null) {
|
||||
suggestions.clear();
|
||||
for (TagStat product : itemsAll) {
|
||||
if (product.tag.getName().contains(constraint.toString().toLowerCase())) {
|
||||
suggestions.add(product);
|
||||
}
|
||||
}
|
||||
FilterResults filterResults = new FilterResults();
|
||||
filterResults.values = suggestions;
|
||||
filterResults.count = suggestions.size();
|
||||
return filterResults;
|
||||
} else {
|
||||
return new FilterResults();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||
@SuppressWarnings("unchecked") ArrayList<TagStat> filteredList = (ArrayList<TagStat>) results.values;
|
||||
if (results != null && results.count > 0) {
|
||||
clear();
|
||||
for (TagStat c : filteredList) {
|
||||
add(c);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -63,21 +63,33 @@ public class EventListActivity extends AppCompatActivity {
|
|||
// Get Queue ID from Intent
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras == null) {
|
||||
Log.e(TAG, "Missing Intent arguments (queue_id)");
|
||||
Log.e(
|
||||
TAG,
|
||||
"Missing Intent arguments (queue_id)"
|
||||
);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
int queue_id = extras.getInt("queue_id", -1);
|
||||
int queue_id = extras.getInt(
|
||||
"queue_id",
|
||||
-1
|
||||
);
|
||||
if (queue_id == -1) {
|
||||
Log.e(TAG, "Missing Intent arguments (queue_id)");
|
||||
Log.e(
|
||||
TAG,
|
||||
"Missing Intent arguments (queue_id)"
|
||||
);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
queue = Wrapper.getQueueMaker().getById(queue_id);
|
||||
if (queue == null) {
|
||||
Log.e(TAG, "Missing Intent arguments (queue_id)");
|
||||
Log.e(
|
||||
TAG,
|
||||
"Missing Intent arguments (queue_id)"
|
||||
);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
@ -116,31 +128,33 @@ public class EventListActivity extends AppCompatActivity {
|
|||
|
||||
/* FAB Listeners */
|
||||
binding.fab.setOnLongClickListener((View view) -> {
|
||||
Snackbar.make(view, "Create Event", Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(
|
||||
view,
|
||||
"Create Event",
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAnchorView(R.id.fab)
|
||||
.setAction("Action", null).show();
|
||||
.setAction(
|
||||
"Action",
|
||||
null
|
||||
).show();
|
||||
|
||||
return true;
|
||||
});
|
||||
binding.fab.setOnClickListener(view -> {
|
||||
Bundle extra = new Bundle();
|
||||
extra.putInt("queue_id", this.queue.getId());
|
||||
extra.putInt(
|
||||
"queue_id",
|
||||
this.queue.getId()
|
||||
);
|
||||
|
||||
Intent intent = new Intent(view.getContext(), EventEditActivity.class);
|
||||
Intent intent = new Intent(
|
||||
view.getContext(),
|
||||
EventEditActivity.class
|
||||
);
|
||||
intent.putExtras(extra);
|
||||
|
||||
view.getContext().startActivity(intent);
|
||||
|
||||
// Log.w(TAG, "TODO: Open editor");
|
||||
//
|
||||
// Event event = Wrapper.getEventMaker().create();
|
||||
// event.setTimestamp(System.currentTimeMillis());
|
||||
// event.setComment("Lobster number " + System.currentTimeMillis());
|
||||
// queue.addEvent(event);
|
||||
//
|
||||
// Log.w(TAG, "Create: " + event.toString() + " in " + queue);
|
||||
|
||||
// updateList();
|
||||
});
|
||||
|
||||
/* Fill lists */
|
||||
|
|
|
@ -59,7 +59,11 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
|
|||
View view = (
|
||||
LayoutInflater
|
||||
.from(viewGroup.getContext())
|
||||
.inflate(R.layout.event_list_item, viewGroup, false)
|
||||
.inflate(
|
||||
R.layout.event_list_item,
|
||||
viewGroup,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return new ViewHolder(view);
|
||||
|
@ -69,12 +73,15 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
|
|||
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
|
||||
viewHolder.getBinding().eventListItemTags.removeAllViews();
|
||||
Tag[] tags = this.events[position].getTags();
|
||||
Log.w(TAG, "Tags: " + tags.length);
|
||||
for (Tag tag: tags) {
|
||||
for (Tag tag : tags) {
|
||||
TextView tagView = (TextView) (
|
||||
LayoutInflater
|
||||
.from(viewHolder.getBinding().getRoot().getContext())
|
||||
.inflate(R.layout.event_list_item_tag, null, false)
|
||||
.inflate(
|
||||
R.layout.event_list_item_tag,
|
||||
null,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
tagView.setText(tag.getName());
|
||||
|
@ -87,22 +94,37 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
|
|||
if (comment != null && !comment.isEmpty()) {
|
||||
viewHolder.getBinding().eventListItemComment.setVisibility(View.VISIBLE);
|
||||
viewHolder.getBinding().eventListItemComment.setText(comment);
|
||||
} else {
|
||||
viewHolder.getBinding().eventListItemComment.setVisibility(View.GONE);
|
||||
viewHolder.getBinding().eventListItemComment.setText("");
|
||||
}
|
||||
|
||||
viewHolder.getBinding().eventListItemItem.setOnLongClickListener((View view) -> {
|
||||
PopupMenu popupMenu = new PopupMenu(view.getContext(), viewHolder.getBinding().eventListItemItem);
|
||||
popupMenu.getMenuInflater().inflate(R.menu.event_list_item_action_menu, popupMenu.getMenu());
|
||||
PopupMenu popupMenu = new PopupMenu(
|
||||
view.getContext(),
|
||||
viewHolder.getBinding().eventListItemItem
|
||||
);
|
||||
popupMenu.getMenuInflater().inflate(
|
||||
R.menu.event_list_item_action_menu,
|
||||
popupMenu.getMenu()
|
||||
);
|
||||
popupMenu.setOnMenuItemClickListener((MenuItem menuItem) -> {
|
||||
if (menuItem.getItemId() == R.id.event_list_item_action_menu_delete) {
|
||||
new AlertDialog.Builder(view.getContext())
|
||||
.setTitle("Delete event")
|
||||
.setMessage("Are you sure you want to delete this event?")
|
||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||
.setPositiveButton(
|
||||
android.R.string.yes,
|
||||
(dialog, which) -> {
|
||||
Wrapper.getEventMaker().delete(events[position]);
|
||||
|
||||
reloadItems();
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
}
|
||||
)
|
||||
.setNegativeButton(
|
||||
android.R.string.no,
|
||||
null
|
||||
)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.show();
|
||||
}
|
||||
|
@ -115,10 +137,19 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
|
|||
});
|
||||
viewHolder.getBinding().eventListItemItem.setOnClickListener((View view) -> {
|
||||
Bundle extra = new Bundle();
|
||||
extra.putInt("event_id", this.events[position].getId());
|
||||
extra.putInt("queue_id", this.queue.getId());
|
||||
extra.putInt(
|
||||
"event_id",
|
||||
this.events[position].getId()
|
||||
);
|
||||
extra.putInt(
|
||||
"queue_id",
|
||||
this.queue.getId()
|
||||
);
|
||||
|
||||
Intent intent = new Intent(view.getContext(), EventEditActivity.class);
|
||||
Intent intent = new Intent(
|
||||
view.getContext(),
|
||||
EventEditActivity.class
|
||||
);
|
||||
intent.putExtras(extra);
|
||||
|
||||
view.getContext().startActivity(intent);
|
||||
|
@ -147,19 +178,4 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
|
|||
this.events = this.queue.getEvents();
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
// public ScheduledFuture<?> scheduleDeleteAt(int position) {
|
||||
// ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
|
||||
// ScheduledFuture<?> future = scheduledExecutorService.schedule(() -> {
|
||||
// try {
|
||||
// Wrapper.getEventMaker().delete(this.events[position]);
|
||||
// } catch (Exception e) {
|
||||
// Log.wtf(TAG, e);
|
||||
// }
|
||||
// }, 5, TimeUnit.SECONDS);
|
||||
//
|
||||
// // Hide item from list
|
||||
//
|
||||
// return future;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package art.pegasko.yeeemp.ui.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.util.Log;
|
||||
|
@ -66,16 +68,20 @@ public class QueueListActivity extends AppCompatActivity {
|
|||
|
||||
/* FAB Listeners */
|
||||
binding.fab.setOnLongClickListener((View view) -> {
|
||||
Snackbar.make(view, "Create Queue", Snackbar.LENGTH_LONG)
|
||||
.setAnchorView(R.id.fab)
|
||||
.setAction("Action", null).show();
|
||||
Snackbar.make(
|
||||
view,
|
||||
"Create Queue",
|
||||
Snackbar.LENGTH_LONG
|
||||
).setAnchorView(R.id.fab).setAction(
|
||||
"Action",
|
||||
null
|
||||
).show();
|
||||
|
||||
return true;
|
||||
});
|
||||
binding.fab.setOnClickListener(view -> {
|
||||
Queue q = Wrapper.getQueueMaker().create();
|
||||
q.setName("New Queue");
|
||||
Log.w(TAG, "Create: " + q.toString());
|
||||
|
||||
updateList();
|
||||
});
|
||||
|
|
|
@ -50,7 +50,11 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
|
|||
View view = (
|
||||
LayoutInflater
|
||||
.from(viewGroup.getContext())
|
||||
.inflate(R.layout.queue_list_item, viewGroup, false)
|
||||
.inflate(
|
||||
R.layout.queue_list_item,
|
||||
viewGroup,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return new ViewHolder(view);
|
||||
|
@ -61,19 +65,31 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
|
|||
viewHolder.getBinding().queueListItemTitle.setText(queues[position].getName());
|
||||
|
||||
viewHolder.getBinding().queueListItemItem.setOnLongClickListener((View view) -> {
|
||||
PopupMenu popupMenu = new PopupMenu(view.getContext(), viewHolder.getBinding().queueListItemItem);
|
||||
popupMenu.getMenuInflater().inflate(R.menu.queue_list_item_action_menu, popupMenu.getMenu());
|
||||
PopupMenu popupMenu = new PopupMenu(
|
||||
view.getContext(),
|
||||
viewHolder.getBinding().queueListItemItem
|
||||
);
|
||||
popupMenu.getMenuInflater().inflate(
|
||||
R.menu.queue_list_item_action_menu,
|
||||
popupMenu.getMenu()
|
||||
);
|
||||
popupMenu.setOnMenuItemClickListener((MenuItem menuItem) -> {
|
||||
if (menuItem.getItemId() == R.id.queue_list_item_action_menu_delete) {
|
||||
new AlertDialog.Builder(view.getContext())
|
||||
.setTitle("Delete queue")
|
||||
.setMessage("Are you sure you want to delete this queue?")
|
||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||
.setPositiveButton(
|
||||
android.R.string.yes,
|
||||
(dialog, which) -> {
|
||||
Wrapper.getQueueMaker().delete(queues[position]);
|
||||
|
||||
reloadItems();
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
}
|
||||
)
|
||||
.setNegativeButton(
|
||||
android.R.string.no,
|
||||
null
|
||||
)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.show();
|
||||
} else if (menuItem.getItemId() == R.id.queue_list_item_action_menu_rename) {
|
||||
|
@ -85,13 +101,19 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
|
|||
input.setText(queues[position].getName());
|
||||
builder.setView(input);
|
||||
|
||||
builder.setPositiveButton("OK", (dialog, which) -> {
|
||||
builder.setPositiveButton(
|
||||
"OK",
|
||||
(dialog, which) -> {
|
||||
String name = input.getText().toString().trim();
|
||||
queues[position].setName(name);
|
||||
|
||||
reloadItems();
|
||||
});
|
||||
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
|
||||
}
|
||||
);
|
||||
builder.setNegativeButton(
|
||||
"Cancel",
|
||||
(dialog, which) -> dialog.cancel()
|
||||
);
|
||||
|
||||
builder.show();
|
||||
}
|
||||
|
@ -104,9 +126,15 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
|
|||
});
|
||||
viewHolder.getBinding().queueListItemItem.setOnClickListener((View view) -> {
|
||||
Bundle extra = new Bundle();
|
||||
extra.putInt("queue_id", queues[position].getId());
|
||||
extra.putInt(
|
||||
"queue_id",
|
||||
queues[position].getId()
|
||||
);
|
||||
|
||||
Intent intent = new Intent(view.getContext(), EventListActivity.class);
|
||||
Intent intent = new Intent(
|
||||
view.getContext(),
|
||||
EventListActivity.class
|
||||
);
|
||||
intent.putExtras(extra);
|
||||
|
||||
view.getContext().startActivity(intent);
|
||||
|
@ -115,35 +143,11 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
|
|||
viewHolder.getBinding().queueListItemStats.setText(Integer.toString(queues[position].getEventCount()));
|
||||
|
||||
viewHolder.getBinding().queueListItemPlus.setOnClickListener((View view) -> {
|
||||
Intent intent = new Intent(view.getContext(), EventEditActivity.class);
|
||||
Intent intent = new Intent(
|
||||
view.getContext(),
|
||||
EventEditActivity.class
|
||||
);
|
||||
view.getContext().startActivity(intent);
|
||||
|
||||
// Log.w(TAG, "TODO: Open editor");
|
||||
//
|
||||
// Event event = Wrapper.getEventMaker().create();
|
||||
// event.setTimestamp(System.currentTimeMillis());
|
||||
// event.setComment("Lobster number " + System.currentTimeMillis() + "\n" + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
|
||||
// queues[position].addEvent(event);
|
||||
//
|
||||
// Tag[] tags = new Tag[] {
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_cum"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_poo"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_fart"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_penis"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_dick"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_cock"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_zalupa"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_ololo"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_owo"),
|
||||
// Wrapper.getTagMaker().getOrCreateInQueue(queues[position], "tag_" + position + "_uwu"),
|
||||
// };
|
||||
// for (Tag tag: tags) {
|
||||
// event.addTag(tag);
|
||||
// }
|
||||
//
|
||||
// Log.w(TAG, "Create: " + event.toString() + " in " + queues[position]);
|
||||
//
|
||||
// reloadItems();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
package art.pegasko.yeeemp.ui.activity;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Utils {
|
||||
public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
@ -26,4 +29,24 @@ public class Utils {
|
|||
SimpleDateFormat sdf = new SimpleDateFormat(Utils.DATE_FORMAT);
|
||||
return sdf.format(timestamp);
|
||||
}
|
||||
|
||||
public static String[] orderedDeduplicateIgnoreCaseAndTrim(String[] items) {
|
||||
Set<String> duplicates = new HashSet<String>();
|
||||
ArrayList<String> reverseOrderedItems = new ArrayList<String>();
|
||||
|
||||
for (int index = items.length - 1; index >= 0; --index) {
|
||||
String item = items[index].toLowerCase().trim();
|
||||
if (!duplicates.contains(item) && !item.isEmpty()) {
|
||||
duplicates.add(item);
|
||||
reverseOrderedItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
String[] finalItems = new String[reverseOrderedItems.size()];
|
||||
for (int index = 0; index < finalItems.length; ++index) {
|
||||
finalItems[finalItems.length - index - 1] = reverseOrderedItems.get(index);
|
||||
}
|
||||
|
||||
return finalItems;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,27 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/pegasko_black"
|
||||
android:orientation="vertical"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/pegasko_black"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/event_edit_container_timestamp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="@dimen/event_edit_box_margin"
|
||||
android:id="@+id/event_edit_container_timestamp"
|
||||
android:background="@drawable/box_red" >
|
||||
android:background="@drawable/box_red"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
|
@ -22,8 +33,8 @@
|
|||
android:layout_margin="@dimen/event_edit_hint_margin"
|
||||
android:paddingLeft="@dimen/event_edit_hint_padding_left"
|
||||
android:text="Time"
|
||||
android:textSize="@dimen/event_edit_hint_text"
|
||||
android:textColor="@color/pegasko_black"
|
||||
android:textSize="@dimen/event_edit_hint_text"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
|
@ -36,26 +47,26 @@
|
|||
android:padding="@dimen/event_edit_timestamp_padding"
|
||||
android:text="Timestamp"
|
||||
android:textColor="@color/pegasko_white"
|
||||
android:textSize="@dimen/event_edit_timestamp_text"/>
|
||||
android:textSize="@dimen/event_edit_timestamp_text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/event_edit_container_comment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="@dimen/event_edit_box_margin"
|
||||
android:background="@drawable/box_red" >
|
||||
android:background="@drawable/box_red"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/event_edit_hint_margin"
|
||||
android:paddingLeft="@dimen/event_edit_hint_padding_left"
|
||||
android:text="Comment"
|
||||
android:textSize="@dimen/event_edit_hint_text"
|
||||
android:textColor="@color/pegasko_black"
|
||||
android:textSize="@dimen/event_edit_hint_text"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<EditText
|
||||
|
@ -66,11 +77,11 @@
|
|||
android:background="@drawable/box_black"
|
||||
android:cursorVisible="true"
|
||||
android:gravity="start|left"
|
||||
android:hint="comment"
|
||||
android:inputType="textMultiLine"
|
||||
android:padding="@dimen/event_edit_comment_padding"
|
||||
android:scrollbars="vertical"
|
||||
android:singleLine="false"
|
||||
android:text="lonk message (very very very long, trust me, i'm sure that is is very loooooooooooooooonk so will fit many lines and still be very very loooooooooooooooooooooooooooooooooonk"
|
||||
android:textColor="@color/pegasko_white"
|
||||
android:textSize="@dimen/event_edit_comment_text">
|
||||
|
||||
|
@ -78,4 +89,40 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/event_edit_container_tags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/event_edit_box_margin"
|
||||
android:background="@drawable/box_red"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/event_edit_hint_margin"
|
||||
android:paddingLeft="@dimen/event_edit_hint_padding_left"
|
||||
android:text="Tags"
|
||||
android:textColor="@color/pegasko_black"
|
||||
android:textSize="@dimen/event_edit_hint_text"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
android:id="@+id/event_edit_tags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/event_edit_tags_suggest_margin"
|
||||
android:background="@drawable/box_black"
|
||||
android:hint="tags"
|
||||
android:padding="@dimen/event_edit_tags_suggest_padding"
|
||||
android:textSize="@dimen/event_edit_tags_suggest_text">
|
||||
|
||||
</MultiAutoCompleteTextView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
11
Yeeemp/app/src/main/res/layout/event_edit_tag.xml
Normal file
11
Yeeemp/app/src/main/res/layout/event_edit_tag.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="@dimen/event_list_item_tag_padding"
|
||||
android:layout_margin="@dimen/event_list_item_tag_margin"
|
||||
android:background="@drawable/box_red"
|
||||
android:textColor="@color/pegasko_black"
|
||||
android:text="sample_tag" >
|
||||
|
||||
</TextView>
|
|
@ -40,7 +40,6 @@
|
|||
android:layout_margin="@dimen/event_list_item_comment_margin"
|
||||
android:fontFamily="monospace"
|
||||
android:text="TextView"
|
||||
android:textAlignment="center"
|
||||
android:visibility="gone"
|
||||
android:padding="@dimen/event_list_item_comment_padding"
|
||||
android:textColor="@color/pegasko_white"
|
||||
|
|
|
@ -53,5 +53,13 @@
|
|||
|
||||
<dimen name="event_edit_comment_margin">8dp</dimen>
|
||||
<dimen name="event_edit_comment_padding">4dp</dimen>
|
||||
<dimen name="event_edit_comment_text">12sp</dimen>
|
||||
<dimen name="event_edit_comment_text">24sp</dimen>
|
||||
|
||||
<dimen name="event_edit_tags_margin">8dp</dimen>
|
||||
<dimen name="event_edit_tags_padding">4dp</dimen>
|
||||
<dimen name="event_edit_tags_text">24sp</dimen>
|
||||
|
||||
<dimen name="event_edit_tags_suggest_padding">4dp</dimen>
|
||||
<dimen name="event_edit_tags_suggest_margin">8dp</dimen>
|
||||
<dimen name="event_edit_tags_suggest_text">24sp</dimen>
|
||||
</resources>
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
* Copyright 2024 pegasko
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package art.pegasko.yeeemp;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue