Skip to content

Commit

Permalink
feat: Allow to capture screenshots of modal Dialogs (PR #221 from den…
Browse files Browse the repository at this point in the history
…nisdeng2002/dialog-screenshot)
  • Loading branch information
rm3l authored Mar 24, 2021
2 parents 9a1ae57 + 9990908 commit 50fb3ca
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.rm3l.maoni.sample.ui

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.floatingactionbutton.FloatingActionButton
import org.rm3l.maoni.Maoni
import org.rm3l.maoni.sample.R
import org.rm3l.maoni.sample.utils.MaoniUtils

class MaoniBottomSheetDialogFragment : BottomSheetDialogFragment() {

private var maoni: Maoni? = null

override fun getTheme(): Int = R.style.RoundedBottomSheetDialog

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(
R.layout.bottom_sheet_dialog_fragment_maoni,
container,
false
)

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<FloatingActionButton>(R.id.fab)
?.setOnClickListener {
maoni = MaoniUtils.buildMaoni(requireContext())
maoni?.start(dialog)
}
}

override fun onDestroy() {
super.onDestroy()
maoni?.clear()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,29 @@

package org.rm3l.maoni.sample.ui;

import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.mikepenz.aboutlibraries.Libs;
import com.mikepenz.aboutlibraries.LibsBuilder;

import org.rm3l.maoni.Maoni;
import org.rm3l.maoni.common.contract.Handler;
import org.rm3l.maoni.sample.R;
import org.rm3l.maoni.sample.extensions.ContextUtils;
import org.rm3l.maoni.sample.utils.MaoniUtils;

public class MaoniSampleMainActivity extends AppCompatActivity {

Expand All @@ -56,31 +61,11 @@ protected void onCreate(Bundle savedInstanceState) {
setSupportActionBar(toolbar);
}

final Handler handlerForMaoni = ContextUtils.getMaoniFeedbackHandler(this); //Custom handler for Maoni, which does nothing more than calling any of the maoni-* available callbacks
final Maoni.Builder maoniBuilder = ContextUtils.getMaoniFeedbackBuilder(this);
final FloatingActionButton fab = findViewById(R.id.fab);
if (fab != null) {
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// MaoniActivity de-registers handlers, listeners and validators upon activity destroy,
// so we need to re-register it again by reconstructing a new Maoni instance.
//Also, Maoni.start(...) cannot be called twice,
// but we are reusing the Builder to construct a new instance along with its handler.
//
//Note that if no handler/listener is specified,
//Maoni will fall back to opening an Email Intent, so your users can send
//their feedback via email
final SharedPreferences defaultSharedPreferences =
PreferenceManager.getDefaultSharedPreferences(MaoniSampleMainActivity.this);
mMaoni = maoniBuilder
.withScreenCapturingFeature(defaultSharedPreferences
.getBoolean("maoni_screen_capturing_enabled", true))
.withLogsCapturingFeature(defaultSharedPreferences
.getBoolean("maoni_logs_capturing_enabled", true))
.withHandler(handlerForMaoni).build();
mMaoni.start(MaoniSampleMainActivity.this);
}
fab.setOnClickListener(view -> {
mMaoni = MaoniUtils.buildMaoni(this);
mMaoni.start(MaoniSampleMainActivity.this);
});
}
}
Expand Down Expand Up @@ -115,6 +100,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
//start the activity
.start(this);

} else if (itemId == R.id.bottom_sheet) {
MaoniBottomSheetDialogFragment fragment = new MaoniBottomSheetDialogFragment();
fragment.show(getSupportFragmentManager(), "MaoniBottomSheetDialogFragment");
}
return super.onOptionsItemSelected(item);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.rm3l.maoni.sample.utils

import android.content.Context
import android.preference.PreferenceManager
import org.rm3l.maoni.Maoni
import org.rm3l.maoni.common.contract.Handler
import org.rm3l.maoni.sample.extensions.getMaoniFeedbackBuilder
import org.rm3l.maoni.sample.extensions.getMaoniFeedbackHandler

