Minimal working prototype

This commit is contained in:
pegasko 2024-06-11 01:03:10 +03:00
parent de2bdf4b91
commit 5f31ce23d0
29 changed files with 668 additions and 451 deletions

View file

@ -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() {
}
}

View file

@ -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());
}
}

View file

@ -18,12 +18,20 @@ package art.pegasko.yeeemp.base;
public interface Event { public interface Event {
int getId(); int getId();
long getTimestamp(); long getTimestamp();
void setTimestamp(long timestamp); void setTimestamp(long timestamp);
String getComment(); String getComment();
void setComment(String comment); void setComment(String comment);
void addTag(Tag tag); void addTag(Tag tag);
void removeTag(Tag tag); void removeTag(Tag tag);
void removeTags(); void removeTags();
Tag[] getTags(); Tag[] getTags();
} }

View file

@ -18,6 +18,8 @@ package art.pegasko.yeeemp.base;
public interface EventMaker { public interface EventMaker {
Event create(); Event create();
void delete(Event event); void delete(Event event);
Event getById(int id); Event getById(int id);
} }

View file

@ -18,11 +18,18 @@ package art.pegasko.yeeemp.base;
public interface Queue { public interface Queue {
int getId(); int getId();
String getName(); String getName();
void setName(String name); void setName(String name);
Event[] getEvents(); Event[] getEvents();
int getEventCount(); int getEventCount();
void addEvent(Event event); void addEvent(Event event);
void removeEvent(Event event); void removeEvent(Event event);
Tag[] getGlobalTags();
TagStat[] getGlobalTags();
} }

View file

@ -18,7 +18,10 @@ package art.pegasko.yeeemp.base;
public interface QueueMaker { public interface QueueMaker {
Queue getById(int id); Queue getById(int id);
Queue create(); Queue create();
void delete(Queue queue); void delete(Queue queue);
Queue[] list(); Queue[] list();
} }

View file

@ -18,5 +18,6 @@ package art.pegasko.yeeemp.base;
public interface Tag { public interface Tag {
int getId(); int getId();
String getName(); String getName();
} }

View file

@ -17,6 +17,5 @@
package art.pegasko.yeeemp.base; package art.pegasko.yeeemp.base;
public interface TagMaker { public interface TagMaker {
/** Get or Create distinct name Tag in Queue */
Tag getOrCreateInQueue(Queue queue, String name); Tag getOrCreateInQueue(Queue queue, String name);
} }

View file

@ -40,6 +40,8 @@ public abstract class Wrapper {
} }
public abstract QueueMaker queueMaker(); public abstract QueueMaker queueMaker();
public abstract EventMaker eventMaker(); public abstract EventMaker eventMaker();
public abstract TagMaker tagMaker(); public abstract TagMaker tagMaker();
} }

View file

@ -129,7 +129,7 @@ public class DBWrapper extends Wrapper {
try { try {
new File(context.getFilesDir(), DB_PATH).delete(); new File(context.getFilesDir(), DB_PATH).delete();
} catch (Exception e) { } catch (Exception e) {
Log.wtf(DBWrapper.TAG, e); Log.wtf(TAG, e);
} }
} }

View file

