1 package org.coolreader.crengine;
2 
3 import android.app.Dialog;
4 import android.util.Log;
5 import android.view.GestureDetector;
6 import android.view.GestureDetector.SimpleOnGestureListener;
7 import android.view.Gravity;
8 import android.view.KeyEvent;
9 import android.view.LayoutInflater;
10 import android.view.MotionEvent;
11 import android.view.View;
12 import android.view.ViewGroup;
13 import android.view.Window;
14 import android.view.WindowManager;
15 import android.widget.ImageButton;
16 import android.widget.TextView;
17 
18 import org.coolreader.R;
19 
20 public class BaseDialog extends Dialog {
21 
22 	View layoutView;
23 	ViewGroup buttonsLayout;
24 	ViewGroup contentsLayout;
25 	BaseActivity activity;
26 	String title;
27 	boolean needCancelButton;
28 	int positiveButtonImage;
29 	int positiveButtonContentDescriptionId = R.string.dlg_button_ok;
30 	int negativeButtonImage;
31 	int negativeButtonContentDescriptionId = R.string.action_go_back;
32 	int thirdButtonImage;
33 	int thirdButtonContentDescriptionId;
setPositiveButtonImage(int imageId, int descriptionId)34 	public void setPositiveButtonImage(int imageId, int descriptionId) {
35 		positiveButtonImage = imageId;
36 		positiveButtonContentDescriptionId = descriptionId;
37 	}
setNegativeButtonImage(int imageId, int descriptionId)38 	public void setNegativeButtonImage(int imageId, int descriptionId) {
39 		negativeButtonImage = imageId;
40 		negativeButtonContentDescriptionId = descriptionId;
41 	}
setThirdButtonImage(int imageId, int descriptionId)42 	public void setThirdButtonImage(int imageId, int descriptionId) {
43 		thirdButtonImage = imageId;
44 		thirdButtonContentDescriptionId = descriptionId;
45 	}
46 
47 	public static final boolean DARK_THEME = !DeviceInfo.FORCE_HC_THEME;
BaseDialog( BaseActivity activity )48 	public BaseDialog( BaseActivity activity )
49 	{
50 		this( activity, "", false, false );
51 	}
BaseDialog( BaseActivity activity, String title, boolean showNegativeButton, boolean windowed )52 	public BaseDialog( BaseActivity activity, String title, boolean showNegativeButton, boolean windowed )
53 	{
54 		this( activity, title, showNegativeButton, activity.isFullscreen(), activity.isNightMode(), windowed );
55 	}
BaseDialog( BaseActivity activity, String title, boolean showNegativeButton, boolean fullscreen, boolean dark, boolean windowed )56 	public BaseDialog( BaseActivity activity, String title, boolean showNegativeButton, boolean fullscreen, boolean dark, boolean windowed )
57 	{
58 		//super(activity, fullscreen ? R.style.Dialog_Fullscreen : R.style.Dialog_Normal);
59 		//super(activity, fullscreen ? R.style.Dialog_Fullscreen : android.R.style.Theme_Dialog); //android.R.style.Theme_Light_NoTitleBar_Fullscreen : android.R.style.Theme_Light
60 		super(activity,
61 				windowed ? activity.getCurrentTheme().getDialogThemeId() :
62 				(fullscreen
63 				? activity.getCurrentTheme().getFullscreenDialogThemeId()
64 				: activity.getCurrentTheme().getDialogThemeId()
65 				));
66 		setOwnerActivity(activity);
67 		this.activity = activity;
68 		this.title = title;
69 		this.needCancelButton = showNegativeButton;
70 		getWindow().requestFeature(Window.FEATURE_NO_TITLE);
71 //		requestWindowFeature(Window.FEATURE_OPTIONS_PANEL);
72 		if (!DeviceInfo.EINK_SCREEN) {
73 			WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
74 			lp.alpha = 1.0f;
75 			lp.dimAmount = 0.0f;
76 			lp.format = DeviceInfo.PIXEL_FORMAT;
77 			lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
78 			lp.horizontalMargin = 0;
79 			lp.verticalMargin = 0;
80 			lp.windowAnimations = 0;
81 			lp.layoutAnimationParameters = null;
82 			//lp.memoryType = WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
83 			getWindow().setAttributes(lp);
84 		}
85 		Log.i("cr3", "BaseDialog.window=" + getWindow());
86         setCancelable(true);
87         setOnDismissListener(dialog -> onClose());
88         onCreate();
89 	}
90 
setView( View view )91 	public void setView( View view )
92 	{
93 		this.view = view;
94 		if ( layoutView==null ) {
95 			layoutView = createLayout(view);
96 			setContentView(layoutView);
97 		}
98 		contentsLayout.removeAllViews();
99 		if (null != view)
100 			contentsLayout.addView(view);
101 	}
102 
onPositiveButtonClick()103 	protected void onPositiveButtonClick()
104 	{
105 		// override it
106 		dismiss();
107 	}
108 
onNegativeButtonClick()109 	protected void onNegativeButtonClick()
110 	{
111 		// override it
112 		dismiss();
113 	}
114 
onThirdButtonClick()115 	protected void onThirdButtonClick()
116 	{
117 		// override it
118 		dismiss();
119 	}
120 
createButtonsPane( ViewGroup parent, ViewGroup layout )121 	protected void createButtonsPane( ViewGroup parent, ViewGroup layout )
122 	{
123 		//getWindow().getDecorView().getWidth()
124 		ImageButton positiveButton = layout.findViewById(R.id.base_dlg_btn_positive);
125 		ImageButton negativeButton = layout.findViewById(R.id.base_dlg_btn_negative);
126 		ImageButton backButton = layout.findViewById(R.id.base_dlg_btn_back);
127 		if (positiveButtonImage != 0) {
128 			positiveButton.setImageResource(positiveButtonImage);
129 			if (positiveButtonContentDescriptionId != 0)
130 				Utils.setContentDescription(positiveButton, getContext().getString(positiveButtonContentDescriptionId));
131 			//backButton.setImageResource(positiveButtonImage);
132 		}
133 		if (thirdButtonImage != 0) {
134 			negativeButton.setImageResource(thirdButtonImage);
135 			if (thirdButtonContentDescriptionId != 0)
136 				Utils.setContentDescription(negativeButton, getContext().getString(thirdButtonContentDescriptionId));
137 		}
138 		if (negativeButtonImage != 0) {
139 			if (thirdButtonImage == 0) {
140 				negativeButton.setImageResource(negativeButtonImage);
141 				if (negativeButtonContentDescriptionId != 0)
142 					Utils.setContentDescription(negativeButton, getContext().getString(negativeButtonContentDescriptionId));
143 			}
144 			backButton.setImageResource(negativeButtonImage);
145 			if (negativeButtonContentDescriptionId != 0)
146 				Utils.setContentDescription(backButton, getContext().getString(negativeButtonContentDescriptionId));
147 		}
148 		if (needCancelButton) {
149 			//layout.removeView(backButton);
150 			if (thirdButtonImage == 0) {
151 				layout.removeView(negativeButton);
152 			} else {
153 				negativeButton.setOnClickListener(v -> onThirdButtonClick());
154 			}
155 			positiveButton.setOnClickListener(v -> onPositiveButtonClick());
156 			//negativeButton.setOnClickListener(new View.OnClickListener() {
157 			backButton.setOnClickListener(v -> onNegativeButtonClick());
158 		} else {
159 			layout.removeView(positiveButton);
160 			layout.removeView(negativeButton);
161 			if (title != null) {
162 				backButton.setOnClickListener(v -> onPositiveButtonClick());
163 			} else {
164 				parent.removeView(layout);
165                 buttonsLayout = null;
166 			}
167 		}
168 		if (title != null)
169 			setTitle(title);
170 		if (buttonsLayout != null) {
171 			buttonsLayout.setOnTouchListener((v, event) -> {
172 				if (event.getAction() == MotionEvent.ACTION_DOWN) {
173 					int x = (int)event.getX();
174 					int dx = v.getWidth();
175 					if (x < dx / 3) {
176 						if (needCancelButton)
177 							onNegativeButtonClick();
178 						else
179 							onPositiveButtonClick();
180 					} else if (x > dx * 2 / 3) {
181 						onPositiveButtonClick();
182 					}
183 					return true;
184 				}
185 				return false;
186 			});
187 		}
188 	}
189 
190 	@Override
setTitle(CharSequence title)191 	public void setTitle(CharSequence title) {
192 		this.title = String.valueOf(title);
193 		if (buttonsLayout != null) {
194 	        TextView lbl = buttonsLayout.findViewById(R.id.base_dlg_title);
195 	        if (lbl != null)
196 	        	lbl.setText(title != null ? title : "");
197 		}
198 	}
199 
createLayout( View view )200 	protected View createLayout( View view )
201 	{
202         LayoutInflater mInflater = LayoutInflater.from(getContext());
203         ViewGroup layout = (ViewGroup)mInflater.inflate(R.layout.base_dialog, null);
204         buttonsLayout = layout.findViewById(R.id.base_dlg_button_panel);
205         if (buttonsLayout != null) {
206             if ( needCancelButton || title != null) {
207             	createButtonsPane(layout, buttonsLayout);
208             } else {
209             	layout.removeView(buttonsLayout);
210                 buttonsLayout = null;
211             }
212         }
213         contentsLayout =  layout.findViewById(R.id.base_dialog_content_view);
214         if (null != view)
215             contentsLayout.addView(view);
216         setTitle(title);
217 		return layout;
218 	}
219 
onCreate()220 	protected void onCreate() {
221 		// when dialog is created
222 		Log.d("DLG","BaseDialog.onCreate()");
223 		activity.onDialogCreated(this);
224 	}
225 
onClose()226 	protected void onClose() {
227 		// when dialog is closed
228 		Log.d("DLG","BaseDialog.onClose()");
229 		activity.onDialogClosed(this);
230 	}
231 
232 
233 	/**
234 	 * Set View's gesture handlers for LTR and RTL horizontal fling
235 	 * @param view
236 	 * @param ltrHandler, pass null to call onNegativeButtonClick
237 	 * @param rtlHandler, pass null to call onPositiveButtonClick
238 	 */
setFlingHandlers(View view, Runnable ltrHandler, Runnable rtlHandler)239 	public void setFlingHandlers(View view, Runnable ltrHandler, Runnable rtlHandler) {
240 		// cancel
241 		if (ltrHandler == null)
242 			ltrHandler = this::onNegativeButtonClick;
243 		// ok
244 		if (rtlHandler == null)
245 			rtlHandler = this::onPositiveButtonClick;
246 		final GestureDetector detector = new GestureDetector(new MyGestureListener(ltrHandler, rtlHandler));
247 		view.setOnTouchListener((v, event) -> detector.onTouchEvent(event));
248 	}
249 
250 	private class MyGestureListener extends SimpleOnGestureListener {
251 		Runnable ltrHandler;
252 		Runnable rtlHandler;
253 
MyGestureListener(Runnable ltrHandler, Runnable rtlHandler)254 		public MyGestureListener(Runnable ltrHandler, Runnable rtlHandler) {
255 			this.ltrHandler = ltrHandler;
256 			this.rtlHandler = rtlHandler;
257 		}
258 
259 		@Override
onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)260 		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
261 				float velocityY) {
262 			if (e1 == null || e2 == null)
263 				return false;
264 			int thresholdDistance = activity.getPalmTipPixels() * 2;
265 			int thresholdVelocity = activity.getPalmTipPixels();
266 			int x1 = (int)e1.getX();
267 			int x2 = (int)e2.getX();
268 			int y1 = (int)e1.getY();
269 			int y2 = (int)e2.getY();
270 			int dist = x2 - x1;
271 			int adist = dist > 0 ? dist : -dist;
272 			int ydist = y2 - y1;
273 			int aydist = ydist > 0 ? ydist : -ydist;
274 			int vel = (int)velocityX;
275 			if (vel<0)
276 				vel = -vel;
277 			if (vel > thresholdVelocity && adist > thresholdDistance && adist > aydist * 2) {
278 				if (dist > 0) {
279 					Log.d("cr3", "LTR fling detected");
280 					if (ltrHandler != null) {
281 						ltrHandler.run();
282 						return true;
283 					}
284 				} else {
285 					Log.d("cr3", "RTL fling detected");
286 					if (rtlHandler != null) {
287 						rtlHandler.run();
288 						return true;
289 					}
290 				}
291 			}
292 			return false;
293 		}
294 
295 	}
296 
297 	@Override
onKeyDown(int keyCode, KeyEvent event)298     public boolean onKeyDown(int keyCode, KeyEvent event) {
299 		activity.onUserActivity();
300 		if (keyCode == KeyEvent.KEYCODE_BACK) {
301 			onNegativeButtonClick();
302 			return true;
303 		}
304         if( this.view != null ) {
305             if (this.view.onKeyDown(keyCode, event))
306             	return true;
307         }
308         return super.onKeyDown(keyCode, event);
309     }
310 
311 	protected View view;
312 }
313