Android - sql query for group_by items - android

I'm creating android app where user enters some Receipts and Logs. Relation is: Receipt has_many Logs.
Here are my receipt and log model.
#Table(name = "Logs")
public class Logs extends Model {
#Column(name="PlateNumber")
String plate_number;
#Column(name="SortID")
String sort_id;
#Column(name="Grade")
String grade;
#Column(name = "Diametar")
double diameter;
#Column(name="Length")
double length;
#Column(name="CreatedAt")
Date createdAt;
#Column(name="Receipt")
Receipt receipt;
#Column(name = "Price")
Price price;
}
#Table(name = "Receipt")
public class Receipt extends Model {
#Column(name="Place")
String place;
#Column(name="ShippingNumber")
String shippingNumber;
#Column(name="Warehouse")
String warehouse;
#Column(name="Carrier")
String carrier;
#Column(name="LicencePlate")
String licencePlate;
#Column(name = "Driver")
String driver;
#Column(name = "Customer")
String customer;
#Column(name= "DestWarehouse")
String destWarehouse;
#Column(name = "Employee")
String employee;
#Column(name = "PriceType")
String priceType;
#Column(name = "PriceCorrection")
Double priceCorrection;
#Column(name = "PriceCorrection2")
Double priceCorrection2;
#Column(name = "Supplier")
String supplier;
#Column(name = "CreatedAt")
Date createdAt;
}
Here is my activity where I'm trying to achieve this but unsuccessfully.
public class LogsRecapitulation extends AppCompatActivity {
private ListView mainListView;
private BaseAdapter listAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_listview);
mainListView = (ListView) findViewById(R.id.ListViewItem);
//recieve RecepitID in displayLogs.activity
final long forwardedId = (long) getIntent().getExtras().get(String.valueOf("recepitID"));
List<Logs> logsList = new Select().from(Logs.class).where("Receipt = " + forwardedId).groupBy("SortID").execute(); // I grouped Logs by sortId in this line.
listAdapter = new RecapitulationArrayAdapter(logsList);
mainListView.setAdapter(listAdapter);
}
private class RecapitulationArrayAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List<Logs> logsList;
public RecapitulationArrayAdapter(List<Logs> logsList) {
inflater = LayoutInflater.from(LogsRecapitulation.this);
this.logsList = logsList;
}
#Override
public int getCount() {
return logsList.size();
}
#Override
public Object getItem(int position) {
return logsList.get(position);
}
#Override
public long getItemId(int position) {
return logsList.get(position).getId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.logs_recapitulation, parent, false);
}
Logs log = logsList.get(position);
((TextView) convertView.findViewById(R.id.rec_log_sort)).setText(log.sort_id);
((TextView) convertView.findViewById(R.id.rec_log_class)).setText(log.grade);
((TextView) convertView.findViewById(R.id.rec_log_count)).setText(String.valueOf(logsList.size()));
((TextView) convertView.findViewById(R.id.rec_logs_mass)).setText(String.format("%.2f m3", log.getM3()));
if (log.receipt.priceType.equals("Na panju")) {
((TextView) convertView.findViewById(R.id.rec_log_price_default)).setText(String.valueOf(log.price.stumpPrice_kn));
} else {
((TextView) convertView.findViewById(R.id.rec_log_price_default)).setText(String.valueOf(log.price.roadPrice_kn));
}
if (log.receipt.priceType.equals("Na panju")) {
((TextView) convertView.findViewById(R.id.rec_calculated_price)).setText(String.format("%.2f KN", log.price.stumpPrice_kn * log.getM3()));
} else {
((TextView) convertView.findViewById(R.id.rec_calculated_price)).setText(String.format("%.2f KN", log.price.roadPrice_kn * log.getM3()));
}
return convertView;
}
}
}
So, what I've done so far is that I display logs by sortID in this BaseAdapter, but in each sort it show's me only last added log and it's data.
Now I need to display data like it is on image below - part where is REKAPITULAT. There I need group by sortID and then in each sort I need group them by grade.
For example if I have like on image sort 1 with 4 logs, 2 of each grade (A,B) then it need's to display it like on image.
I'm stuck here and I would be very grateful if someone knows how to do it and is willing to help.
Question: How to create sql query or fix this my code to display data like it is on image above?

