Skip to content

Commit d0f37a6

Browse files
committed
Custom toolbar buttons for feed post form
1 parent 25386a1 commit d0f37a6

File tree

6 files changed

+809
-8
lines changed

6 files changed

+809
-8
lines changed
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
package com.fastcomments;
2+
3+
import android.os.Bundle;
4+
import android.view.View;
5+
import android.widget.Toast;
6+
7+
import androidx.activity.result.ActivityResultLauncher;
8+
import androidx.activity.result.contract.ActivityResultContracts;
9+
import androidx.appcompat.app.AppCompatActivity;
10+
import androidx.constraintlayout.widget.ConstraintLayout;
11+
import androidx.constraintlayout.widget.ConstraintSet;
12+
13+
import com.fastcomments.core.CommentWidgetConfig;
14+
import com.fastcomments.core.sso.FastCommentsSSO;
15+
import com.fastcomments.core.sso.SimpleSSOUserData;
16+
import com.fastcomments.model.FeedPost;
17+
import com.fastcomments.sdk.CommentsDialog;
18+
import com.fastcomments.sdk.FastCommentsFeedSDK;
19+
import com.fastcomments.sdk.FastCommentsFeedView;
20+
import com.fastcomments.sdk.FeedPostCreateView;
21+
import com.fastcomments.sdk.OnUserClickListener;
22+
import com.fastcomments.sdk.UserClickSource;
23+
import com.fastcomments.sdk.examples.GifPickerFeedToolbarButton;
24+
import com.google.android.material.floatingactionbutton.FloatingActionButton;
25+
26+
import java.util.List;
27+
28+
/**
29+
* Activity demonstrating custom toolbar buttons for feed post creation.
30+
* This example shows how to add global custom toolbar buttons to the feed SDK
31+
* which will appear on all FeedPostCreateView instances.
32+
*
33+
* Features demonstrated:
34+
* - How to add global custom toolbar buttons to FastCommentsFeedSDK
35+
* - How toolbar buttons automatically appear in FeedPostCreateView
36+
* - Example GIF picker button implementation
37+
* - Best practices for custom button integration
38+
*/
39+
public class FeedExampleCustomButtonsActivity extends AppCompatActivity {
40+
41+
private FastCommentsFeedView feedView;
42+
private FastCommentsFeedSDK feedSDK;
43+
private FeedPostCreateView postCreateView;
44+
private FloatingActionButton createPostFab;
45+
private OnUserClickListener userClickListener;
46+
47+
// Image picker launcher
48+
private final ActivityResultLauncher<String> pickImageLauncher =
49+
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
50+
if (uri != null && postCreateView != null) {
51+
postCreateView.handleImageResult(uri);
52+
}
53+
});
54+
55+
@Override
56+
protected void onCreate(Bundle savedInstanceState) {
57+
super.onCreate(savedInstanceState);
58+
setContentView(R.layout.activity_example_feed);
59+
60+
// Create a configuration for the SDK
61+
CommentWidgetConfig config = new CommentWidgetConfig();
62+
config.tenantId = "demo"; // Use your tenant ID here
63+
config.urlId = "https://example.com/toolbar-demo"; // Different URL to avoid conflicts
64+
config.pageTitle = "Feed Toolbar Demo";
65+
66+
// Set up Simple SSO for user authentication
67+
SimpleSSOUserData userData = new SimpleSSOUserData(
68+
"Toolbar Demo User",
69+
70+
"https://staticm.fastcomments.com/1639362726066-DSC_0841.JPG");
71+
72+
FastCommentsSSO sso = new FastCommentsSSO(userData);
73+
config.sso = sso.prepareToSend();
74+
75+
// Initialize the Feed SDK
76+
feedSDK = new FastCommentsFeedSDK(config);
77+
78+
// Add global custom toolbar buttons to the SDK
79+
// These buttons will automatically appear in all FeedPostCreateView instances
80+
setupGlobalToolbarButtons();
81+
82+
// Find the feed view in the layout
83+
feedView = findViewById(R.id.feedView);
84+
85+
// Set the SDK instance for the view
86+
feedView.setSDK(feedSDK);
87+
88+
feedView.setTagSupplier(currentUser -> {
89+
// Return null to get a "global" feed for this demo
90+
return null;
91+
});
92+
93+
// Create and add the FeedPostCreateView
94+
setupPostCreationView();
95+
96+
setupUserClickListener();
97+
98+
// Set interaction listener
99+
feedView.setFeedViewInteractionListener(new FastCommentsFeedView.OnFeedViewInteractionListener() {
100+
@Override
101+
public void onFeedLoaded(List<FeedPost> posts) {
102+
// Feed loaded successfully
103+
}
104+
105+
@Override
106+
public void onFeedError(String errorMessage) {
107+
// Error loading feed
108+
Toast.makeText(FeedExampleCustomButtonsActivity.this, errorMessage, Toast.LENGTH_SHORT).show();
109+
}
110+
111+
@Override
112+
public void onPostSelected(FeedPost post) {
113+
// User selected a post
114+
}
115+
116+
@Override
117+
public void onCommentsRequested(FeedPost post) {
118+
// Show comments dialog for the post from the SDK
119+
CommentsDialog dialog = new CommentsDialog(FeedExampleCustomButtonsActivity.this, post, feedSDK);
120+
121+
// Set comment added listener to update the post in the feed
122+
dialog.setOnCommentAddedListener(postId -> {
123+
// Post stats already updated in feedSDK, just need to refresh UI
124+
runOnUiThread(() -> {
125+
// Find position of post in adapter and update it
126+
feedView.refreshPost(postId);
127+
});
128+
});
129+
130+
dialog.setOnUserClickListener(userClickListener);
131+
132+
dialog.show();
133+
}
134+
});
135+
136+
feedView.setOnUserClickListener(userClickListener);
137+
138+
// Load the feed
139+
feedView.load();
140+
}
141+
142+
/**
143+
* Set up global custom toolbar buttons that will appear in all FeedPostCreateView instances.
144+
* This demonstrates how to configure custom buttons at the SDK level.
145+
*/
146+
private void setupGlobalToolbarButtons() {
147+
// Add a GIF picker button that will appear in the feed post creation toolbar
148+
// This button demonstrates how custom toolbar buttons work in the feed context
149+
feedSDK.addGlobalFeedToolbarButton(new GifPickerFeedToolbarButton());
150+
151+
// You could add additional custom buttons here:
152+
// feedSDK.addGlobalFeedToolbarButton(new CustomEmojiPickerFeedToolbarButton());
153+
// feedSDK.addGlobalFeedToolbarButton(new MentionFeedToolbarButton());
154+
// feedSDK.addGlobalFeedToolbarButton(new CustomFormattingFeedToolbarButton());
155+
}
156+
157+
private void setupUserClickListener() {
158+
userClickListener = (context, userInfo, source) -> {
159+
String sourceText = source == UserClickSource.NAME ? "name" : "avatar";
160+
String contextText = context.isComment() ? "comment" : "feed post";
161+
Toast.makeText(FeedExampleCustomButtonsActivity.this,
162+
"Clicked " + userInfo.getDisplayName() + "'s " + sourceText + " in " + contextText,
163+
Toast.LENGTH_SHORT).show();
164+
};
165+
}
166+
167+
/**
168+
* Set up the post creation view and floating action button.
169+
* The FeedPostCreateView will automatically include all global toolbar buttons
170+
* added to the SDK via addGlobalFeedToolbarButton().
171+
*/
172+
private void setupPostCreationView() {
173+
// Get the parent ConstraintLayout
174+
final ConstraintLayout parentLayout = findViewById(R.id.feedParentLayout);
175+
176+
// Create the post creation view
177+
postCreateView = new FeedPostCreateView(this);
178+
postCreateView.setId(View.generateViewId());
179+
180+
// Setting the SDK will automatically add all global toolbar buttons
181+
postCreateView.setSDK(feedSDK);
182+
postCreateView.setVisibility(View.GONE);
183+
184+
// Create constraints for post creation view (full width at top, floating above content)
185+
ConstraintLayout.LayoutParams postCreateParams = new ConstraintLayout.LayoutParams(
186+
ConstraintLayout.LayoutParams.MATCH_PARENT,
187+
ConstraintLayout.LayoutParams.WRAP_CONTENT);
188+
postCreateView.setLayoutParams(postCreateParams);
189+
postCreateView.setElevation(16f); // Elevate above other content
190+
191+
// Add view to parent
192+
parentLayout.addView(postCreateView);
193+
194+
// Update constraints to position the view at the top
195+
ConstraintSet initialConstraintSet = new ConstraintSet();
196+
initialConstraintSet.clone(parentLayout);
197+
initialConstraintSet.connect(postCreateView.getId(), ConstraintSet.TOP, parentLayout.getId(), ConstraintSet.TOP, 0);
198+
initialConstraintSet.connect(postCreateView.getId(), ConstraintSet.START, parentLayout.getId(), ConstraintSet.START, 0);
199+
initialConstraintSet.connect(postCreateView.getId(), ConstraintSet.END, parentLayout.getId(), ConstraintSet.END, 0);
200+
initialConstraintSet.applyTo(parentLayout);
201+
202+
// Create FAB
203+
createPostFab = new FloatingActionButton(this);
204+
createPostFab.setId(View.generateViewId());
205+
createPostFab.setImageResource(android.R.drawable.ic_input_add);
206+
createPostFab.setContentDescription(getString(R.string.create_new_post));
207+
208+
// Create params for FAB
209+
ConstraintLayout.LayoutParams fabParams = new ConstraintLayout.LayoutParams(
210+
ConstraintLayout.LayoutParams.WRAP_CONTENT,
211+
ConstraintLayout.LayoutParams.WRAP_CONTENT);
212+
createPostFab.setLayoutParams(fabParams);
213+
214+
// Add FAB to parent
215+
parentLayout.addView(createPostFab);
216+
217+
// Update constraints to position the FAB at bottom-end
218+
ConstraintSet fabConstraintSet = new ConstraintSet();
219+
fabConstraintSet.clone(parentLayout);
220+
fabConstraintSet.connect(createPostFab.getId(), ConstraintSet.BOTTOM, parentLayout.getId(), ConstraintSet.BOTTOM, 32);
221+
fabConstraintSet.connect(createPostFab.getId(), ConstraintSet.END, parentLayout.getId(), ConstraintSet.END, 32);
222+
fabConstraintSet.applyTo(parentLayout);
223+
224+
// Set FAB click listener
225+
createPostFab.setOnClickListener(v -> {
226+
// Configure post creation view and prepare it for showing
227+
postCreateView.show();
228+
createPostFab.setVisibility(View.GONE);
229+
230+
// Apply animation to slide it down
231+
postCreateView.startAnimation(android.view.animation.AnimationUtils.loadAnimation(
232+
FeedExampleCustomButtonsActivity.this, com.fastcomments.sdk.R.anim.slide_down_from_top));
233+
});
234+
235+
// Set post creation listener
236+
postCreateView.setOnPostCreateListener(new FeedPostCreateView.OnPostCreateListener() {
237+
@Override
238+
public void onPostCreated(FeedPost post) {
239+
// Use our new slide up and fade animation
240+
android.view.animation.Animation slideUpFade = android.view.animation.AnimationUtils.loadAnimation(
241+
FeedExampleCustomButtonsActivity.this, com.fastcomments.sdk.R.anim.slide_up_and_fade);
242+
243+
slideUpFade.setAnimationListener(new android.view.animation.Animation.AnimationListener() {
244+
@Override
245+
public void onAnimationStart(android.view.animation.Animation animation) {
246+
// No need to change visibility yet
247+
}
248+
249+
@Override
250+
public void onAnimationEnd(android.view.animation.Animation animation) {
251+
// Make form completely gone and unclickable
252+
postCreateView.clearAnimation();
253+
postCreateView.setVisibility(View.GONE);
254+
postCreateView.setClickable(false);
255+
postCreateView.setEnabled(false);
256+
257+
// Show FAB button
258+
createPostFab.setVisibility(View.VISIBLE);
259+
260+
// Refresh the feed to show the new post
261+
feedView.refresh();
262+
}
263+
264+
@Override
265+
public void onAnimationRepeat(android.view.animation.Animation animation) {}
266+
});
267+
268+
postCreateView.startAnimation(slideUpFade);
269+
270+
// Refresh the feed to show the new post
271+
feedView.refresh();
272+
}
273+
274+
@Override
275+
public void onPostCreateError(String errorMessage) {
276+
Toast.makeText(FeedExampleCustomButtonsActivity.this, errorMessage, Toast.LENGTH_SHORT).show();
277+
}
278+
279+
@Override
280+
public void onPostCreateCancelled() {
281+
// Use our new slide up and fade animation
282+
android.view.animation.Animation slideUpFade = android.view.animation.AnimationUtils.loadAnimation(
283+
FeedExampleCustomButtonsActivity.this, com.fastcomments.sdk.R.anim.slide_up_and_fade);
284+
285+
slideUpFade.setAnimationListener(new android.view.animation.Animation.AnimationListener() {
286+
@Override
287+
public void onAnimationStart(android.view.animation.Animation animation) {
288+
// No need to change visibility yet
289+
}
290+
291+
@Override
292+
public void onAnimationEnd(android.view.animation.Animation animation) {
293+
// Make form completely gone and unclickable
294+
postCreateView.clearAnimation();
295+
postCreateView.setVisibility(View.GONE);
296+
postCreateView.setClickable(false);
297+
postCreateView.setEnabled(false);
298+
299+
// Show FAB button
300+
createPostFab.setVisibility(View.VISIBLE);
301+
}
302+
303+
@Override
304+
public void onAnimationRepeat(android.view.animation.Animation animation) {}
305+
});
306+
307+
postCreateView.startAnimation(slideUpFade);
308+
}
309+
310+
@Override
311+
public void onImagePickerRequested() {
312+
// Launch image picker
313+
pickImageLauncher.launch("image/*");
314+
}
315+
});
316+
}
317+
318+
@Override
319+
protected void onDestroy() {
320+
super.onDestroy();
321+
// Clean up the feed view to prevent memory leaks
322+
if (feedView != null) {
323+
feedView.cleanup();
324+
}
325+
}
326+
}

