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