Here's an example query with GROUP BY and JOIN using ActiveAndroid:
new Select("SUM(Logs.Price)")
.from(Logs.class)
.join(Receipt.class)
.on("Receipt.Id = Logs.Receipt")
.groupBy("Logs.sortID")
.execute();
From this query, you'll get a Log instance, so you'll need to map the SUM(Logs.Price) field to a valid Log field, such as Price. For example:
new Select("SUM(Logs.Price) AS Logs.Price")
The query should be adapted for your use case.

Related

Pass an object in android mvp?

recently I been reading about the mvp pattern on Internet and to be honest, it has been a little bit confusing.
I'm trying to re-write an app using the mvp pattern but I reached a point using AsyncTask where I can't figure out how to pass the Object in the Interactor back to the View.
Here'e the code:
View:
public class DetailsActivity extends BaseActivity {
private DetailsPresenter presenter;
private Pet pet;
private TextView name, description, breed, lostAt, age;
private int idList;
#Override
protected void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.details_layout);
DetailsPresenter presenter = new DetailsPresenter();
Typeface font0 = Typeface.createFromAsset(getAssets(), "fonts/CaviarDreams.ttf");
Typeface font1 = Typeface.createFromAsset(getAssets(), "fonts/CaviarDreams_Bold.ttf");
TextView txtDescription = findViewById(R.id.textView8);
TextView txt1 = findViewById(R.id.textView6); //Age, Type
TextView txt2 = findViewById(R.id.textView9); //LostAt
Button btnContact = findViewById(R.id.button6);
description = findViewById(R.id.details);
menuRes = R.menu.details_menu;
name = findViewById(R.id.textView10);
breed = findViewById(R.id.breed);
lostAt = findViewById(R.id.lostAt);
age = findViewById(R.id.age);
name.setTypeface(font1);
breed.setTypeface(font0);
description.setTypeface(font0);
lostAt.setTypeface(font0);
txtDescription.setTypeface(font1);
txt2.setTypeface(font1);
txt1.setTypeface(font1);
btnContact.setTypeface(font0);
idList = getIntent().getExtras().getInt("TAG_LIST");
id = getIntent().getExtras().getInt("TAG_ID");
if(idList == 0){
txt1.setText(R.string.type);
txt2.setText(R.string.txt2);
} else{
txt1.setText(R.string.txt0);
txt2.setText(null);
}
btnContact.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), ChatFragment.class);
startActivity(intent);
}
});
// Get pet details from database on background
pet = presenter.getPet(idList, id);
}
#Override
protected void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if(idList == 0){
name.setText(pet.getName());
breed.setText("(" + pet.getBreed() + ")");
description.setText(pet.getDescription());
lostAt.setText(pet.getLocation());
}else{
name.setText(pet.getBreed());
description.setText(pet.getDescription());
lostAt.setText(pet.getGender());
age.setText(pet.getAge());
}
}
}
Presenter:
public class DetailsPresenter {
private DetailsInteractor interactor;
public Pet getPet(int idList, int id) {
interactor = new DetailsInteractor(idList, id);
interactor.execute();
return interactor.pet;
}
}
Interactor:
public class DetailsInteractor extends AsyncTask<String, String, Pet> {
public Pet pet;
private int idList;
private int id;
private DBAction database;
public DetailsInteractor (int idList, int id) {
this.idList = idList;
this.id = id;
database = new DBAction();
}
#Override
protected Pet doInBackground(String... strings) {
pet = database.requestItem(idList, id);
return pet;
}
I need that after getting the data from the database, it updates the View, using object Pet.
Any answers and suggestions will be welcomed, Thanks!
When You create/initialize a presenter in Activity(This is your view) you should pass the view to the presenter. Something like this.
DetailsPresenter presenter = new DetailsPresenter(View view);
View can be any object with which you can update the UI or can call the methods in the activity.
Moreover, you have to go through few more good site to learn about MVP.
http://valokafor.com/learn-android-mvp-pattern-example/ this is really nice one.

Properly Getting Firebase Data

I'm working on an app for a club where members attendance should be recorded. I'm having trouble getting it properly in a list view.
Here is a portion of the database:
There might be more than one sport attended like Karate or swimming for a given day. I want to get the member's attendance in a list view. I'll try to section it by day later, but for now I need to get the data properly.
Here is the model I made:
public class MemberAttendance {
private String day;
private HashMap<String, Object> attendedSport;
public MemberAttendance() {
}
public MemberAttendance(String day, HashMap<String, Object> attendedSport) {
this.day = day;
this.attendedSport = attendedSport;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public HashMap<String, Object> getAttendedSport() {
return attendedSport;
}
public void setAttendedSport(HashMap<String, Object> attendedSport) {
this.attendedSport = attendedSport;
}
}
Here is the adapter:
public class MemberAttendanceAdapter extends FirebaseListAdapter<MemberAttendance> {
public MemberAttendanceAdapter(Activity activity, Class<MemberAttendance> modelClass, int modelLayout, Query ref) {
super(activity, modelClass, modelLayout, ref);
}
#Override
protected void populateView(View view, MemberAttendance memberAttendance, int i) {
// Get values from firebase database
String day = memberAttendance.getDay();
HashMap<String, Object> hashMap = memberAttendance.getAttendedSport();
String sport = (String) hashMap.get("attended");
String date = (String) hashMap.get("timestamp");
// Create views and assign values
TextView dayTxtView = (TextView) view.findViewById(R.id.dayTxtView);
dayTxtView.setText(day);
TextView sportTxtView = (TextView) view.findViewById(R.id.sportTxtView);
sportTxtView.setText(sport);
TextView dateTxtView = (TextView) view.findViewById(R.id.dateTxtView);
dateTxtView.setText(date);
}
}
And here how I try to set the adapter:
final FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference attendanceRef = database.getReference()
.child(Constants.MEMBERS_NODE).child(userID).child("attendance");
attendanceAdapter = new MemberAttendanceAdapter(getActivity(), MemberAttendance.class,
R.layout.attendance_list_item, attendanceRef);
attendanceListView.setAdapter(attendanceAdapter);
So far not working and gives null pointer exception on the object reference that uses HashMap.get(..)
String sport = (String) hashMap.get("attended");
Any help is appreciated.
You might want to restructure your NoSQL Database like this:
member
---memberID
------attendance
---------attendance ID
------------attended
------------timestamp
------------date
For example:
member
---member1
------attendance
---------attendance1
------------soccer
------------14938372834
------------14-04-2017
---------attendance2
------------swimming
------------14938374323
------------14-04-2017
You don't need to store the date because use could use the timestamp to create a Date object in Java that would contain that information
Date date = new Date(timestamp);
With this structure you would need to change your POJO to this:
public class MemberAttendance {
private String attended;
private long timestamp;
public MemberAttendance() {
}
public MemberAttendance(String attended, long timestamp) {
this.attended = attended;
this.timestamp = timestamp;
}
public String getAttended() {
return attended;
}
public void setAttended(String attended) {
this.attended = attended;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.attendedSport = attendedSport;
}
}
And then you could use your same Firebase Query with the following changes in the adapter:
public class MemberAttendanceAdapter extends FirebaseListAdapter<MemberAttendance> {
public MemberAttendanceAdapter(Activity activity, Class<MemberAttendance> modelClass, int modelLayout, Query ref) {
super(activity, modelClass, modelLayout, ref);
}
#Override
protected void populateView(View view, MemberAttendance memberAttendance, int i) {
String sport = memberAttendace.getAttended();
Date date = new Date(memberAttendance.getTimestamp());
// Create views and assign values
TextView dayTxtView = (TextView) view.findViewById(R.id.dayTxtView);
dayTxtView.setText(new SimpleDateFormat("dd-MM-yyyy").format(date););
TextView sportTxtView = (TextView) view.findViewById(R.id.sportTxtView);
sportTxtView.setText(sport);
//I think you want to show the time here, not the date
TextView dateTxtView = (TextView) view.findViewById(R.id.dateTxtView);
dateTxtView.setText(new SimpleDateFormat("HH:mm:ss").format(date));
}
}
Edit: As for your comment in querying the attendances by date, check the edits I made in the structure above and then use a Firebase Query like
ref.child("members")
.child(<memberIdHere>)
.child("attendance")
.orderByChild("date")
.equalTo(<yourDateHere>);
Instead of using HashMap I would recommended to create another object like AttendedSport as variable inside MemberAttendance then Firebase will map the data for with out using HashMap inside populateView you could get data like
memberAttendance.getAttendedSport().getSport() and memberAttendance.getAttendedSport().getTimeStamp()
I'm not guarantee it would fix your problem but I think it is less error prone.

Sort List<Modal> with Custom Fild Object

I write a program that parse json and shows it in a listView.
Now i want to sort it but don't know how and fail. In program i have a List<PoolOfflineModal> alist = new ArrayList<>();
so modal are this;
public class PoolOfflineModal {
private int id;
private String name;
private int price;
private int priceWithoutDiscount;
private String tel;
private int discountPercent;
private String address;
private String photo;
}
and data simple is here http://hayat.cloudsite.ir/pools/pools.json
so i want to sort List ascending with price, so update ListView and i don't know...
another idea?! or solution?!
another way are exist to sort ListView from a column without sort list?!?
this is my last Comparator
public class MyComparator implements Comparator<PoolOfflineModal> {
#Override
public int compare(PoolOfflineModal lo, PoolOfflineModal ro) {
int result = 0;
if (way == "name") {
result = lo.getName().compareTo(ro.getName());
} else if (way == "price") {
result = lo.getPrice().compareTo(ro.getPrice());
} else if (way == "percent") {
result = lo.getDiscountPercent().compareTo(ro.getDiscountPercent());
}
return result;
}
}
List Object Like This:
List<PoolOfflineModal> alist = new ArrayList<>();
Comparator Class Like this:
public class MyComparator implements Comparator<PoolOfflineModal> {
#Override
public int compare(PoolOfflineModal o1, PoolOfflineModal o2) {
return o1.id.compareTo(o2.id);
}
}
Use Like this:
Collections.sort(alist, new MyComparator());
Hope it will helpful to you.

Update an object passed through Parcelable intent

I'm new to Android and i'm still learning. I currently have a ListView which allows you to click on an item. Clicking on an item will open a new intent displaying extra information about the item.
The thing i'm tripping up on is figuring out how to get the updated values back into my custom object and update the values in array at the correct index.
For example:
I'll add an item and set it's quantity to 2. This will appear in my ListView. Great. I decide i need 3 instead of 2, so i click the item to open the new activity, see 2 sitting in quantity, update it to 3 and hit save. On the save click i want to go back to my listview and have the updated quantity value displaying there and also updated in the array at the index.
Code for segments:
Onclick method for the listview in ItemList class
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
//#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
bean = (CustomObject) listview.getItemAtPosition(arg2);
Intent in1 = new Intent(Itemlist.this, SingleItem.class);
in1.putExtra("ActivityObject", bean);
startActivity(in1);
}
});
Adding an item the array in my ItemList class. this contain the listview.
else {
objects.add(new CustomObject(roomname.getText().toString() + " - " + resultSet.get(namecount), resultSet.get(partno), itemq, "$" + resultSet.get(rrpcol), resultSet.get(glcode), resultSet.get(desc)));
adapter.notifyDataSetChanged();
SingleItem class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_singleitem);
siname = (TextView) findViewById(R.id.siname);
sipartno = (TextView) findViewById(R.id.sipartno);
siquantity = (EditText) findViewById(R.id.siq);
sirrp = (EditText) findViewById(R.id.sirrp);
siglcode = (TextView) findViewById(R.id.siglcode);
sidesc = (EditText) findViewById(R.id.sidesc);
update = (Button) findViewById(R.id.siupdate);
Bundle b = getIntent().getExtras();
CustomObject itemInfo = b.getParcelable("ActivityObject");
siname.setText(itemInfo.getItemName());
sipartno.setText(itemInfo.getItemPartNo());
siquantity.setText(itemInfo.getItemQuantity());
sirrp.setText(itemInfo.getItemPrice());
siglcode.setText(itemInfo.getItemGLCode());
sidesc.setText(itemInfo.getItemDesc());
}
Custom Object class
public class CustomObject implements Parcelable {
private String itemName;
private String itemPartNo;
private String itemQuantity;
private String itemPrice;
private String itemGLCode;
private String itemDesc;
public CustomObject(Parcel source){
/*
* Reconstruct from the Parcel
*/
//Log.v(TAG, "ParcelData(Parcel source): time to put back parcel data");
//id = source.readInt();
itemName = source.readString();
itemPartNo = source.readString();
itemQuantity = source.readString();
itemPrice = source.readString();
itemGLCode = source.readString();
itemDesc = source.readString();
}
public CustomObject(String prop1, String prop2, String prop3, String prop4, String prop5, String prop6) {
this.itemName = prop1;
this.itemPartNo = prop2;
this.itemQuantity = prop3;
this.itemPrice = prop4;
this.itemGLCode = prop5;
this.itemDesc = prop6;
}
public String getItemName() {
return itemName;
}
public String getItemPartNo() { return itemPartNo; }
public String getItemQuantity() {
return itemQuantity;
}
public String getItemPrice() {
return itemPrice;
}
public String getItemGLCode() {return itemGLCode;}
public String getItemDesc() {return itemDesc;}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(itemName);
dest.writeString(itemPartNo);
dest.writeString(itemQuantity);
dest.writeString(itemPrice);
dest.writeString(itemGLCode);
dest.writeString(itemDesc);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public CustomObject createFromParcel(Parcel in) {
return new CustomObject(in);
}
public CustomObject[] newArray(int size) {
return new CustomObject[size];
}
};
}
I want to be able to change the quantity in the SingleItem class, click the Update button, and then have it load up the itemlist class with the updated values in the item list.
It'd be more efficient to use Fragments with your own callback interfaces defined for the activity. But, if you want to go the Activity approach, use startActivityForResult() and have your detail Activity send back a result Intent with any updates object contents.

