Skip to content

Commit 0c5aab9

Browse files
committed
1. Cleanup
2. Added support for detach view
1 parent 37143d1 commit 0c5aab9

11 files changed

+154
-65
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ chatContainer.setViewAdapter(new ChatHeadViewAdapter() {
3636
}
3737

3838
@Override
39-
public Fragment createView(Object key, ChatHead chatHead) {
39+
public Fragment attachView(Object key, ChatHead chatHead) {
4040
// return the fragment which should be shown when the arrangment switches to maximized (on clicking a chat head)
4141
// you can use the key parameter to get back the object you passed in the addChatHead method.
4242
// this key should be used to decide which fragment to show.

demo/src/main/java/com/flipkart/springyheads/demo/ChatHeadService.java

+43-17
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,20 @@
2525
import com.flipkart.circularImageView.TextDrawer;
2626
import com.flipkart.circularImageView.notification.CircularNotificationDrawer;
2727

28+
import java.io.Serializable;
2829
import java.util.HashMap;
2930
import java.util.Map;
3031
import java.util.Random;
3132

3233
public class ChatHeadService extends Service {
3334

35+
// Binder given to clients
36+
private final IBinder mBinder = new LocalBinder();
3437
private DefaultChatHeadManager<String> chatHeadManager;
3538
private int chatHeadIdentifier = 0;
3639
private WindowManagerContainer windowManagerContainer;
3740
private Map<String, View> viewCache = new HashMap<>();
38-
// Binder given to clients
39-
private final IBinder mBinder = new LocalBinder();
40-
4141

42-
/**
43-
* Class used for the client Binder. Because we know this service always
44-
* runs in the same process as its clients, we don't need to deal with IPC.
45-
*/
46-
public class LocalBinder extends Binder {
47-
ChatHeadService getService() {
48-
// Return this instance of LocalService so clients can call public methods
49-
return ChatHeadService.this;
50-
}
51-
}
5242

5343
@Override
5444
public IBinder onBind(Intent intent) {
@@ -64,7 +54,7 @@ public void onCreate() {
6454
chatHeadManager.setViewAdapter(new ChatHeadViewAdapter<String>() {
6555

6656
@Override
67-
public View createView(String key, ChatHead chatHead, ViewGroup parent) {
57+
public View attachView(String key, ChatHead chatHead, ViewGroup parent) {
6858
View cachedView = viewCache.get(key);
6959
if (cachedView == null) {
7060
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
@@ -74,9 +64,27 @@ public View createView(String key, ChatHead chatHead, ViewGroup parent) {
7464
cachedView = view;
7565
viewCache.put(key, view);
7666
}
67+
parent.addView(cachedView);
7768
return cachedView;
7869
}
7970

71+
@Override
72+
public void detachView(String key, ChatHead<? extends Serializable> chatHead, ViewGroup parent) {
73+
View cachedView = viewCache.get(key);
74+
if(cachedView!=null) {
75+
parent.removeView(cachedView);
76+
}
77+
}
78+
79+
@Override
80+
public void removeView(String key, ChatHead<? extends Serializable> chatHead, ViewGroup parent) {
81+
View cachedView = viewCache.get(key);
82+
if(cachedView!=null) {
83+
viewCache.remove(key);
84+
parent.removeView(cachedView);
85+
}
86+
}
87+
8088
@Override
8189
public Drawable getChatHeadDrawable(String key) {
8290
return ChatHeadService.this.getChatHeadDrawable(key);
@@ -92,7 +100,6 @@ public Drawable getChatHeadDrawable(String key) {
92100

93101
}
94102

95-
96103
private Drawable getChatHeadDrawable(String key) {
97104
Random rnd = new Random();
98105
int randomColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
@@ -119,14 +126,14 @@ private void moveToForeground() {
119126
public void addChatHead() {
120127
chatHeadIdentifier++;
121128
chatHeadManager.addChatHead(String.valueOf(chatHeadIdentifier), false, true);
129+
chatHeadManager.bringToFront(chatHeadManager.findChatHeadByKey(String.valueOf(chatHeadIdentifier)));
122130
}
123131

124132
public void removeChatHead() {
125-
chatHeadIdentifier--;
126133
chatHeadManager.removeChatHead(String.valueOf(chatHeadIdentifier), true);
134+
chatHeadIdentifier--;
127135
}
128136

129-
130137
public void removeAllChatHeads() {
131138
chatHeadIdentifier = 0;
132139
chatHeadManager.removeAllChatHeads(true);
@@ -140,9 +147,28 @@ public void toggleArrangement() {
140147
}
141148
}
142149

150+
public void updateBadgeCount() {
151+
chatHeadManager.reloadDrawable(String.valueOf(chatHeadIdentifier));
152+
}
153+
143154
@Override
144155
public void onDestroy() {
145156
super.onDestroy();
146157
windowManagerContainer.destroy();
147158
}
159+
160+
public void minimize() {
161+
chatHeadManager.setArrangement(MinimizedArrangement.class,null);
162+
}
163+
164+
/**
165+
* Class used for the client Binder. Because we know this service always
166+
* runs in the same process as its clients, we don't need to deal with IPC.
167+
*/
168+
public class LocalBinder extends Binder {
169+
ChatHeadService getService() {
170+
// Return this instance of LocalService so clients can call public methods
171+
return ChatHeadService.this;
172+
}
173+
}
148174
}

demo/src/main/java/com/flipkart/springyheads/demo/FloatingActivity.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class FloatingActivity extends Activity implements View.OnClickListener {
2020
private Button removeButton;
2121
private Button removeAllButtons;
2222
private Button toggleButton;
23+
private Button updateBadgeCount;
2324

2425
private ChatHeadService chatHeadService;
2526
private boolean bound;
@@ -35,6 +36,7 @@ public void onServiceConnected(ComponentName className,
3536
ChatHeadService.LocalBinder binder = (ChatHeadService.LocalBinder) service;
3637
chatHeadService = binder.getService();
3738
bound = true;
39+
chatHeadService.minimize();
3840
}
3941

4042
@Override
@@ -59,11 +61,13 @@ private void setupButtons() {
5961
removeButton = (Button) findViewById(R.id.remove_head);
6062
removeAllButtons = (Button) findViewById(R.id.remove_all_heads);
6163
toggleButton = (Button) findViewById(R.id.toggle_arrangement);
64+
updateBadgeCount = (Button) findViewById(R.id.update_badge_count);
6265

6366
addButton.setOnClickListener(this);
6467
removeButton.setOnClickListener(this);
6568
removeAllButtons.setOnClickListener(this);
6669
toggleButton.setOnClickListener(this);
70+
updateBadgeCount.setOnClickListener(this);
6771
}
6872

6973

@@ -72,17 +76,18 @@ public void onClick(View v) {
7276
if (bound) {
7377
if (v == addButton) {
7478
chatHeadService.addChatHead();
75-
7679
} else if (v == removeButton) {
7780
chatHeadService.removeChatHead();
78-
7981
} else if (v == removeAllButtons) {
8082
chatHeadService.removeAllChatHeads();
8183
} else if (v == toggleButton) {
8284
chatHeadService.toggleArrangement();
85+
} else if (v == updateBadgeCount) {
86+
chatHeadService.updateBadgeCount();
8387
}
8488
} else {
8589
Toast.makeText(this, "Service not bound", Toast.LENGTH_SHORT).show();
8690
}
8791
}
92+
8893
}

demo/src/main/res/layout/activity_main.xml

+7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@
3333
android:layout_width="wrap_content"
3434
android:layout_height="wrap_content"
3535
android:text="Toggle arrangement" />
36+
37+
<Button
38+
android:id="@+id/update_badge_count"
39+
android:layout_width="wrap_content"
40+
android:layout_height="wrap_content"
41+
android:text="Update badge count" />
42+
3643
</LinearLayout>
3744

3845

library/src/main/java/com/flipkart/chatheads/ui/ChatHeadCloseButton.java

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import com.facebook.rebound.SpringUtil;
1515
import com.flipkart.chatheads.R;
1616

17+
import java.io.Serializable;
18+
1719
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
1820
public class ChatHeadCloseButton extends ImageView {
1921

library/src/main/java/com/flipkart/chatheads/ui/ChatHeadManager.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ public interface ChatHeadManager<T extends Serializable> {
4343
void selectChatHead(ChatHead chatHead);
4444

4545
void selectChatHead(T key);
46+
4647
/**
4748
* Should be called when measuring of the container is done.
4849
* Typically called from onMeasure or onLayout
4950
* Only when {@link ChatHeadContainer#getContainerHeight()} && {@link ChatHeadContainer#getContainerWidth()} returns a positive value will arrangements start working
51+
*
5052
* @param height
5153
* @param width
5254
*/
@@ -105,11 +107,11 @@ public interface ChatHeadManager<T extends Serializable> {
105107

106108
SpringSystem getSpringSystem();
107109

108-
View addView(ChatHead<T> activeChatHead, ViewGroup parent);
110+
View attachView(ChatHead<T> activeChatHead, ViewGroup parent);
109111

110-
View removeView(ChatHead chatHead);
112+
void detachView(ChatHead<T> chatHead, ViewGroup parent);
111113

112-
View detachView(ChatHead chatHead);
114+
void removeView(ChatHead<T> chatHead, ViewGroup parent);
113115

114116
ChatHeadConfig getConfig();
115117

Original file line numberDiff line numberDiff line change
@@ -1,29 +1,39 @@
11
package com.flipkart.chatheads.ui;
22

33
import android.graphics.drawable.Drawable;
4-
import android.support.v4.app.Fragment;
5-
import android.support.v4.app.FragmentManager;
64
import android.view.View;
75
import android.view.ViewGroup;
86

97
import java.io.Serializable;
108

119
/**
12-
* Created by kirankumar on 16/02/15.
10+
* An adapter to provide views. Inspired by {@link android.support.v4.view.PagerAdapter}
1311
*/
1412
public interface ChatHeadViewAdapter<T> {
1513

1614
/**
17-
* Based on the key, this should instantiate and return a View. This View will be removed when the chathead is removed.
15+
* Based on the key, this should instantiate and return a View. This view will be shown once {@link MaximizedArrangement} is activated.. Make sure you have added the view into the specified parent ViewGroup.
16+
* Cache the view so that you can either detach it or remove it later.
1817
*/
19-
public View createView(T key, ChatHead<? extends Serializable> chatHead, ViewGroup parent);
18+
View attachView(T key, ChatHead<? extends Serializable> chatHead, ViewGroup parent);
2019

2120
/**
22-
* Should return the view used to represent a chat "head". Typically a rounded imageview.
23-
* @param key
24-
* @return
21+
* This will be called when the view has to be temporarily detached. {@link #attachView(Object, ChatHead, ViewGroup)} will be called if view has to be reattached.
22+
* You would typically remove the view from parent here, but wont reclaim resources yet.
23+
* If a chat head is removed, this method will be called followed by {@link #removeView(Object, ChatHead, ViewGroup)}
2524
*/
26-
public Drawable getChatHeadDrawable(T key);
25+
void detachView(T key, ChatHead<? extends Serializable> chatHead, ViewGroup parent);
2726

2827

28+
/**
29+
* This will be called when a chat head has been removed forever. In this callback you can reclaim any resources you have allocated for this chat head.
30+
* Also make sure you remove the view you returned from {@link #attachView(Object, ChatHead, ViewGroup)} from the specified parent.
31+
*/
32+
void removeView(T key, ChatHead<? extends Serializable> chatHead, ViewGroup parent);
33+
34+
/**
35+
* Should return the view used to represent a chat "head". Typically a rounded imageview. Use {@link ChatHeadManager#reloadDrawable(Serializable)} if you want to reload.
36+
*/
37+
Drawable getChatHeadDrawable(T key);
38+
2939
}

library/src/main/java/com/flipkart/chatheads/ui/MaximizedArrangement.java

+23-13
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ public void onClick(View v) {
100100
});
101101
container.showOverlayView(animated);
102102
selectChatHead(currentChatHead);
103-
currentChatHead.getVerticalSpring().addListener(new SimpleSpringListener()
104-
{
103+
currentChatHead.getVerticalSpring().addListener(new SimpleSpringListener() {
105104
@Override
106105
public void onSpringAtRest(Spring spring) {
107106
super.onSpringAtRest(spring);
@@ -111,8 +110,7 @@ public void onSpringAtRest(Spring spring) {
111110
currentChatHead.getVerticalSpring().removeListener(this);
112111
}
113112
});
114-
currentChatHead.getHorizontalSpring().addListener(new SimpleSpringListener()
115-
{
113+
currentChatHead.getHorizontalSpring().addListener(new SimpleSpringListener() {
116114
@Override
117115
public void onSpringAtRest(Spring spring) {
118116
super.onSpringAtRest(spring);
@@ -129,7 +127,7 @@ public void onSpringAtRest(Spring spring) {
129127
@Override
130128
public void onDeactivate(int maxWidth, int maxHeight) {
131129
if (currentChatHead != null) {
132-
manager.detachView(currentChatHead);
130+
manager.detachView(currentChatHead, getArrowLayout());
133131
}
134132
hideView();
135133
manager.hideOverlayView(true);
@@ -172,9 +170,16 @@ public boolean handleTouchUp(ChatHead activeChatHead, int xVelocity, int yVeloci
172170
}
173171

174172
private void selectTab(final ChatHead<T> activeChatHead) {
175-
currentChatHead = activeChatHead;
176-
showOrHideView(activeChatHead);
173+
if (currentChatHead != activeChatHead) {
174+
detach(currentChatHead);
175+
currentChatHead = activeChatHead;
176+
}
177177
pointTo(activeChatHead);
178+
showOrHideView(activeChatHead);
179+
}
180+
181+
private void detach(ChatHead chatHead) {
182+
manager.detachView(chatHead, getArrowLayout());
178183
}
179184

180185
private void positionToOriginal(ChatHead activeChatHead, Spring activeHorizontalSpring, Spring activeVerticalSpring) {
@@ -248,7 +253,7 @@ public void onSpringUpdate(ChatHead activeChatHead, boolean isDragging, int maxW
248253
activeVerticalSpring.setSpringConfig(SpringConfigsHolder.NOT_DRAGGING);
249254
activeChatHead.setState(ChatHead.State.CAPTURED);
250255
}
251-
if (activeChatHead.getState() == ChatHead.State.CAPTURED && activeHorizontalSpring.getSpringConfig()!= SpringConfigsHolder.CAPTURING) {
256+
if (activeChatHead.getState() == ChatHead.State.CAPTURED && activeHorizontalSpring.getSpringConfig() != SpringConfigsHolder.CAPTURING) {
252257
activeHorizontalSpring.setAtRest();
253258
activeVerticalSpring.setAtRest();
254259
activeHorizontalSpring.setSpringConfig(SpringConfigsHolder.CAPTURING);
@@ -314,16 +319,17 @@ private void showView(ChatHead activeChatHead, double dx, double dy, double dist
314319
}
315320

316321
public static void sendViewToBack(final View child) {
317-
final ViewGroup parent = (ViewGroup)child.getParent();
318-
if (null != parent && parent.indexOfChild(child)!=0) {
322+
final ViewGroup parent = (ViewGroup) child.getParent();
323+
if (null != parent && parent.indexOfChild(child) != 0) {
319324
parent.removeView(child);
320325
parent.addView(child, 0);
321326
}
322327
}
328+
323329
private void pointTo(ChatHead<T> activeChatHead) {
324330
UpArrowLayout arrowLayout = getArrowLayout();
325331
getArrowLayout().removeAllViews();
326-
manager.addView(activeChatHead, arrowLayout);
332+
manager.attachView(activeChatHead, arrowLayout);
327333
sendViewToBack(manager.getOverlayView());
328334
Point point = positions.get(activeChatHead);
329335
if (point != null) {
@@ -346,7 +352,8 @@ public void onChatHeadAdded(final ChatHead chatHead, final boolean animated) {
346352

347353
@Override
348354
public void onChatHeadRemoved(ChatHead removed) {
349-
manager.removeView(removed);
355+
manager.detachView(removed, getArrowLayout());
356+
manager.removeView(removed, getArrowLayout());
350357
positions.remove(removed);
351358
boolean isEmpty = false;
352359
if (currentChatHead == removed) {
@@ -394,6 +401,9 @@ private ChatHead getNextBestChatHead() {
394401

395402
private Bundle getBundleWithHero() {
396403
Bundle bundle = extras;
404+
if (bundle == null) {
405+
bundle = new Bundle();
406+
}
397407
bundle.putInt(MinimizedArrangement.BUNDLE_HERO_INDEX_KEY, getHeroIndex());
398408
return bundle;
399409
}
@@ -457,7 +467,7 @@ public void bringToFront(final ChatHead chatHead) {
457467
@Override
458468
public void onReloadFragment(ChatHead chatHead) {
459469
if (currentChatHead != null && chatHead == currentChatHead) {
460-
manager.addView(chatHead, getArrowLayout());
470+
manager.attachView(chatHead, getArrowLayout());
461471
}
462472
}
463473

0 commit comments

Comments
 (0)