or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

buttons-and-selection.mdfeedback-and-communication.mdindex.mdinput-and-forms.mdlayout-and-containers.mdnavigation-components.mdpickers-and-selection.mdtheming-and-styling.md

feedback-and-communication.mddocs/

0

# Feedback and Communication

1

2

Components for user feedback, notifications, dialogs, progress indicators, and status communication.

3

4

## Core Imports

5

6

```java

7

import com.google.android.material.snackbar.Snackbar;

8

import com.google.android.material.snackbar.BaseTransientBottomBar;

9

import com.google.android.material.dialog.MaterialAlertDialogBuilder;

10

import com.google.android.material.progressindicator.CircularProgressIndicator;

11

import com.google.android.material.progressindicator.LinearProgressIndicator;

12

import com.google.android.material.progressindicator.BaseProgressIndicator;

13

import com.google.android.material.loadingindicator.LoadingIndicator;

14

import com.google.android.material.badge.BadgeDrawable;

15

import com.google.android.material.badge.BadgeUtils;

16

import com.google.android.material.tooltip.TooltipDrawable;

17

```

18

19

## Snackbar

20

21

Brief messages displayed at the bottom of the screen for user feedback.

22

23

```java { .api }

24

class Snackbar extends BaseTransientBottomBar<Snackbar> {

25

// Factory methods

26

static Snackbar make(View view, CharSequence text, int duration);

27

static Snackbar make(Context context, View view, CharSequence text, int duration);

28

29

// Action configuration

30

Snackbar setAction(CharSequence text, View.OnClickListener listener);

31

Snackbar setAction(@StringRes int resId, View.OnClickListener listener);

32

Snackbar setActionTextColor(@ColorInt int color);

33

Snackbar setActionTextColor(ColorStateList colors);

34

35

// Text configuration

36

Snackbar setText(CharSequence message);

37

Snackbar setText(@StringRes int resId);

38

Snackbar setTextColor(@ColorInt int color);

39

Snackbar setTextColor(ColorStateList colors);

40

Snackbar setTextMaxLines(int maxLines);

41

int getTextMaxLines();

42

43

// Background configuration

44

Snackbar setBackgroundTint(@ColorInt int color);

45

Snackbar setBackgroundTintList(ColorStateList colorStateList);

46

Snackbar setBackgroundTintMode(PorterDuff.Mode mode);

47

48

// Action width

49

Snackbar setMaxInlineActionWidth(@Dimension int width);

50

int getMaxInlineActionWidth();

51

52

// Display control

53

void show();

54

void dismiss();

55

boolean isShown();

56

boolean isShownOrQueued();

57

58

// Callbacks

59

Snackbar addCallback(BaseCallback<Snackbar> callback);

60

Snackbar removeCallback(BaseCallback<Snackbar> callback);

61

}

62

```

63

64

### Snackbar Duration Constants

65

66

```java { .api }

67

public static final int LENGTH_INDEFINITE = -2;

68

public static final int LENGTH_SHORT = -1;

69

public static final int LENGTH_LONG = 0;

70

```

71

72

### Usage Example

73

74

```java

75

// Simple snackbar

76

Snackbar.make(coordinatorLayout, "Item deleted", Snackbar.LENGTH_SHORT).show();

77

78

// Snackbar with action

79

Snackbar snackbar = Snackbar.make(coordinatorLayout, "Item deleted", Snackbar.LENGTH_LONG);

80

snackbar.setAction("UNDO", v -> {

81

// Restore deleted item

82

restoreItem();

83

});

84

snackbar.setActionTextColor(ContextCompat.getColor(this, R.color.accent_color));

85

snackbar.show();

86

87

// Customized snackbar

88

Snackbar customSnackbar = Snackbar.make(view, "Custom message", Snackbar.LENGTH_INDEFINITE);

89

customSnackbar.setText("Network error occurred");

90

customSnackbar.setTextColor(Color.WHITE);

91

customSnackbar.setBackgroundTint(ContextCompat.getColor(this, R.color.error_color));

92

customSnackbar.setAction("RETRY", v -> {

93

// Retry action

94

retryNetworkRequest();

95

});

96

customSnackbar.show();

97

98

// Snackbar with callback

99

snackbar.addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {

100

@Override

101

public void onShown(Snackbar transientBottomBar) {

102

// Snackbar is now visible

103

}

104

105

@Override

106

public void onDismissed(Snackbar transientBottomBar, int event) {

107

switch (event) {

108

case DISMISS_EVENT_TIMEOUT:

109

// Dismissed due to timeout

110

break;

111

case DISMISS_EVENT_ACTION:

112

// Dismissed due to action click

113

break;

114

case DISMISS_EVENT_SWIPE:

115

// Dismissed by swipe

116

break;

117

}

118

}

119

});

120

```