libraries/sdk/src/main/java/com/fastcomments/sdk/FastCommentsFeedSDK.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public class FastCommentsFeedSDK {
8484
private String urlIdWS;
8585
private String userIdWS;
8686
private TagSupplier tagSupplier;
87+
private final List<FeedCustomToolbarButton> globalFeedToolbarButtons = new ArrayList<>(0);
8788

8889
/**
8990
* Constructs a FastCommentsFeedSDK instance with the given configuration
@@ -1387,4 +1388,44 @@ public void onDownloadProgress(long bytesRead, long contentLength, boolean done)
13871388
CallbackWrapper.handleAPIException(mainHandler, callback, e);
13881389
}
13891390
}
1391+
1392+
/**
1393+
* Add a global feed toolbar button that will be applied to all FeedPostCreateView instances
1394+
*
1395+
* @param button The toolbar button to add
1396+
*/
1397+
public void addGlobalFeedToolbarButton(FeedCustomToolbarButton button) {
1398+
if (button != null && !globalFeedToolbarButtons.contains(button)) {
1399+
globalFeedToolbarButtons.add(button);
1400+
}
1401+
}
1402+
1403+
/**
1404+
* Remove a global feed toolbar button by its ID
1405+
*
1406+
* @param buttonId The ID of the button to remove
1407+
* @return true if a button was removed, false otherwise
1408+
*/
1409+
public boolean removeGlobalFeedToolbarButton(String buttonId) {
1410+
if (buttonId == null) {
1411+
return false;
1412+
}
1413+
return globalFeedToolbarButtons.removeIf(button -> buttonId.equals(button.getId()));
1414+
}
1415+
1416+
/**
1417+
* Clear all global feed toolbar buttons
1418+
*/
1419+
public void clearGlobalFeedToolbarButtons() {
1420+
globalFeedToolbarButtons.clear();
1421+
}
1422+
1423+
/**
1424+
* Get a copy of the current global feed toolbar buttons
1425+
*
1426+
* @return List of global feed toolbar buttons
1427+
*/
1428+
public List<FeedCustomToolbarButton> getGlobalFeedToolbarButtons() {
1429+
return new ArrayList<>(globalFeedToolbarButtons);
1430+
}
13901431
}

0 commit comments

Comments
 (0)