object MaoniUtils {

@JvmStatic
fun buildMaoni(context: Context): Maoni {
val handlerForMaoni: Handler = context.getMaoniFeedbackHandler() //Custom handler for Maoni, which does nothing more than calling any of the maoni-* available callbacks
val maoniBuilder: Maoni.Builder = context.getMaoniFeedbackBuilder()
// MaoniActivity de-registers handlers, listeners and validators upon activity destroy,
// so we need to re-register it again by reconstructing a new Maoni instance.
// Also, Maoni.start(...) cannot be called twice,
// but we are reusing the Builder to construct a new instance along with its handler.
//
//Note that if no handler/listener is specified,
//Maoni will fall back to opening an Email Intent, so your users can send
//their feedback via email
// MaoniActivity de-registers handlers, listeners and validators upon activity destroy,
// so we need to re-register it again by reconstructing a new Maoni instance.
// Also, Maoni.start(...) cannot be called twice,
// but we are reusing the Builder to construct a new instance along with its handler.
//
//Note that if no handler/listener is specified,
//Maoni will fall back to opening an Email Intent, so your users can send
//their feedback via email
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
return maoniBuilder
.withScreenCapturingFeature(defaultSharedPreferences
.getBoolean("maoni_screen_capturing_enabled", true))
.withLogsCapturingFeature(defaultSharedPreferences
.getBoolean("maoni_logs_capturing_enabled", true))
.withHandler(handlerForMaoni).build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="@string/main_activity_text"
android:textAppearance="?android:textAppearanceLarge"
android:textColor="@color/white" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_feedback_white_24dp"
app:tint="@color/white" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
9 changes: 7 additions & 2 deletions maoni-sample/src/main/res/menu/menu_maoni_sample.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ SOFTWARE.
tools:context=".ui.MaoniSampleMainActivity">
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_maoni_sample_settings_white_24dp"
android:orderInCategory="1"
android:title="@string/action_settings"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_maoni_sample_settings_white_24dp"/>
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_about"
android:orderInCategory="100"
android:title="@string/action_about"
app:showAsAction="never" />
<item
android:id="@+id/bottom_sheet"
android:orderInCategory="101"
android:title="@string/action_bottom_sheet"
app:showAsAction="never" />
</menu>
1 change: 1 addition & 0 deletions maoni-sample/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@ SOFTWARE.
<string name="how_to_send_feedback">How would you like to send your feedback?</string>

<string name="action_settings">Settings</string>
<string name="action_bottom_sheet">Bottom Sheet</string>
</resources>
17 changes: 17 additions & 0 deletions maoni-sample/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,21 @@ SOFTWARE.

<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

<style name="RoundedBottomSheetDialog" parent="@style/ThemeOverlay.MaterialComponents.BottomSheetDialog">
<item name="bottomSheetStyle">@style/RoundedBottomSheetDialogStyle</item>
</style>

<style name="RoundedBottomSheetDialogStyle" parent="Widget.MaterialComponents.BottomSheet">
<item name="shapeAppearanceOverlay">@style/RoundedBottomSheetDialogShapeOverlay</item>
<item name="backgroundTint">@color/maoni_black</item>
</style>

<style name="RoundedBottomSheetDialogShapeOverlay" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSizeTopRight">16dp</item>
<item name="cornerSizeTopLeft">16dp</item>
<item name="cornerSizeBottomRight">0dp</item>
<item name="cornerSizeBottomLeft">0dp</item>
</style>

</resources>
28 changes: 25 additions & 3 deletions maoni/src/main/java/org/rm3l/maoni/Maoni.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import android.view.Window;

import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
Expand Down Expand Up @@ -224,12 +226,33 @@ private Maoni(final Builder builder) {
}

/**
* Start the Maoni Activity
* Start the Maoni Activity. If screenCapturingFeatureEnabled is true this will take a
* screenshot of the activity window
*
* @param callerActivity the caller activity
*/
public void start(@Nullable final Activity callerActivity) {
start(callerActivity, callerActivity.getWindow());
}

/**
* Start the Maoni Activity. If screenCapturingFeatureEnabled is true this will take a
* screenshot of the dialog window
*
* @param dialog the caller dialog
*/
public void start(@Nullable Dialog dialog) {
Activity activity = ContextUtils.scanForActivity(dialog.getContext());
start(activity, dialog.getWindow());
}

/**
* Internal helper method used to start MaoniActivity
*
* @param callerActivity activity context
* @param window window for screen (if enabled)
*/
private void start(Activity callerActivity, Window window) {
if (mUsed.getAndSet(true)) {
this.clear();
throw new UnsupportedOperationException(
Expand Down Expand Up @@ -292,7 +315,7 @@ public void start(@Nullable final Activity callerActivity) {
//Create screenshot file
final File screenshotFile = new File(maoniWorkingDir != null ? maoniWorkingDir : callerActivity.getCacheDir(),
MAONI_FEEDBACK_SCREENSHOT_FILENAME);
ViewUtils.exportViewToFile(callerActivity, callerActivity.getWindow().getDecorView(),
ViewUtils.exportViewToFile(callerActivity, window.getDecorView(),
screenshotFile);
maoniIntent.putExtra(SCREENSHOT_FILE, screenshotFile.getAbsolutePath());

Expand Down Expand Up @@ -363,7 +386,6 @@ public void start(@Nullable final Activity callerActivity) {
callerActivity.startActivity(maoniIntent);
}


public Maoni unregisterListener() {
getInstance(context).setListener(null);
return this;
Expand Down
15 changes: 13 additions & 2 deletions maoni/src/main/java/org/rm3l/maoni/utils/ContextUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
*/
package org.rm3l.maoni.utils;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -53,8 +55,17 @@ public static Object getBuildConfigValue(@NonNull final Context context,
.getField(fieldName)
.get(null);
} catch (final Exception e) {
//No worries
e.printStackTrace();
return null;
}
}

@Nullable
public static Activity scanForActivity(@NonNull final Context context) {
if (context instanceof Activity) {
return (Activity) context;
} else if (context instanceof ContextWrapper) {
return scanForActivity(((ContextWrapper) context).getBaseContext());
} else {
return null;
}
}
Expand Down

0 comments on commit 50fb3ca

Please sign in to comment.