Skip to content

Commit

Permalink
Finish FamilyTreeActivity
Browse files Browse the repository at this point in the history
  • Loading branch information
teinvdlugt committed May 22, 2016
1 parent b05be0f commit c2641d2
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/* Greek Gods: an Android application which shows the family tree of the Greek Gods.
* Copyright (C) 2016 Tein van der Lugt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.teinvdlugt.android.greekgods;

import android.annotation.SuppressLint;
Expand All @@ -18,7 +34,7 @@
import java.util.ArrayList;
import java.util.List;

public class FamilyTreeActivity extends AppCompatActivity implements FamilyTreeLayout.OnPersonClickListener {
public class FamilyTreeActivity extends AppCompatActivity implements FamilyTreeLayout2.OnPersonClickListener {
public static final String PERSON_ID_EXTRA = "personId";

private FamilyTreeLayout2 treeLayout;
Expand All @@ -35,18 +51,18 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
int personId = getIntent().getIntExtra(PERSON_ID_EXTRA, 64);

treeLayout = (FamilyTreeLayout2) findViewById(R.id.family_tree_layout);
//treeLayout.setOnPersonClickListener(this);
treeLayout.setOnPersonClickListener(this);
loadPerson(personId);
}

@Override
public void onClickPerson(Person person) {
/*if (person.getId() == treeLayout.getPerson().getId()) {
if (person.getId() == treeLayout.getPerson().getId()) {
InfoActivity.openActivity(this, person.getId(), Info.INFO_TYPE_PERSON);
} else {
backStack.add(treeLayout.getPerson().getId());
loadPerson(person.getId());
}*/
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
/* Greek Gods: an Android application which shows the family tree of the Greek Gods.
* Copyright (C) 2016 Tein van der Lugt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.teinvdlugt.android.greekgods;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.teinvdlugt.android.greekgods.models.Person;

Expand All @@ -17,51 +34,72 @@
public class FamilyTreeLayout2 extends ViewGroup {
public FamilyTreeLayout2(Context context) {
super(context);
init();
}

public FamilyTreeLayout2(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public FamilyTreeLayout2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

private void init() {
setWillNotDraw(false);
childRelationPaint = new Paint();
childRelationPaint.setStrokeWidth(3);
childRelationPaint.setColor(Color.BLACK);
marriageRelationPaint = new Paint();
marriageRelationPaint.setStrokeWidth(3);
marriageRelationPaint.setColor(Color.RED);
public interface OnPersonClickListener {
void onClickPerson(Person person);
}

private Person person;
private int startX, startY;
private Paint childRelationPaint, marriageRelationPaint;
private float prevTouchX, prevTouchY;
private OnPersonClickListener onPersonClickListener;

public void setOnPersonClickListener(OnPersonClickListener onPersonClickListener) {
this.onPersonClickListener = onPersonClickListener;
}

public Person getPerson() {
return person;
}

public void setPerson(Person person) {
this.person = person;
calculateTree();
invalidate();
requestLayout();
}

@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (people == null || people.isEmpty()) return;
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
removeAllViewsInLayout();
for (Person person : people.keySet()) {

for (final Person person : people.keySet()) {
Rect personRect = people.get(person);

if (personRect.intersects(l + startX, t + startY, r + startX, b + startY)) {
FamilyTreeNode view = new FamilyTreeNode(getContext());
view.setPerson(person);
addView(view);
view.layout(personRect.left - startX, personRect.top - startY,
View familyTreeNode = inflater.inflate(R.layout.family_tree_node, null, false);
((TextView) familyTreeNode.findViewById(R.id.name_textView)).setText(person.getName());
((TextView) familyTreeNode.findViewById(R.id.shortDescription_textView)).setText(person.getShortDescription());
familyTreeNode.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onPersonClickListener != null)
onPersonClickListener.onClickPerson(person);
}
});

addView(familyTreeNode);

familyTreeNode.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
familyTreeNode.layout(personRect.left - startX, personRect.top - startY,
personRect.right - startX, personRect.bottom - startY);
}
}
}

private float prevTouchX, prevTouchY;

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
Expand All @@ -81,39 +119,13 @@ public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (relations == null || relations.isEmpty()) return;
for (Person[] persons : relations.keySet()) {
Rect person1 = people.get(persons[0]);
Rect person2 = people.get(persons[1]);
int p1X = (person1.right - person1.left) / 2 - startX;
int p1Y = (person1.bottom - person1.top) / 2 - startY;
int p2X = (person2.right - person2.left) / 2 - startX;
int p2Y = (person2.bottom - person2.top) / 2 - startY;
canvas.drawLine(p1X, p1Y, p2X, p2Y,
relations.get(persons) == RELATION_TYPE_MARRIAGE ? marriageRelationPaint : childRelationPaint);
}
}

public void setPerson(Person person) {
this.person = person;
calculateTree();
invalidate();
requestLayout();
}

private Map<Person, Rect> people;
private Map<Person[], Integer> relations;
private static final int RELATION_TYPE_MARRIAGE = 0;
private static final int RELATION_TYPE_CHILD = 1;
private int minRelationDistance = 50;
private static final int minRelationDistance = 50;

private void calculateTree() {
people = new HashMap<>();
relations = new HashMap<>();
FamilyTreeNode dummy = new FamilyTreeNode(getContext());
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View dummy = inflater.inflate(R.layout.family_tree_node, null, false);

Rect personRect = createPersonRect(person, 0, 0, dummy);
people.put(person, personRect);
Expand All @@ -130,30 +142,45 @@ private void calculateTree() {
Person parent = person.getParents().get(i);
Rect rect = createPersonRect(parent, left, top, dummy);
people.put(parent, rect);
relations.put(new Person[]{parent, person}, RELATION_TYPE_CHILD);
for (int j = 0; j < person.getParents().size(); j++) {
if (i != j)
relations.put(new Person[]{parent, person.getParents().get(j)}, RELATION_TYPE_MARRIAGE);
}
left = rect.right + minRelationDistance;
}
}

if (person.getChildren() != null && !person.getChildren().isEmpty()) {
int totalWidth = 0;
for (Person child : person.getChildren()) {
measureDummy(child, dummy);
totalWidth += dummy.getMeasuredWidth();
}
totalWidth += (person.getChildren().size() - 1) * minRelationDistance;
int top = personRect.bottom + minRelationDistance;
int left = -totalWidth / 2 + personRect.width() / 2;
for (int i = 0; i < person.getChildren().size(); i++) {
Person child = person.getChildren().get(i);
Rect rect = createPersonRect(child, left, top, dummy);
people.put(child, rect);
left = rect.right + minRelationDistance;
}
}
}

private void measureDummy(Person person, FamilyTreeNode dummy) {
dummy.setPerson(person);
private void measureDummy(Person person, View dummy) {
((TextView) dummy.findViewById(R.id.name_textView)).setText(person.getName());

TextView shortDescriptionTV = (TextView) dummy.findViewById(R.id.shortDescription_textView);
if (person.getShortDescription() == null || person.getShortDescription().isEmpty())
shortDescriptionTV.setVisibility(View.GONE);
else {
shortDescriptionTV.setVisibility(View.VISIBLE);
shortDescriptionTV.setText(person.getShortDescription());
}

dummy.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
}

private Rect createPersonRect(Person person, int left, int top, FamilyTreeNode dummy) {
private Rect createPersonRect(Person person, int left, int top, View dummy) {
measureDummy(person, dummy);
return new Rect(left, top, left + dummy.getMeasuredWidth(), top + dummy.getMeasuredHeight());
}

public static class PersonConstructor {
public static Person constructPerson(int personId) {
return new Person();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ private void init(Context context) {
addView(content);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setPerson(person);
}

public FamilyTreeNode(Context context) {
super(context);
init(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,7 @@ public class Person {
private List<Person> parents;
private int id;

public Person(int id, String name) {
this.id = id;
this.name = name;
}

public Person() {
}
public Person() {}

public Person(int id) {
this.id = id;
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/res/layout/family_tree_node.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">

<TextView
android:id="@+id/name_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="18sp" />

<TextView
android:id="@+id/shortDescription_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp" />
</LinearLayout>
</android.support.v7.widget.CardView>

0 comments on commit c2641d2

Please sign in to comment.