121

122

## Base Transient Bottom Bar

123

124

Base class for transient bottom bars like Snackbar.

125

126

```java { .api }

127

abstract class BaseTransientBottomBar<B extends BaseTransientBottomBar<B>> {

128

// Animation mode

129

B setAnimationMode(int animationMode);

130

int getAnimationMode();

131

132

// Anchor view

133

B setAnchorView(View anchorView);

134

View getAnchorView();

135

136

// Gesture insets

137

B setGestureInsetBottomIgnored(boolean gestureInsetBottomIgnored);

138

boolean isGestureInsetBottomIgnored();

139

140

// Callbacks

141

B addCallback(BaseCallback<B> callback);

142

B removeCallback(BaseCallback<B> callback);

143

144

// Display control

145

void show();

146

void dismiss();

147

boolean isShown();

148

boolean isShownOrQueued();

149

150

// Properties

151

int getDuration();

152

View getView();

153

Context getContext();

154

}

155

156

abstract class BaseTransientBottomBar.BaseCallback<B> {

157

void onShown(B transientBottomBar);

158

void onDismissed(B transientBottomBar, int event);

159

160

// Dismiss event constants

161

public static final int DISMISS_EVENT_SWIPE = 0;

162

public static final int DISMISS_EVENT_ACTION = 1;

163

public static final int DISMISS_EVENT_TIMEOUT = 2;

164

public static final int DISMISS_EVENT_MANUAL = 3;

165

public static final int DISMISS_EVENT_CONSECUTIVE = 4;

166

}

167

```

168

169

### Animation Mode Constants

170

171

```java { .api }

172

public static final int ANIMATION_MODE_SLIDE = 0;

173

public static final int ANIMATION_MODE_FADE = 1;

174

```

175

176

## Material Alert Dialog Builder

177

178

Builder for creating Material Design alert dialogs.

179

180

```java { .api }

181

class MaterialAlertDialogBuilder extends AlertDialog.Builder {

182

MaterialAlertDialogBuilder(Context context);

183

MaterialAlertDialogBuilder(Context context, int overrideThemeResId);

184

185

// Background configuration

186

MaterialAlertDialogBuilder setBackground(Drawable background);

187

MaterialAlertDialogBuilder setBackgroundInsetStart(@Dimension int backgroundInsetStart);

188

MaterialAlertDialogBuilder setBackgroundInsetTop(@Dimension int backgroundInsetTop);

189

MaterialAlertDialogBuilder setBackgroundInsetEnd(@Dimension int backgroundInsetEnd);

190

MaterialAlertDialogBuilder setBackgroundInsetBottom(@Dimension int backgroundInsetBottom);

191

}

192

```

193

194

### Usage Example

195

196

```java

197

// Simple alert dialog

198

new MaterialAlertDialogBuilder(this)

199

.setTitle("Delete item?")

200

.setMessage("This action cannot be undone.")

201

.setPositiveButton("Delete", (dialog, which) -> {

202

// Handle delete

203

deleteItem();

204

})

205

.setNegativeButton("Cancel", null)

206

.show();

207

208

// Dialog with custom styling

209

MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);

210

builder.setTitle("Confirm Action")

211

.setMessage("Are you sure you want to proceed?")

212

.setIcon(R.drawable.ic_warning)

213

.setPositiveButton("Yes", (dialog, which) -> {

214

// Handle confirmation

215

})

216

.setNegativeButton("No", null)

217

.setNeutralButton("Learn More", (dialog, which) -> {

218

// Show more info

219

});

220

221

AlertDialog dialog = builder.create();

222

dialog.show();

223

224

// Single choice dialog

225

String[] options = {"Option 1", "Option 2", "Option 3"};

226

new MaterialAlertDialogBuilder(this)

227

.setTitle("Choose an option")

228

.setSingleChoiceItems(options, selectedIndex, (dialog, which) -> {

229

selectedIndex = which;

230

})

231

.setPositiveButton("OK", (dialog, which) -> {

232

// Handle selection

233

processSelection(selectedIndex);

234

})

235

.setNegativeButton("Cancel", null)

236

.show();

237

238

// Multi-choice dialog

239

boolean[] checkedItems = {false, true, false};

240

new MaterialAlertDialogBuilder(this)

241

.setTitle("Select items")

242

.setMultiChoiceItems(options, checkedItems, (dialog, which, isChecked) -> {

243

checkedItems[which] = isChecked;

244

})

245

.setPositiveButton("OK", (dialog, which) -> {

246

// Handle multiple selections

247

processMultipleSelections(checkedItems);

248

})

249

.setNegativeButton("Cancel", null)

250

.show();

251

```