@ -46,14 +46,8 @@ public class EventImpl implements Event {
@Override @Override
public long getTimestamp() { public long getTimestamp() {
synchronized (this.db) { synchronized (this.db) {
Cursor cursor = db.query( Cursor cursor = db.query("event", new String[] { "timestamp" }, "id = ?",
"event", new String[] { Integer.toString(this.getId()) }, null, null, null
new String[] { "timestamp" },
"id = ?",
new String[] { Integer.toString(this.getId()) },
null,
null,
null
); );
if (Utils.findResult(cursor)) { if (Utils.findResult(cursor)) {
@ -69,26 +63,15 @@ public class EventImpl implements Event {
synchronized (this.db) { synchronized (this.db) {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
cv.put("timestamp", timestamp); cv.put("timestamp", timestamp);
db.update( db.update("event", cv, "id = ?", new String[] { Integer.toString(this.getId()) });
"event",
cv,
"id = ?",
new String[] { Integer.toString(this.getId()) }
);
} }
} }
@Override @Override
public String getComment() { public String getComment() {
synchronized (this.db) { synchronized (this.db) {
Cursor cursor = db.query( Cursor cursor = db.query("event", new String[] { "comment" }, "id = ?",
"event", new String[] { Integer.toString(this.getId()) }, null, null, null
new String[] { "comment" },
"id = ?",
new String[] { Integer.toString(this.getId()) },
null,
null,
null
); );
if (Utils.findResult(cursor)) { if (Utils.findResult(cursor)) {
@ -104,27 +87,18 @@ public class EventImpl implements Event {
synchronized (this.db) { synchronized (this.db) {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
cv.put("comment", comment); cv.put("comment", comment);
db.update( db.update("event", cv, "id = ?", new String[] { Integer.toString(this.getId()) });
"event",
cv,
"id = ?",
new String[] { Integer.toString(this.getId()) }
);
} }
} }
/** !synchronized */ /**
* !synchronized
*/
protected boolean hasTag(Tag tag) { protected boolean hasTag(Tag tag) {
synchronized (this.db) { synchronized (this.db) {
Cursor cursor = db.query( Cursor cursor = db.query("event_tag", new String[] { "1" }, "event_id = ? AND tag_id = ?", new String[] {
"event_tag", Integer.toString(this.getId()), Integer.toString(tag.getId())
new String[] { "1" }, }, null, null, null);
"event_id = ? AND tag_id = ?",
new String[] { Integer.toString(this.getId()), Integer.toString(tag.getId()) },
null,
null,
null
);
return Utils.findResult(cursor); return Utils.findResult(cursor);
} }
@ -133,11 +107,9 @@ public class EventImpl implements Event {
@Override @Override
public void addTag(Tag tag) { public void addTag(Tag tag) {
synchronized (this.db) { synchronized (this.db) {
if (tag == null) if (tag == null) return;
return;
if (this.hasTag(tag)) if (this.hasTag(tag)) return;
return;
try { try {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
@ -153,18 +125,14 @@ public class EventImpl implements Event {
@Override @Override
public void removeTag(Tag tag) { public void removeTag(Tag tag) {
synchronized (this.db) { synchronized (this.db) {
if (tag == null) if (tag == null) return;
return;
if (!this.hasTag(tag)) if (!this.hasTag(tag)) return;
return;
try { try {
db.delete( db.delete("event_tag", "event_id = ? AND tag_id = ?", new String[] {
"event_tag", Integer.toString(this.getId()), Integer.toString(tag.getId())
"event_id = ? AND tag_id = ?", });
new String[] { Integer.toString(this.getId()), Integer.toString(tag.getId()) }
);
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(TAG, e);
} }
@ -175,11 +143,7 @@ public class EventImpl implements Event {
public void removeTags() { public void removeTags() {
synchronized (this.db) { synchronized (this.db) {
try { try {
db.delete( db.delete("event_tag", "event_id = ?", new String[] { Integer.toString(this.getId()) });
"event_tag",
"event_id = ?",
new String[] { Integer.toString(this.getId()) }
);
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(TAG, e);
} }
@ -189,14 +153,8 @@ public class EventImpl implements Event {
@Override @Override
public Tag[] getTags() { public Tag[] getTags() {
synchronized (this.db) { synchronized (this.db) {
Cursor cursor = db.query( Cursor cursor = db.query("event_tag", new String[] { "tag_id" }, "event_id = ?",
"event_tag", new String[] { Integer.toString(this.getId()) }, null, null, "tag_id desc"
new String[] { "tag_id" },
"event_id = ?",
new String[] { Integer.toString(this.getId()) },
null,
null,
null
); );
if (cursor == null) { if (cursor == null) {
@ -207,10 +165,7 @@ public class EventImpl implements Event {
int index = 0; int index = 0;
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
tags[index++] = new TagImpl( tags[index++] = new TagImpl(this.db, cursor.getInt(0));
this.db,
cursor.getInt(0)
);
} }
return tags; return tags;

View file

@ -49,8 +49,7 @@ public class EventMakerImpl implements EventMaker {
null null
); );
if (Utils.findResult(cursor)) if (Utils.findResult(cursor)) return new EventImpl(this.db, id);
return new EventImpl(this.db, id);
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(TAG, e);
@ -67,10 +66,7 @@ public class EventMakerImpl implements EventMaker {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
cv.put("id", (Integer) null); cv.put("id", (Integer) null);
long rowId = db.insertOrThrow("event", null, cv); long rowId = db.insertOrThrow("event", null, cv);
return new EventImpl( return new EventImpl(this.db, (int) rowId);
this.db,
(int) rowId
);
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(TAG, e);
} }
@ -84,25 +80,13 @@ public class EventMakerImpl implements EventMaker {
synchronized (this.db) { synchronized (this.db) {
try { try {
// Delete queue <-> event // Delete queue <-> event
db.delete( db.delete("queue_event", "event_id = ?", new String[] { Integer.toString(event.getId()) });
"queue_event",
"event_id = ?",
new String[] { Integer.toString(event.getId()) }
);
// Delete event <-> tag // Delete event <-> tag
db.delete( db.delete("event_tag", "event_id = ?", new String[] { Integer.toString(event.getId()) });
"event_tag",
"event_id = ?",
new String[] { Integer.toString(event.getId()) }
);
// Delete event // Delete event
db.delete( db.delete("event", "id = ?", new String[] { Integer.toString(event.getId()) });
"event",
"id = ?",
new String[] { Integer.toString(event.getId()) }
);
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(TAG, e);
} }

View file

@ -27,6 +27,7 @@ import androidx.annotation.NonNull;
import art.pegasko.yeeemp.base.Event; import art.pegasko.yeeemp.base.Event;
import art.pegasko.yeeemp.base.Queue; import art.pegasko.yeeemp.base.Queue;
import art.pegasko.yeeemp.base.Tag; import art.pegasko.yeeemp.base.Tag;
import art.pegasko.yeeemp.base.TagStat;
import kotlin.NotImplementedError; import kotlin.NotImplementedError;
public class QueueImpl implements Queue { public class QueueImpl implements Queue {
@ -131,7 +132,9 @@ public class QueueImpl implements Queue {
} }
} }
/** !synchronized */ /**
* !synchronized
*/
protected boolean hasEvent(Event event) { protected boolean hasEvent(Event event) {
synchronized (this.db) { synchronized (this.db) {
Cursor cursor = db.query( Cursor cursor = db.query(
@ -190,30 +193,60 @@ public class QueueImpl implements Queue {
} }
@Override @Override
public Tag[] getGlobalTags() { public TagStat[] getGlobalTags() {
synchronized (this.db) { synchronized (this.db) {
Cursor cursor = db.query( Cursor cursor = db.rawQuery(
"tag", "select" +
new String[] { "id" }, " tag_id,\n" +
"queue_id = ?", " count(*) as cnt\n" +
new String[] { Integer.toString(this.getId()) }, "from (\n" +
null, " select\n" +
null, " event_id,\n" +
null " 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) { 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; int index = 0;
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
tags[index++] = new TagImpl( TagStat tagStat = new TagStat();
tags[index++] = tagStat;
tagStat.tag = new TagImpl(
this.db, this.db,
cursor.getInt(0) cursor.getInt(0)
); );
tagStat.count = cursor.getInt(1);
} }
return tags; return tags;

View file

@ -50,11 +50,16 @@ public class QueueMakerImpl implements QueueMaker {
null null
); );
if (Utils.findResult(cursor)) if (Utils.findResult(cursor)) return new QueueImpl(
return new QueueImpl(this.db, id); this.db,
id
);
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(
TAG,
e
);
} }
return null; return null;
@ -66,14 +71,24 @@ public class QueueMakerImpl implements QueueMaker {
synchronized (this.db) { synchronized (this.db) {
try { try {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
cv.put("id", (Integer) null); cv.put(
long rowId = db.insertOrThrow("queue", null, cv); "id",
(Integer) null
);
long rowId = db.insertOrThrow(
"queue",
null,
cv
);
return new QueueImpl( return new QueueImpl(
this.db, this.db,
(int) rowId (int) rowId
); );
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(
TAG,
e
);
} }
return null; return null;
@ -117,7 +132,7 @@ public class QueueMakerImpl implements QueueMaker {
// Drop events // Drop events
try { try {
for (Event event: queue.getEvents()) { for (Event event : queue.getEvents()) {
db.delete( db.delete(
"event", "event",
"id = ?", "id = ?",
@ -125,7 +140,10 @@ public class QueueMakerImpl implements QueueMaker {
); );
} }
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(
TAG,
e
);
return; return;
} }
@ -137,7 +155,10 @@ public class QueueMakerImpl implements QueueMaker {
new String[] { Integer.toString(queue.getId()) } new String[] { Integer.toString(queue.getId()) }
); );
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(
TAG,
e
);
} }
// Drop queue // Drop queue
@ -148,7 +169,10 @@ public class QueueMakerImpl implements QueueMaker {
new String[] { Integer.toString(queue.getId()) } new String[] { Integer.toString(queue.getId()) }
); );
} catch (SQLiteException e) { } catch (SQLiteException e) {
Log.wtf(TAG, e); Log.wtf(
TAG,
e
);
} }
} }
} }

View file

@ -21,8 +21,7 @@ import android.database.sqlite.SQLiteDatabase;
public class Utils { public class Utils {
public static boolean findResult(Cursor cursor) { public static boolean findResult(Cursor cursor) {
if (cursor == null) if (cursor == null) return false;
return false;
cursor.moveToFirst(); cursor.moveToFirst();
return cursor.getCount() != 0; return cursor.getCount() != 0;
} }

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package art.pegasko.yeeemp.okand.base; package art.pegasko.yeeemp.okand.base;
public abstract class Potato { public abstract class Potato {
private static Potato instance; private static Potato instance;
@ -28,6 +28,8 @@ public abstract class Potato {
} }
public abstract Event getById(int id); public abstract Event getById(int id);
public abstract void save(Event container); public abstract void save(Event container);
public abstract void delete(Event container); public abstract void delete(Event container);
} }

View file

@ -14,7 +14,7 @@
* limitations under the License. * 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.Event;
import art.pegasko.yeeemp.okand.base.Potato; import art.pegasko.yeeemp.okand.base.Potato;

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package art.pegasko.yeeemp.ui.activity; package art.pegasko.yeeemp.ui.activity;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
@ -24,9 +24,14 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.util.TimeUtils; import android.util.TimeUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.DatePicker; import android.widget.DatePicker;
import android.widget.MultiAutoCompleteTextView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TimePicker; import android.widget.TimePicker;
@ -39,12 +44,16 @@ import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import art.pegasko.yeeemp.base.Queue; import art.pegasko.yeeemp.base.Queue;
import art.pegasko.yeeemp.base.Tag; import art.pegasko.yeeemp.base.Tag;
import art.pegasko.yeeemp.base.TagStat;
import art.pegasko.yeeemp.databinding.ActivityEventEditBinding; import art.pegasko.yeeemp.databinding.ActivityEventEditBinding;
import art.pegasko.yeeemp.R; import art.pegasko.yeeemp.R;
@ -59,8 +68,11 @@ public class EventEditActivity extends AppCompatActivity {
private Event event; private Event event;
private EventContainer eventContainer; private EventContainer eventContainer;
private ActivityEventEditBinding binding; private ActivityEventEditBinding binding;
private TagStat[] tagStat;
/** Store values for edited or new event */ /**
* Store values for edited or new event
*/
private static class EventContainer { private static class EventContainer {
public String comment; public String comment;
public long timestamp; public long timestamp;
@ -82,21 +94,33 @@ public class EventEditActivity extends AppCompatActivity {
// Get Queue ID from Intent // Get Queue ID from Intent
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
if (extras == null) { if (extras == null) {
Log.e(TAG, "Missing Intent arguments (queue_id)"); Log.e(
TAG,
"Missing Intent arguments (queue_id)"
);
finish(); finish();
return; return;
} }
int queue_id = extras.getInt("queue_id", -1); int queue_id = extras.getInt(
"queue_id",
-1
);
if (queue_id == -1) { if (queue_id == -1) {
Log.e(TAG, "Missing Intent arguments (queue_id)"); Log.e(
TAG,
"Missing Intent arguments (queue_id)"
);
finish(); finish();
return; return;
} }
queue = Wrapper.getQueueMaker().getById(queue_id); queue = Wrapper.getQueueMaker().getById(queue_id);
if (queue == null) { if (queue == null) {
Log.e(TAG, "Missing Intent arguments (queue_id)"); Log.e(
TAG,
"Missing Intent arguments (queue_id)"
);
finish(); finish();
return; return;
} }
@ -107,12 +131,15 @@ public class EventEditActivity extends AppCompatActivity {
// Get Event ID from Intent (optional) // Get Event ID from Intent (optional)
extras = getIntent().getExtras(); extras = getIntent().getExtras();
if (extras != null) { if (extras != null) {
int event_id = extras.getInt("event_id", -1); int event_id = extras.getInt(
"event_id",
-1
);
if (event_id != -1) { if (event_id != -1) {
this.event = Wrapper.getEventMaker().getById(event_id); this.event = Wrapper.getEventMaker().getById(event_id);
this.eventContainer.timestamp = this.event.getTimestamp(); this.eventContainer.timestamp = this.event.getTimestamp();
this.eventContainer.comment = this.event.getComment(); this.eventContainer.comment = this.event.getComment();
for (Tag tag: this.event.getTags()) { for (Tag tag : this.event.getTags()) {
this.eventContainer.tags.add(tag.getName()); this.eventContainer.tags.add(tag.getName());
} }
} }
@ -121,7 +148,8 @@ public class EventEditActivity extends AppCompatActivity {
binding = ActivityEventEditBinding.inflate(getLayoutInflater()); binding = ActivityEventEditBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar); 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().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true);
@ -131,6 +159,17 @@ public class EventEditActivity extends AppCompatActivity {
if (this.eventContainer.comment != null) if (this.eventContainer.comment != null)
binding.eventEditContent.eventEditComment.setText(this.eventContainer.comment); 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) -> { binding.eventEditContent.eventEditContainerTimestamp.setOnClickListener((View view) -> {
Date date; Date date;
if (this.eventContainer.timestamp != 0) if (this.eventContainer.timestamp != 0)
@ -153,21 +192,34 @@ public class EventEditActivity extends AppCompatActivity {
newDate.setSeconds(0); newDate.setSeconds(0);
this.eventContainer.timestamp = newDate.getTime(); 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(); timePickerDialog.show();
}, date.getYear() + 1900, date.getMonth(), date.getDate() },
date.getYear() + 1900,
date.getMonth(),
date.getDate()
); );
datePickerDialog.show(); datePickerDialog.show();
}); });
/* FAB Listeners */ /* FAB Listeners */
binding.fab.setOnLongClickListener((View view) -> { 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) .setAnchorView(R.id.fab)
.setAction("Action", null).show(); .setAction(
"Action",
null
).show();
return true; return true;
}); });
@ -175,20 +227,75 @@ public class EventEditActivity extends AppCompatActivity {
// Finalize values // Finalize values
this.eventContainer.comment = this.binding.eventEditContent.eventEditComment.getText().toString().trim(); 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 // Fill event
boolean hasEvent = this.event != null;
if (this.event == null) if (this.event == null)
this.event = Wrapper.getEventMaker().create(); this.event = Wrapper.getEventMaker().create();
this.event.setTimestamp(this.eventContainer.timestamp); this.event.setTimestamp(this.eventContainer.timestamp);
this.event.removeTags(); this.event.removeTags();
for (String tag: this.eventContainer.tags) { for (String tag : this.eventContainer.tags) {
this.event.addTag(Wrapper.getTagMaker().getOrCreateInQueue(this.queue, tag)); this.event.addTag(Wrapper.getTagMaker().getOrCreateInQueue(
this.queue,
tag
));
} }
this.event.setComment(this.eventContainer.comment); this.event.setComment(this.eventContainer.comment);
if (!hasEvent) {
this.queue.addEvent(event);
}
finish(); 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 @Override

View file

@ -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();
}
}
};
}

View file

@ -63,21 +63,33 @@ public class EventListActivity extends AppCompatActivity {
// Get Queue ID from Intent // Get Queue ID from Intent
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
if (extras == null) { if (extras == null) {
Log.e(TAG, "Missing Intent arguments (queue_id)"); Log.e(
TAG,
"Missing Intent arguments (queue_id)"
);
finish(); finish();
return; return;
} }
int queue_id = extras.getInt("queue_id", -1); int queue_id = extras.getInt(
"queue_id",
-1
);
if (queue_id == -1) { if (queue_id == -1) {
Log.e(TAG, "Missing Intent arguments (queue_id)"); Log.e(
TAG,
"Missing Intent arguments (queue_id)"
);
finish(); finish();
return; return;
} }
queue = Wrapper.getQueueMaker().getById(queue_id); queue = Wrapper.getQueueMaker().getById(queue_id);
if (queue == null) { if (queue == null) {
Log.e(TAG, "Missing Intent arguments (queue_id)"); Log.e(
TAG,
"Missing Intent arguments (queue_id)"
);
finish(); finish();
return; return;
} }
@ -116,31 +128,33 @@ public class EventListActivity extends AppCompatActivity {
/* FAB Listeners */ /* FAB Listeners */
binding.fab.setOnLongClickListener((View view) -> { 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) .setAnchorView(R.id.fab)
.setAction("Action", null).show(); .setAction(
"Action",
null
).show();
return true; return true;
}); });
binding.fab.setOnClickListener(view -> { binding.fab.setOnClickListener(view -> {
Bundle extra = new Bundle(); 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); intent.putExtras(extra);
view.getContext().startActivity(intent); 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 */ /* Fill lists */

View file

@ -59,7 +59,11 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
View view = ( View view = (
LayoutInflater LayoutInflater
.from(viewGroup.getContext()) .from(viewGroup.getContext())
.inflate(R.layout.event_list_item, viewGroup, false) .inflate(
R.layout.event_list_item,
viewGroup,
false
)
); );
return new ViewHolder(view); return new ViewHolder(view);
@ -69,12 +73,15 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
viewHolder.getBinding().eventListItemTags.removeAllViews(); viewHolder.getBinding().eventListItemTags.removeAllViews();
Tag[] tags = this.events[position].getTags(); Tag[] tags = this.events[position].getTags();
Log.w(TAG, "Tags: " + tags.length); for (Tag tag : tags) {
for (Tag tag: tags) {
TextView tagView = (TextView) ( TextView tagView = (TextView) (
LayoutInflater LayoutInflater
.from(viewHolder.getBinding().getRoot().getContext()) .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()); tagView.setText(tag.getName());
@ -87,22 +94,37 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
if (comment != null && !comment.isEmpty()) { if (comment != null && !comment.isEmpty()) {
viewHolder.getBinding().eventListItemComment.setVisibility(View.VISIBLE); viewHolder.getBinding().eventListItemComment.setVisibility(View.VISIBLE);
viewHolder.getBinding().eventListItemComment.setText(comment); viewHolder.getBinding().eventListItemComment.setText(comment);
} else {
viewHolder.getBinding().eventListItemComment.setVisibility(View.GONE);
viewHolder.getBinding().eventListItemComment.setText("");
} }
viewHolder.getBinding().eventListItemItem.setOnLongClickListener((View view) -> { viewHolder.getBinding().eventListItemItem.setOnLongClickListener((View view) -> {
PopupMenu popupMenu = new PopupMenu(view.getContext(), viewHolder.getBinding().eventListItemItem); PopupMenu popupMenu = new PopupMenu(
popupMenu.getMenuInflater().inflate(R.menu.event_list_item_action_menu, popupMenu.getMenu()); view.getContext(),
viewHolder.getBinding().eventListItemItem
);
popupMenu.getMenuInflater().inflate(
R.menu.event_list_item_action_menu,
popupMenu.getMenu()
);
popupMenu.setOnMenuItemClickListener((MenuItem menuItem) -> { popupMenu.setOnMenuItemClickListener((MenuItem menuItem) -> {
if (menuItem.getItemId() == R.id.event_list_item_action_menu_delete) { if (menuItem.getItemId() == R.id.event_list_item_action_menu_delete) {
new AlertDialog.Builder(view.getContext()) new AlertDialog.Builder(view.getContext())
.setTitle("Delete event") .setTitle("Delete event")
.setMessage("Are you sure you want to delete this event?") .setMessage("Are you sure you want to delete this event?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> { .setPositiveButton(
Wrapper.getEventMaker().delete(events[position]); android.R.string.yes,
(dialog, which) -> {
Wrapper.getEventMaker().delete(events[position]);
reloadItems(); reloadItems();
}) }
.setNegativeButton(android.R.string.no, null) )
.setNegativeButton(
android.R.string.no,
null
)
.setIcon(android.R.drawable.ic_dialog_alert) .setIcon(android.R.drawable.ic_dialog_alert)
.show(); .show();
} }
@ -115,10 +137,19 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
}); });
viewHolder.getBinding().eventListItemItem.setOnClickListener((View view) -> { viewHolder.getBinding().eventListItemItem.setOnClickListener((View view) -> {
Bundle extra = new Bundle(); Bundle extra = new Bundle();
extra.putInt("event_id", this.events[position].getId()); extra.putInt(
extra.putInt("queue_id", this.queue.getId()); "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); intent.putExtras(extra);
view.getContext().startActivity(intent); view.getContext().startActivity(intent);
@ -147,19 +178,4 @@ class EventRecyclerViewAdapter extends RecyclerView.Adapter<EventRecyclerViewAda
this.events = this.queue.getEvents(); this.events = this.queue.getEvents();
this.notifyDataSetChanged(); 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;
// }
} }

View file

@ -17,7 +17,9 @@
package art.pegasko.yeeemp.ui.activity; package art.pegasko.yeeemp.ui.activity;
import android.os.Bundle; import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.util.Log; import android.util.Log;
@ -66,16 +68,20 @@ public class QueueListActivity extends AppCompatActivity {
/* FAB Listeners */ /* FAB Listeners */
binding.fab.setOnLongClickListener((View view) -> { binding.fab.setOnLongClickListener((View view) -> {
Snackbar.make(view, "Create Queue", Snackbar.LENGTH_LONG) Snackbar.make(
.setAnchorView(R.id.fab) view,
.setAction("Action", null).show(); "Create Queue",
Snackbar.LENGTH_LONG
).setAnchorView(R.id.fab).setAction(
"Action",
null
).show();
return true; return true;
}); });
binding.fab.setOnClickListener(view -> { binding.fab.setOnClickListener(view -> {
Queue q = Wrapper.getQueueMaker().create(); Queue q = Wrapper.getQueueMaker().create();
q.setName("New Queue"); q.setName("New Queue");
Log.w(TAG, "Create: " + q.toString());
updateList(); updateList();
}); });

View file

@ -50,7 +50,11 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
View view = ( View view = (
LayoutInflater LayoutInflater
.from(viewGroup.getContext()) .from(viewGroup.getContext())
.inflate(R.layout.queue_list_item, viewGroup, false) .inflate(
R.layout.queue_list_item,
viewGroup,
false
)
); );
return new ViewHolder(view); return new ViewHolder(view);
@ -61,19 +65,31 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
viewHolder.getBinding().queueListItemTitle.setText(queues[position].getName()); viewHolder.getBinding().queueListItemTitle.setText(queues[position].getName());
viewHolder.getBinding().queueListItemItem.setOnLongClickListener((View view) -> { viewHolder.getBinding().queueListItemItem.setOnLongClickListener((View view) -> {
PopupMenu popupMenu = new PopupMenu(view.getContext(), viewHolder.getBinding().queueListItemItem); PopupMenu popupMenu = new PopupMenu(
popupMenu.getMenuInflater().inflate(R.menu.queue_list_item_action_menu, popupMenu.getMenu()); view.getContext(),
viewHolder.getBinding().queueListItemItem
);
popupMenu.getMenuInflater().inflate(
R.menu.queue_list_item_action_menu,
popupMenu.getMenu()
);
popupMenu.setOnMenuItemClickListener((MenuItem menuItem) -> { popupMenu.setOnMenuItemClickListener((MenuItem menuItem) -> {
if (menuItem.getItemId() == R.id.queue_list_item_action_menu_delete) { if (menuItem.getItemId() == R.id.queue_list_item_action_menu_delete) {
new AlertDialog.Builder(view.getContext()) new AlertDialog.Builder(view.getContext())
.setTitle("Delete queue") .setTitle("Delete queue")
.setMessage("Are you sure you want to delete this queue?") .setMessage("Are you sure you want to delete this queue?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> { .setPositiveButton(
Wrapper.getQueueMaker().delete(queues[position]); android.R.string.yes,
(dialog, which) -> {
Wrapper.getQueueMaker().delete(queues[position]);
reloadItems(); reloadItems();
}) }
.setNegativeButton(android.R.string.no, null) )
.setNegativeButton(
android.R.string.no,
null
)
.setIcon(android.R.drawable.ic_dialog_alert) .setIcon(android.R.drawable.ic_dialog_alert)
.show(); .show();
} else if (menuItem.getItemId() == R.id.queue_list_item_action_menu_rename) { } 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()); input.setText(queues[position].getName());
builder.setView(input); builder.setView(input);
builder.setPositiveButton("OK", (dialog, which) -> { builder.setPositiveButton(
String name = input.getText().toString().trim(); "OK",
queues[position].setName(name); (dialog, which) -> {
String name = input.getText().toString().trim();
queues[position].setName(name);
reloadItems(); reloadItems();
}); }
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel()); );
builder.setNegativeButton(
"Cancel",
(dialog, which) -> dialog.cancel()
);
builder.show(); builder.show();
} }
@ -104,9 +126,15 @@ class QueueRecyclerViewAdapter extends RecyclerView.Adapter<QueueRecyclerViewAda
}); });
viewHolder.getBinding().queueListItemItem.setOnClickListener((View view) -> { viewHolder.getBinding().queueListItemItem.setOnClickListener((View view) -> {
Bundle extra = new Bundle(); 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); intent.putExtras(extra);
view.getContext().startActivity(intent); 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().queueListItemStats.setText(Integer.toString(queues[position].getEventCount()));
viewHolder.getBinding().queueListItemPlus.setOnClickListener((View view) -> { 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); 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();
}); });
} }

View file

@ -17,7 +17,10 @@
package art.pegasko.yeeemp.ui.activity; package art.pegasko.yeeemp.ui.activity;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class Utils { public class Utils {
public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; 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); SimpleDateFormat sdf = new SimpleDateFormat(Utils.DATE_FORMAT);
return sdf.format(timestamp); 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;
}
} }

View file

@ -5,77 +5,124 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/pegasko_black" android:background="@color/pegasko_black"
android:orientation="vertical" android:orientation="vertical">
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent">
android:orientation="vertical"
android:layout_margin="@dimen/event_edit_box_margin"
android:id="@+id/event_edit_container_timestamp"
android:background="@drawable/box_red" >
<TextView <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_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_margin="@dimen/event_edit_hint_margin" android:background="@color/pegasko_black"
android:paddingLeft="@dimen/event_edit_hint_padding_left" android:orientation="vertical">
android:text="Time"
android:textSize="@dimen/event_edit_hint_text"
android:textColor="@color/pegasko_black"
android:textStyle="bold" />
<TextView <LinearLayout
android:id="@+id/event_edit_timestamp" android:id="@+id/event_edit_container_timestamp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/event_edit_timestamp_margin" android:layout_margin="@dimen/event_edit_box_margin"
android:background="@drawable/box_black" android:background="@drawable/box_red"
android:gravity="center" android:orientation="vertical">
android:padding="@dimen/event_edit_timestamp_padding"
android:text="Timestamp"
android:textColor="@color/pegasko_white"
android:textSize="@dimen/event_edit_timestamp_text"/>
</LinearLayout> <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="Time"
android:textColor="@color/pegasko_black"
android:textSize="@dimen/event_edit_hint_text"
android:textStyle="bold" />
<LinearLayout <TextView
android:layout_width="match_parent" android:id="@+id/event_edit_timestamp"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="wrap_content"
android:layout_margin="@dimen/event_edit_box_margin" android:layout_margin="@dimen/event_edit_timestamp_margin"
android:background="@drawable/box_red" > android:background="@drawable/box_black"
android:gravity="center"
android:padding="@dimen/event_edit_timestamp_padding"
android:text="Timestamp"
android:textColor="@color/pegasko_white"
android:textSize="@dimen/event_edit_timestamp_text" />
<TextView </LinearLayout>
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:textStyle="bold" />
<EditText <LinearLayout
android:id="@+id/event_edit_comment" android:id="@+id/event_edit_container_comment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/event_edit_comment_margin" android:layout_margin="@dimen/event_edit_box_margin"
android:background="@drawable/box_black" android:background="@drawable/box_red"
android:cursorVisible="true" android:orientation="vertical">
android:gravity="start|left"
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">
</EditText> <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="Comment"
android:textColor="@color/pegasko_black"
android:textSize="@dimen/event_edit_hint_text"
android:textStyle="bold" />
</LinearLayout> <EditText
android:id="@+id/event_edit_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/event_edit_comment_margin"
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:textColor="@color/pegasko_white"
android:textSize="@dimen/event_edit_comment_text">
</EditText>
</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> </LinearLayout>

View 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>

View file

@ -40,7 +40,6 @@
android:layout_margin="@dimen/event_list_item_comment_margin" android:layout_margin="@dimen/event_list_item_comment_margin"
android:fontFamily="monospace" android:fontFamily="monospace"
android:text="TextView" android:text="TextView"
android:textAlignment="center"
android:visibility="gone" android:visibility="gone"
android:padding="@dimen/event_list_item_comment_padding" android:padding="@dimen/event_list_item_comment_padding"
android:textColor="@color/pegasko_white" android:textColor="@color/pegasko_white"

View file

@ -53,5 +53,13 @@
<dimen name="event_edit_comment_margin">8dp</dimen> <dimen name="event_edit_comment_margin">8dp</dimen>
<dimen name="event_edit_comment_padding">4dp</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> </resources>

View file

@ -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);
}
}