Project

General

Profile

Download (8.59 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / main / MainSettingsPopup.java @ 3bedda30

1 c820515c leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10
package org.distorted.main;
11
12
import android.content.Context;
13 881697b3 leszek
import android.content.res.Resources;
14 0a9adc31 leszek
import android.graphics.drawable.ColorDrawable;
15 c820515c leszek
import android.os.Build;
16
import android.view.Gravity;
17
import android.view.LayoutInflater;
18
import android.view.View;
19
import android.widget.AdapterView;
20
import android.widget.ArrayAdapter;
21
import android.widget.ListPopupWindow;
22
import android.widget.PopupWindow;
23
import android.widget.Spinner;
24
25 def32b2c leszek
import java.lang.ref.WeakReference;
26 c820515c leszek
import java.lang.reflect.Field;
27
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29
30
public class MainSettingsPopup implements AdapterView.OnItemSelectedListener
31
  {
32 def32b2c leszek
  public static final int SORT_CLASSIC    = 0;
33 881697b3 leszek
  public static final int SORT_SHAPE      = 1;
34 def32b2c leszek
  public static final int SORT_DIFFICULTY = 2;
35
  public static final int SORT_AUTHOR     = 3;
36
  public static final int SORT_YEAR       = 4;
37
38 97076b52 leszek
  public static final int SORT_DEFAULT    = SORT_SHAPE;
39 417d51b6 leszek
40 def32b2c leszek
  private static final int[] mLocation = new int[2];
41 c820515c leszek
42 2eb70e4a leszek
  private final int mWidth, mHeight;
43 9881dc03 leszek
  private PopupWindow mPopup;
44
  private WeakReference<MainActivity> mAct;
45 c820515c leszek
  private int mCurrMethod;
46 881697b3 leszek
  private String[] mSortNames;
47 9881dc03 leszek
  private int mCurrTheme;
48
  private String[] mThemeNames;
49 c820515c leszek
50
///////////////////////////////////////////////////////////////////////////////////////////////////
51
// this is supposed to prevent showing the navigational bar when we show the drop down list,
52
// but it doesn't quite work... At least not in the emulator.
53
// see https://gist.github.com/kakajika/a236ba721a5c0ad3c1446e16a7423a63
54
//
55
// EDIT: the bar does not appear on API 34 without the need to call this method. Must have been
56
// fixed by Android developers.
57
58
  public static void avoidSpinnerDropdownFocus(Spinner spinner)
59
    {
60
    try
61
      {
62
      Field listPopupField = Spinner.class.getDeclaredField("mPopup");
63
      listPopupField.setAccessible(true);
64
      Object listPopup = listPopupField.get(spinner);
65
66
      if( listPopup instanceof ListPopupWindow )
67
        {
68
        Field popupField = ListPopupWindow.class.getDeclaredField("mPopup");
69
        popupField.setAccessible(true);
70
        Object popup = popupField.get((ListPopupWindow) listPopup);
71
72
        if( popup instanceof PopupWindow )
73
          {
74
          ((PopupWindow) popup).setFocusable(false);
75
          }
76
        }
77
      }
78
    catch (NoSuchFieldException | IllegalAccessException ignored)
79
      {
80
81
      }
82
    }
83
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85
86 9b6f8f18 leszek
  MainSettingsPopup(MainActivity act, int sortMethod, int themeValue, int popupWidth, int popupHeight)
87 c820515c leszek
    {
88 def32b2c leszek
    mAct = new WeakReference<>(act);
89
90 2eb70e4a leszek
    mWidth = popupWidth;
91
    mHeight= popupHeight;
92
93 c820515c leszek
    // due to bugs in Android API <=25, a Spinner inside a PopupWindow will crash once you click on it.
94
    // solution: on those APIs, use a special Spinner in dialog mode (this does not crash)
95
    int id = android.os.Build.VERSION.SDK_INT <= 25 ? R.layout.settings_popup_android25 : R.layout.settings_popup;
96
97
    LayoutInflater layoutInflater = (LayoutInflater) act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
98
    final View layout = layoutInflater.inflate(id, null);
99 0a9adc31 leszek
    final View title  = layout.findViewById(R.id.settingsTitle);
100 c820515c leszek
101
    mPopup = new PopupWindow(act);
102
    mPopup.setContentView(layout);
103
    mPopup.setFocusable(true);
104
105 0a9adc31 leszek
    Resources res = act.getResources();
106
    int d = res.getColor(act.getDarkTrans());
107
    int l = res.getColor(act.getLightTrans());
108
109
    mPopup.setBackgroundDrawable(new ColorDrawable(l));
110
    title.setBackground(new ColorDrawable(d));
111
    mPopup.setElevation(100);
112
113 9881dc03 leszek
    Spinner sortSpinner  = layout.findViewById(R.id.sortMethod);
114
    sortSpinner.setOnItemSelectedListener(this);
115 c820515c leszek
116 acee3e3e leszek
    mCurrMethod = sortMethod;
117 881697b3 leszek
    buildSortOptions(act);
118 c820515c leszek
119 2eb70e4a leszek
    ArrayAdapter<String> sortAdapter = new ArrayAdapter<>(act, R.layout.settings_spinner_item, mSortNames);
120 236cc1c1 leszek
    sortAdapter.setDropDownViewResource(R.layout.settings_spinner_item);
121 9881dc03 leszek
    sortSpinner.setAdapter(sortAdapter);
122 acee3e3e leszek
123 9881dc03 leszek
    if( sortMethod>=0 && sortMethod<mSortNames.length ) sortSpinner.setSelection(sortMethod);
124
125
    Spinner themeSpinner  = layout.findViewById(R.id.themeValue);
126
    themeSpinner.setOnItemSelectedListener(this);
127
128
    mCurrTheme = themeValue;
129
    buildThemeOptions(act);
130
131 2eb70e4a leszek
    ArrayAdapter<String> themeAdapter = new ArrayAdapter<>(act, R.layout.settings_spinner_item, mThemeNames);
132 236cc1c1 leszek
    themeAdapter.setDropDownViewResource(R.layout.settings_spinner_item);
133 9881dc03 leszek
    themeSpinner.setAdapter(themeAdapter);
134
135
    if( themeValue>=0 && themeValue<mThemeNames.length ) themeSpinner.setSelection(themeValue);
136 c820515c leszek
    }
137 881697b3 leszek
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139
140
  private void buildSortOptions(MainActivity act)
141
    {
142
    Resources res = act.getResources();
143
    mSortNames = new String[5];
144
145
    mSortNames[0] = res.getString(R.string.sort_classic);
146
    mSortNames[1] = res.getString(R.string.sort_shape);
147
    mSortNames[2] = res.getString(R.string.sort_difficulty);
148
    mSortNames[3] = res.getString(R.string.sort_author);
149
    mSortNames[4] = res.getString(R.string.sort_year);
150
    }
151 c820515c leszek
152 9881dc03 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
153
154
  private void buildThemeOptions(MainActivity act)
155
    {
156
    Resources res = act.getResources();
157 2456eaa0 leszek
    mThemeNames = new String[5];
158 9881dc03 leszek
159 7214ddf1 leszek
    mThemeNames[0] = res.getString(R.string.theme_green);
160 2456eaa0 leszek
    mThemeNames[1] = res.getString(R.string.theme_blue);
161 7214ddf1 leszek
    mThemeNames[2] = res.getString(R.string.theme_grey);
162 2456eaa0 leszek
    mThemeNames[3] = res.getString(R.string.theme_pink);
163
    mThemeNames[4] = res.getString(R.string.theme_orange);
164 9881dc03 leszek
    }
165
166 c820515c leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
167
// work around lame bugs in Android's version <= 10 pop-up and split-screen modes
168
169 2eb70e4a leszek
  public void displayPopup(MainActivity act, View view, int xoff, int yoff)
170 c820515c leszek
    {
171
    View v = mPopup.getContentView();
172
    v.setSystemUiVisibility(MainActivity.FLAGS);
173
174
    View topLayout = act.findViewById(R.id.relativeLayout);
175
176
    boolean isFullScreen;
177
178
    if( topLayout!=null )
179
      {
180
      topLayout.getLocationOnScreen(mLocation);
181
      isFullScreen = (mLocation[1]==0);
182
      }
183
    else
184
      {
185
      isFullScreen = true;
186
      }
187
188
    try
189
      {
190
      // if on Android 11 or we are fullscreen
191
      if (Build.VERSION_CODES.R<=Build.VERSION.SDK_INT || isFullScreen )
192
        {
193
        mPopup.showAsDropDown(view, xoff, yoff, Gravity.CENTER);
194 2eb70e4a leszek
        mPopup.update(view, mWidth, mHeight);
195 c820515c leszek
        }
196
      else  // Android 10 or below in pop-up mode or split-screen mode
197
        {
198
        view.getLocationOnScreen(mLocation);
199
        int width  = view.getWidth();
200
        int height = view.getHeight();
201 2eb70e4a leszek
        int x = mLocation[0]+(width-mWidth)/2;
202 c820515c leszek
        int y = mLocation[1]+height+yoff;
203
        mPopup.showAsDropDown(view);
204 2eb70e4a leszek
        mPopup.update(x,y,mWidth,mHeight);
205 c820515c leszek
        }
206
      }
207
    catch( IllegalArgumentException iae )
208
      {
209
      // ignore, this means window is 'not attached to window manager' -
210
      // which most probably is because we are already exiting the app.
211
      }
212
    }
213
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215
216
  public void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
217
    {
218
    if( parent.getId()==R.id.sortMethod && mCurrMethod!=pos )
219
      {
220 9881dc03 leszek
      mPopup.dismiss();
221 c820515c leszek
      mCurrMethod = pos;
222 def32b2c leszek
      MainActivity act = mAct.get();
223
      act.sortObjectsBy(pos);
224 9881dc03 leszek
      }
225
    if( parent.getId()==R.id.themeValue && mCurrTheme!=pos )
226
      {
227 acee3e3e leszek
      mPopup.dismiss();
228 9881dc03 leszek
      mPopup = null;
229
      mCurrTheme = pos;
230
      MainActivity act = mAct.get();
231
      mAct = null;
232
      act.changeThemeTo(pos);
233 c820515c leszek
      }
234
    }
235
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237
238
  public void onNothingSelected(AdapterView<?> parent)
239
    {
240
241
    }
242
  }