252

253

## Progress Indicators

254

255

Material Design progress indicators for showing loading states and progress.

256

257

### Base Progress Indicator

258

259

```java { .api }

260

abstract class BaseProgressIndicator<S> extends ProgressBar {

261

// Show/hide animation

262

void setShowAnimationBehavior(int showAnimationBehavior);

263

int getShowAnimationBehavior();

264

void setHideAnimationBehavior(int hideAnimationBehavior);

265

int getHideAnimationBehavior();

266

267

// Colors

268

void setIndicatorColor(@ColorInt int... colors);

269

void setIndicatorColor(@NonNull int[] colors);

270

int[] getIndicatorColor();

271

void setTrackColor(@ColorInt int trackColor);

272

int getTrackColor();

273

void setTrackCornerRadius(int trackCornerRadius);

274

int getTrackCornerRadius();

275

276

// Visibility control

277

void show();

278

void hide();

279

boolean isShown();

280

void setVisibilityAfterHide(int visibility);

281

int getVisibilityAfterHide();

282

}

283

```

284

285

### Animation Behavior Constants

286

287

```java { .api }

288

public static final int SHOW_NONE = 0;

289

public static final int SHOW_OUTWARD = 1;

290

public static final int SHOW_INWARD = 2;

291

292

public static final int HIDE_NONE = 0;

293

public static final int HIDE_OUTWARD = 1;

294

public static final int HIDE_INWARD = 2;

295

public static final int HIDE_ESCAPE = 3;

296

```

297

298

### Circular Progress Indicator

299

300

```java { .api }

301

class CircularProgressIndicator extends BaseProgressIndicator<CircularProgressIndicatorSpec> {

302

CircularProgressIndicator(Context context);

303

CircularProgressIndicator(Context context, AttributeSet attrs);

304

305

// Size configuration

306

void setIndicatorSize(int indicatorSize);

307

int getIndicatorSize();

308

void setTrackThickness(int trackThickness);

309

int getTrackThickness();

310

void setIndicatorInset(int indicatorInset);

311

int getIndicatorInset();

312

313

// Direction

314

void setIndicatorDirection(int indicatorDirection);

315

int getIndicatorDirection();

316

}

317

```

318

319

### Linear Progress Indicator

320

321

```java { .api }

322

class LinearProgressIndicator extends BaseProgressIndicator<LinearProgressIndicatorSpec> {

323

LinearProgressIndicator(Context context);

324

LinearProgressIndicator(Context context, AttributeSet attrs);

325

326

// Track thickness

327

void setTrackThickness(int trackThickness);

328

int getTrackThickness();

329

330

// Direction

331

void setIndicatorDirection(int indicatorDirection);

332

int getIndicatorDirection();

333

}

334

```

335

336

### Progress Direction Constants

337

338

```java { .api }

339

// Circular progress

340

public static final int INDICATOR_DIRECTION_CLOCKWISE = 0;

341

public static final int INDICATOR_DIRECTION_COUNTERCLOCKWISE = 1;

342

343

// Linear progress

344

public static final int INDICATOR_DIRECTION_LEFT_TO_RIGHT = 0;

345

public static final int INDICATOR_DIRECTION_RIGHT_TO_LEFT = 1;

346

```

347

348

### Usage Example

349

350