Removing specific items from ListView on Android

I'm working on an application for Android that downloads RSS data from given URLs to a ListView where I can sort items in a number of ways (alphabetically, by date, by title etc.).
I'd like to be able to remove all items that were downloaded from a given URL.
Sorting changes original item positions, so I can't simply remove items by position.
Here I explain in detail how it's working:
In fragment A I have an EditText in which you type URLs.
Once you press ENTER:
the URL is passed on through an interface to fragment B where it uses the URL to download XML data and loads "item"s into it's ListView through an ArrayAdapter of 'item' class type.
fragment A has it's own ListView where it stores accepted URLs along with >delete< buttons next to them.
Each RSS item that's loaded into fragment's B ListView has unique title, link, and description, and publish date.
That means there are no common values in the loaded items.
I do download the "channel" part, which is the parent of all "item"s which were downloaded from the given URL, but I am not using it in the fragment's B adapter.
Here is the code for the POJO:
#Root(name = "rss", strict = false)
public class RSS {
#Element
private Channel channel;
#Attribute
private String version;
public Channel getChannel() {
return channel;
}
}
#Root(name = "channel", strict = false)
public class Channel {
#ElementList(name = "item", inline = true)
List<Article> articleList;
#Element
private String title;
#Element
private String link;
#Element
private String description;
// setters and getters
}
#Root(name = "item", strict = false)
public class Article {
#Element
private String title;
#Element
private String description;
#Element
private String link;
#Element(required = false)
private String author;
#Element(required = false)
private String pubDate;
// setters and getters
}
This is the URL class used for storing URLs in fragment A's ListView adapter.
public class URL {
private String url;
URL(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setUrl(String title) {
this.url = title;
}
}
Now, fragment B downloads the RSS object (called 'articles' here) and this is how I load the items to the other ListView adapter:
previewList = articles.getChannel().articleList;
adapter.addTop(previewList);
adapter.notifyDataSetChanged();
And finally, the Fragment B's ListView adapter:
public class ArticlePreviewAdapter extends ArrayAdapter<Article> {
List<Article> articlePreviewItems;
public ArticlePreviewAdapter(Activity activity, List<Article> articlePreviewItems) {
super(activity, R.layout.item_article_preview, articlePreviewItems);
this.articlePreviewItems = articlePreviewItems;
}
private static class ViewHolder {
TextView articlePreviewTitle;
TextView articlePreviewLink;
TextView articlePreviewDescription;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
Article articlePreviewItem = getItem(position);
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.item_article_preview, parent, false);
viewHolder.articlePreviewTitle = (TextView) convertView.findViewById(R.id.articleTitle);
viewHolder.articlePreviewLink = (TextView) convertView.findViewById(R.id.articleLink);
viewHolder.articlePreviewDescription = (TextView) convertView.findViewById(R.id.articleDescription);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.articlePreviewTitle.setText(articlePreviewItem.getTitle());
viewHolder.articlePreviewLink.setText(articlePreviewItem.getLink());
viewHolder.articlePreviewDescription.setText(articlePreviewItem.getDescription());
return convertView;
}
public void removeChannelItems(what do) {
what do?
}
public void addTop(List<Article> articles) {
articlePreviewItems.addAll(0, articles);
}
}
Thanks for help in advance.
If your Article object (or RSS, or Channel) can hold references to many URLs, you can implement the association like below (Article taken as example)
public class URL {
private String url;
private ArrayList<String> articleTitles;
public class URL(){
this.articleTitles = new ArrayList<String>();
}
public void setArticleTitles(String articleTitle){
this.articleTitle.add(articleTitle);
}
public ArrayList<String> getAarticleTitles(){
return this.articleTitles;
}
URL(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setUrl(String title) {
this.url = title;
}
}
Then you would have your URL reference your object. When you delete the URL, you remove all Articles from the respective adapter, finally calling notifyDataSetChanged(); on the adapter.

Categories

Resources