```java

351

// Determinate circular progress

352

CircularProgressIndicator circularProgress = findViewById(R.id.circular_progress);

353

circularProgress.setProgress(0);

354

circularProgress.setMax(100);

355

356

// Animate progress

357

ValueAnimator animator = ValueAnimator.ofInt(0, 75);

358

animator.setDuration(2000);

359

animator.addUpdateListener(animation -> {

360

int progress = (int) animation.getAnimatedValue();

361

circularProgress.setProgress(progress);

362

});

363

animator.start();

364

365

// Indeterminate linear progress with custom colors

366

LinearProgressIndicator linearProgress = findViewById(R.id.linear_progress);

367

linearProgress.setIndeterminate(true);

368

linearProgress.setIndicatorColor(

369

ContextCompat.getColor(this, R.color.primary),

370

ContextCompat.getColor(this, R.color.secondary)

371

);

372

373

// Show/hide with animation

374

linearProgress.setShowAnimationBehavior(BaseProgressIndicator.SHOW_INWARD);

375

linearProgress.setHideAnimationBehavior(BaseProgressIndicator.HIDE_OUTWARD);

376

linearProgress.show();

377

378

// Hide after delay

379

new Handler().postDelayed(() -> {

380

linearProgress.hide();

381

}, 3000);

382

383

// Progress with custom appearance

384

CircularProgressIndicator customProgress = findViewById(R.id.custom_progress);

385

customProgress.setIndicatorSize(64);

386

customProgress.setTrackThickness(8);

387

customProgress.setIndicatorDirection(CircularProgressIndicator.INDICATOR_DIRECTION_COUNTERCLOCKWISE);

388

```

389

390

## Loading Indicator

391

392

Material Design loading indicator component with show/hide delay capabilities.

393

394

```java { .api }

395

public class LoadingIndicator extends View {

396

public LoadingIndicator(Context context);

397

public LoadingIndicator(Context context, AttributeSet attrs);

398

399

// Visibility control

400

public void show();

401

public void hide();

402

403

// Indicator appearance

404

public void setIndicatorSize(@Px int indicatorSize);

405

public int getIndicatorSize();

406

public void setIndicatorColor(@ColorInt int... indicatorColors);

407

public int[] getIndicatorColor();

408

409

// Container dimensions

410

public void setContainerWidth(@Px int containerWidth);

411

public int getContainerWidth();

412

public void setContainerHeight(@Px int containerHeight);

413

public int getContainerHeight();

414

public void setContainerColor(@ColorInt int containerColor);

415

public int getContainerColor();

416

}

417

```

418

419

**Usage Example:**

420

421

```java

422

LoadingIndicator loadingIndicator = findViewById(R.id.loading_indicator);

423

424

// Configure appearance

425

loadingIndicator.setIndicatorSize(48);

426

loadingIndicator.setContainerWidth(100);

427

loadingIndicator.setContainerHeight(100);

428

loadingIndicator.setIndicatorColor(

429

ContextCompat.getColor(this, R.color.primary),

430

ContextCompat.getColor(this, R.color.secondary),

431

ContextCompat.getColor(this, R.color.tertiary)

432

);

433

434

// Show loading indicator

435

loadingIndicator.show();

436

437

// Hide after operation completes

438

performLongRunningOperation(() -> {

439

loadingIndicator.hide();

440

});

441

```

442

443

## Badge Drawable

444

445

Drawable for displaying notification badges with numbers or text.

446

447

```java { .api }

448

class BadgeDrawable extends Drawable {

449

// Factory methods

450

static BadgeDrawable create(Context context);

451

static BadgeDrawable createFromResource(Context context, @XmlRes int id);

452

453

// Number badge

454

void setNumber(int number);

455

int getNumber();

456

void clearNumber();

457

boolean hasNumber();

458

void setMaxCharacterCount(int maxCharacterCount);

459

int getMaxCharacterCount();

460

461

// Text badge

462

void setText(String text);

463

String getText();

464

void clearText();

465

boolean hasText();

466

467

// Colors

468

void setBackgroundColor(@ColorInt int backgroundColor);

469

int getBackgroundColor();

470

void setBadgeTextColor(@ColorInt int badgeTextColor);

471

int getBadgeTextColor();

472

473

// Visibility

474

boolean isVisible();

475

void setVisible(boolean visible);

476

477

// Additional configuration methods for positioning, etc.

478

}

479

```

480

481

### Badge Utils

482

483

```java { .api }

484

class BadgeUtils {

485

static void attachBadgeDrawable(BadgeDrawable badgeDrawable, View anchor);

486

static void attachBadgeDrawable(BadgeDrawable badgeDrawable, View anchor, FrameLayout customBadgeParent);

487

static void detachBadgeDrawable(BadgeDrawable badgeDrawable, View anchor);

488

static void setBadgeDrawableBounds(BadgeDrawable badgeDrawable, View anchor, FrameLayout customBadgeParent);

489

}

490

```

491

492

### Usage Example

493

494

```java

495

// Create and attach badge to view

496

ImageView notificationIcon = findViewById(R.id.notification_icon);

497

BadgeDrawable badge = BadgeDrawable.create(this);

498

badge.setNumber(5);

499

badge.setBackgroundColor(ContextCompat.getColor(this, R.color.red));

500

badge.setBadgeTextColor(Color.WHITE);

501

BadgeUtils.attachBadgeDrawable(badge, notificationIcon);

502

503

// Update badge count

504

badge.setNumber(badge.getNumber() + 1);

505

506

// Text badge

507

BadgeDrawable textBadge = BadgeDrawable.create(this);

508

textBadge.setText("NEW");

509

textBadge.setVisible(true);

510

511

// Hide badge

512

badge.setVisible(false);

513

514

// Clear badge

515

badge.clearNumber();

516

BadgeUtils.detachBadgeDrawable(badge, notificationIcon);

517

518

// Badge with navigation components

519

BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation);

520

BadgeDrawable navBadge = bottomNav.getOrCreateBadge(R.id.nav_messages);

521

navBadge.setNumber(3);

522

navBadge.setVisible(true);

523

524

// Remove navigation badge

525

bottomNav.removeBadge(R.id.nav_messages);

526

```

527

528

## Tooltip Drawable

529

530

Drawable for creating Material Design tooltips.

531

532

```java { .api }

533

class TooltipDrawable extends Drawable {

534

// Factory methods

535

static TooltipDrawable create(Context context);

536

static TooltipDrawable createFromAttributes(Context context, AttributeSet attrs);

537

static TooltipDrawable createFromAttributes(Context context, AttributeSet attrs, @AttrRes int defStyleAttr);

538

static TooltipDrawable createFromAttributes(Context context, AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes);

539

540

// Text content

541

void setText(CharSequence text);

542

CharSequence getText();

543

void setTextAppearance(@StyleRes int textAppearanceResId);

544

TextAppearance getTextAppearance();

545

void setTextColor(@ColorInt int textColor);

546

547

// Positioning

548

void setTooltipPivotX(float tooltipPivotX);

549

float getTooltipPivotX();

550

void setTooltipPivotY(float tooltipPivotY);

551

float getTooltipPivotY();

552

553

// Layout

554

void setLayoutMargin(int layoutMargin);

555

int getLayoutMargin();

556

void setMinWidth(int minWidth);

557

int getMinWidth();

558

void setMinHeight(int minHeight);

559

int getMinHeight();

560

561

// Arrow

562

void setArrowSize(int arrowSize);

563

int getArrowSize();

564

565

// Corner radius

566

void setCornerRadius(float cornerRadius);

567

float getCornerRadius();

568

569

// Background

570

void setBackgroundTint(ColorStateList backgroundTint);

571

572

// View attachment

573

void setRelativeToView(View view);

574

void detachView(View view);

575

}

576

```

577

578

### Usage Example

579

580

```java

581

// Create tooltip for a view

582

MaterialButton helpButton = findViewById(R.id.help_button);

583

TooltipDrawable tooltip = TooltipDrawable.create(this);

584

tooltip.setText("This button provides help information");

585

tooltip.setBackgroundTint(ColorStateList.valueOf(ContextCompat.getColor(this, R.color.tooltip_bg)));

586

587

// Show tooltip on long click

588

helpButton.setOnLongClickListener(v -> {

589

showTooltip(v, tooltip);

590

return true;

591

});

592

593

// Custom tooltip appearance

594

TooltipDrawable customTooltip = TooltipDrawable.create(this);

595

customTooltip.setText("Custom styled tooltip");

596

customTooltip.setCornerRadius(8f);

597

customTooltip.setArrowSize(16);

598

customTooltip.setMinWidth(200);

599

customTooltip.setTextColor(Color.WHITE);

600

```

601

602

## Loading and Error States Example

603

604

Complete example showing various feedback patterns:

605

606

```java

607

public class FeedbackExampleActivity extends AppCompatActivity {

608

private LinearProgressIndicator progressBar;

609

private MaterialButton loadDataButton;

610

private MaterialButton showErrorButton;

611

private TextView statusText;

612

private CoordinatorLayout coordinatorLayout;

613

614

@Override

615

protected void onCreate(Bundle savedInstanceState) {

616

super.onCreate(savedInstanceState);

617

setContentView(R.layout.activity_feedback_example);

618

619

initViews();

620

setupClickListeners();

621

}

622

623

private void initViews() {

624

progressBar = findViewById(R.id.progress_bar);

625

loadDataButton = findViewById(R.id.load_data_button);

626

showErrorButton = findViewById(R.id.show_error_button);

627

statusText = findViewById(R.id.status_text);

628

coordinatorLayout = findViewById(R.id.coordinator_layout);

629

630

// Configure progress bar

631

progressBar.setIndicatorColor(

632

ContextCompat.getColor(this, R.color.primary),

633

ContextCompat.getColor(this, R.color.secondary)

634

);

635

progressBar.setShowAnimationBehavior(BaseProgressIndicator.SHOW_INWARD);

636

progressBar.setHideAnimationBehavior(BaseProgressIndicator.HIDE_OUTWARD);

637

}

638

639

private void setupClickListeners() {

640

loadDataButton.setOnClickListener(v -> simulateDataLoading());

641

showErrorButton.setOnClickListener(v -> showErrorDialog());

642

}

643

644

private void simulateDataLoading() {

645

// Show loading state

646

progressBar.show();

647

loadDataButton.setEnabled(false);

648

statusText.setText("Loading data...");

649

650

// Simulate network request

651

new Handler().postDelayed(() -> {

652

// Hide loading and show success

653

progressBar.hide();

654

loadDataButton.setEnabled(true);

655

statusText.setText("Data loaded successfully");

656

657

// Show success snackbar

658

Snackbar.make(coordinatorLayout, "Data loaded successfully", Snackbar.LENGTH_SHORT)

659

.setBackgroundTint(ContextCompat.getColor(this, R.color.success))

660

.show();

661

}, 2000);

662

}

663

664

private void showErrorDialog() {

665

new MaterialAlertDialogBuilder(this)

666

.setTitle("Network Error")

667

.setMessage("Failed to connect to the server. Please check your internet connection and try again.")

668

.setIcon(R.drawable.ic_error)

669

.setPositiveButton("Retry", (dialog, which) -> {

670

// Retry action

671

simulateDataLoading();

672

})

673

.setNegativeButton("Cancel", null)

674

.setNeutralButton("Settings", (dialog, which) -> {

675

// Open network settings

676

openNetworkSettings();

677

})

678

.show();

679

}

680

681

private void showNetworkErrorSnackbar() {

682

Snackbar errorSnackbar = Snackbar.make(coordinatorLayout,

683

"Network error occurred", Snackbar.LENGTH_INDEFINITE);

684

errorSnackbar.setAction("RETRY", v -> simulateDataLoading());

685

errorSnackbar.setActionTextColor(ContextCompat.getColor(this, R.color.accent));

686

errorSnackbar.setBackgroundTint(ContextCompat.getColor(this, R.color.error));

687

errorSnackbar.show();

688

}

689

690

private void showProgressWithCallback() {

691

CircularProgressIndicator progressIndicator = findViewById(R.id.circular_progress);

692

693

// Simulate determinate progress

694

progressIndicator.setProgress(0);

695

progressIndicator.setMax(100);

696

progressIndicator.show();

697

698

ValueAnimator progressAnimator = ValueAnimator.ofInt(0, 100);

699

progressAnimator.setDuration(3000);

700

progressAnimator.addUpdateListener(animation -> {

701

int progress = (int) animation.getAnimatedValue();

702

progressIndicator.setProgress(progress);

703

704

if (progress == 100) {

705

// Hide progress when complete

706

new Handler().postDelayed(() -> {

707

progressIndicator.hide();

708

showCompletionFeedback();

709

}, 500);

710

}

711

});

712

progressAnimator.start();

713

}

714

715

private void showCompletionFeedback() {

716

// Show completion badge

717

ImageView completionIcon = findViewById(R.id.completion_icon);

718

BadgeDrawable completionBadge = BadgeDrawable.create(this);

719

completionBadge.setText("✓");

720

completionBadge.setBackgroundColor(ContextCompat.getColor(this, R.color.success));

721

completionBadge.setBadgeTextColor(Color.WHITE);

722

BadgeUtils.attachBadgeDrawable(completionBadge, completionIcon);

723

724

// Auto-hide badge after delay

725

new Handler().postDelayed(() -> {

726

BadgeUtils.detachBadgeDrawable(completionBadge, completionIcon);

727

}, 2000);

728

}

729

}

730

```