Revision b42c8399
Added by Leszek Koltunski about 1 year ago
src/main/AndroidManifest.xml | ||
---|---|---|
20 | 20 |
android:value="${crashlyticsCollectionEnabled}" |
21 | 21 |
/> |
22 | 22 |
|
23 |
<activity android:name="org.distorted.main.MainActivity" android:exported="true" android:screenOrientation="portrait"> |
|
23 |
<activity android:name="org.distorted.main.MainActivity" |
|
24 |
android:exported="true" |
|
25 |
android:screenOrientation="portrait" |
|
26 |
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> |
|
24 | 27 |
<intent-filter> |
25 | 28 |
<action android:name="android.intent.action.MAIN" /> |
26 | 29 |
<category android:name="android.intent.category.LAUNCHER" /> |
src/main/java/org/distorted/main/MainActivity.java | ||
---|---|---|
13 | 13 |
import android.content.SharedPreferences; |
14 | 14 |
import android.content.pm.PackageInfo; |
15 | 15 |
import android.content.pm.PackageManager; |
16 |
import android.content.res.Configuration; |
|
16 | 17 |
import android.os.Build; |
17 | 18 |
import android.os.Bundle; |
18 | 19 |
import android.util.DisplayMetrics; |
... | ... | |
25 | 26 |
import android.widget.ScrollView; |
26 | 27 |
import android.widget.TextView; |
27 | 28 |
|
29 |
import androidx.annotation.NonNull; |
|
28 | 30 |
import androidx.appcompat.app.AppCompatActivity; |
29 | 31 |
import androidx.preference.PreferenceManager; |
30 | 32 |
|
... | ... | |
57 | 59 |
| View.SYSTEM_UI_FLAG_FULLSCREEN |
58 | 60 |
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; |
59 | 61 |
|
60 |
private static final float RATIO_INSET= 0.09f; |
|
61 |
|
|
62 | 62 |
private boolean mJustStarted; |
63 | 63 |
private FirebaseAnalytics mFirebaseAnalytics; |
64 |
private static int mScreenWidth, mScreenHeight; |
|
65 | 64 |
private int mCurrentApiVersion; |
66 |
private int mHeightUpperBar; |
|
67 | 65 |
private String mOldVersion, mCurrVersion; |
68 | 66 |
private int mSolverIndex; |
67 |
private int mScreenWidth; |
|
69 | 68 |
private TextView mBubbleUpdates; |
70 | 69 |
private int mNumUpdates; |
71 | 70 |
private MainScrollGrid mGrid; |
... | ... | |
83 | 82 |
mJustStarted = true; |
84 | 83 |
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this); |
85 | 84 |
|
86 |
DisplayMetrics displaymetrics = new DisplayMetrics(); |
|
87 |
getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics); |
|
88 |
mScreenWidth =displaymetrics.widthPixels; |
|
89 |
mScreenHeight=displaymetrics.heightPixels; |
|
90 |
|
|
91 | 85 |
cutoutHack(); |
92 | 86 |
computeHeights(); |
93 | 87 |
|
... | ... | |
111 | 105 |
|
112 | 106 |
private void computeHeights() |
113 | 107 |
{ |
114 |
int barHeight = (int)(mScreenHeight*RATIO_BAR); |
|
115 |
int scrollHeight = (int)(mScreenHeight*(1-2*RATIO_BAR)); |
|
116 |
mHeightUpperBar = barHeight; |
|
117 |
|
|
108 |
LinearLayout.LayoutParams pU = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, RATIO_BAR); |
|
118 | 109 |
LinearLayout layoutTop = findViewById(R.id.upperBar); |
119 |
ViewGroup.LayoutParams paramsTop = layoutTop.getLayoutParams(); |
|
120 |
paramsTop.height = barHeight; |
|
121 |
layoutTop.setLayoutParams(paramsTop); |
|
122 |
|
|
123 |
LinearLayout layoutBot = findViewById(R.id.lowerBar); |
|
124 |
ViewGroup.LayoutParams paramsBot = layoutBot.getLayoutParams(); |
|
125 |
paramsBot.height = barHeight; |
|
126 |
layoutBot.setLayoutParams(paramsBot); |
|
110 |
layoutTop.setLayoutParams(pU); |
|
127 | 111 |
|
112 |
LinearLayout.LayoutParams pS = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1-2*RATIO_BAR); |
|
128 | 113 |
ScrollView scroll = findViewById(R.id.objectScroll); |
129 |
ViewGroup.LayoutParams paramsScroll = scroll.getLayoutParams(); |
|
130 |
paramsScroll.height = scrollHeight; |
|
131 |
scroll.setLayoutParams(paramsScroll); |
|
114 |
scroll.setLayoutParams(pS); |
|
115 |
|
|
116 |
LinearLayout.LayoutParams pL = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, RATIO_BAR); |
|
117 |
LinearLayout layoutBot = findViewById(R.id.lowerBar); |
|
118 |
layoutBot.setLayoutParams(pL); |
|
132 | 119 |
} |
133 | 120 |
|
134 | 121 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
164 | 151 |
{ |
165 | 152 |
super.onAttachedToWindow(); |
166 | 153 |
|
154 |
getWindowWidth(getResources().getConfiguration()); |
|
155 |
mGrid = new MainScrollGrid(); |
|
156 |
mGrid.createGrid(this,mScreenWidth); |
|
157 |
|
|
167 | 158 |
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ) |
168 | 159 |
{ |
169 | 160 |
DisplayCutout cutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout(); |
170 | 161 |
int insetHeight = cutout!=null ? cutout.getSafeInsetTop() : 0; |
171 | 162 |
|
172 |
LinearLayout layoutHid = findViewById(R.id.hiddenBar); |
|
173 |
ViewGroup.LayoutParams paramsHid = layoutHid.getLayoutParams(); |
|
174 |
paramsHid.height = (int)(insetHeight*RATIO_INSET); |
|
175 |
layoutHid.setLayoutParams(paramsHid); |
|
176 |
mHeightUpperBar += paramsHid.height; |
|
163 |
if( insetHeight>0 ) |
|
164 |
{ |
|
165 |
LinearLayout.LayoutParams pH = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, RATIO_BAR); |
|
166 |
LinearLayout layoutHid = findViewById(R.id.hiddenBar); |
|
167 |
layoutHid.setLayoutParams(pH); |
|
168 |
|
|
169 |
LinearLayout.LayoutParams pS = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1-3*RATIO_BAR); |
|
170 |
ScrollView scroll = findViewById(R.id.objectScroll); |
|
171 |
scroll.setLayoutParams(pS); |
|
172 |
} |
|
177 | 173 |
} |
178 | 174 |
} |
179 | 175 |
|
... | ... | |
188 | 184 |
} |
189 | 185 |
} |
190 | 186 |
|
187 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
188 |
|
|
189 |
private void getWindowWidth(Configuration conf) |
|
190 |
{ |
|
191 |
int dpi = getResources().getDisplayMetrics().densityDpi; |
|
192 |
float conv = ((float) dpi/DisplayMetrics.DENSITY_DEFAULT); |
|
193 |
|
|
194 |
mScreenWidth = (int) (conf.screenWidthDp*conv + 0.5f); |
|
195 |
} |
|
196 |
|
|
191 | 197 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
192 | 198 |
|
193 | 199 |
@Override |
... | ... | |
201 | 207 |
} |
202 | 208 |
} |
203 | 209 |
|
210 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
211 |
|
|
212 |
@Override |
|
213 |
public void onConfigurationChanged(@NonNull Configuration conf) |
|
214 |
{ |
|
215 |
super.onConfigurationChanged(conf); |
|
216 |
|
|
217 |
getWindowWidth(conf); |
|
218 |
mGrid.updateGrid(this,mScreenWidth); |
|
219 |
} |
|
220 |
|
|
204 | 221 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
205 | 222 |
|
206 | 223 |
@Override |
... | ... | |
229 | 246 |
network.signUpForUpdates(this); |
230 | 247 |
network.downloadUpdates(this); |
231 | 248 |
|
232 |
mGrid = new MainScrollGrid(); |
|
233 |
mGrid.createGrid(this,mScreenWidth,mScreenHeight); |
|
234 |
|
|
235 | 249 |
if( mJustStarted ) |
236 | 250 |
{ |
237 | 251 |
mJustStarted = false; |
... | ... | |
312 | 326 |
} |
313 | 327 |
} |
314 | 328 |
|
315 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
316 |
// PUBLIC API |
|
317 | 329 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
318 | 330 |
|
319 |
public FirebaseAnalytics getAnalytics()
|
|
331 |
private void updateBubble(int num)
|
|
320 | 332 |
{ |
321 |
return mFirebaseAnalytics; |
|
322 |
} |
|
323 |
|
|
324 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
333 |
runOnUiThread(new Runnable() |
|
334 |
{ |
|
335 |
@Override |
|
336 |
public void run() |
|
337 |
{ |
|
338 |
mNumUpdates = num; |
|
325 | 339 |
|
326 |
public int getHeightUpperBar() |
|
327 |
{ |
|
328 |
return mHeightUpperBar; |
|
340 |
if( num>0 ) |
|
341 |
{ |
|
342 |
String shownNum = String.valueOf(num); |
|
343 |
mBubbleUpdates.setText(shownNum); |
|
344 |
mBubbleUpdates.setVisibility(View.VISIBLE); |
|
345 |
int height = (int)(0.05f*mScreenWidth); |
|
346 |
mBubbleUpdates.setTextSize(TypedValue.COMPLEX_UNIT_PX,height); |
|
347 |
} |
|
348 |
else |
|
349 |
{ |
|
350 |
mBubbleUpdates.setVisibility(View.INVISIBLE); |
|
351 |
} |
|
352 |
} |
|
353 |
}); |
|
329 | 354 |
} |
330 | 355 |
|
331 | 356 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
332 |
|
|
333 |
public int getScreenWidthInPixels() |
|
334 |
{ |
|
335 |
return mScreenWidth; |
|
336 |
} |
|
337 |
|
|
357 |
// PUBLIC API |
|
338 | 358 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
339 | 359 |
|
340 |
public int getScreenHeightInPixels()
|
|
360 |
public FirebaseAnalytics getAnalytics()
|
|
341 | 361 |
{ |
342 |
return mScreenHeight;
|
|
362 |
return mFirebaseAnalytics;
|
|
343 | 363 |
} |
344 | 364 |
|
345 | 365 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
436 | 456 |
diag.show(getSupportFragmentManager(), RubikDialogCreators.getDialogTag() ); |
437 | 457 |
} |
438 | 458 |
|
439 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
440 |
|
|
441 |
public void updateBubble(int num) |
|
442 |
{ |
|
443 |
runOnUiThread(new Runnable() |
|
444 |
{ |
|
445 |
@Override |
|
446 |
public void run() |
|
447 |
{ |
|
448 |
mNumUpdates = num; |
|
449 |
|
|
450 |
if( num>0 ) |
|
451 |
{ |
|
452 |
String shownNum = String.valueOf(num); |
|
453 |
mBubbleUpdates.setText(shownNum); |
|
454 |
mBubbleUpdates.setVisibility(View.VISIBLE); |
|
455 |
int height = (int)(0.05f*mScreenWidth); |
|
456 |
mBubbleUpdates.setTextSize(TypedValue.COMPLEX_UNIT_PX,height); |
|
457 |
} |
|
458 |
else |
|
459 |
{ |
|
460 |
mBubbleUpdates.setVisibility(View.INVISIBLE); |
|
461 |
} |
|
462 |
} |
|
463 |
}); |
|
464 |
} |
|
465 |
|
|
466 | 459 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
467 | 460 |
|
468 | 461 |
public void receiveUpdate(RubikUpdates updates) |
... | ... | |
477 | 470 |
{ |
478 | 471 |
mNumUpdates--; |
479 | 472 |
updateBubble(mNumUpdates); |
480 |
mGrid.updateGrid(this,mScreenWidth,mScreenHeight);
|
|
473 |
mGrid.updateGrid(this,mScreenWidth); |
|
481 | 474 |
} |
482 | 475 |
|
483 | 476 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
src/main/java/org/distorted/main/MainObjectPopup.java | ||
---|---|---|
1 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
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 static android.view.View.GONE; |
|
13 |
|
|
14 |
import android.app.Activity; |
|
15 |
import android.content.Context; |
|
16 |
import android.util.TypedValue; |
|
17 |
import android.view.Gravity; |
|
18 |
import android.view.LayoutInflater; |
|
19 |
import android.view.View; |
|
20 |
import android.widget.Button; |
|
21 |
import android.widget.LinearLayout; |
|
22 |
import android.widget.PopupWindow; |
|
23 |
import android.widget.TextView; |
|
24 |
|
|
25 |
import org.distorted.objects.RubikObject; |
|
26 |
import org.distorted.objects.RubikObjectList; |
|
27 |
|
|
28 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
29 |
|
|
30 |
public class MainObjectPopup |
|
31 |
{ |
|
32 |
private static final float MENU_TEXT_SIZE= 0.024f; |
|
33 |
private static final float MENU_MARGIN = 0.008f; |
|
34 |
private static final float BUTTON_HEIGHT = 0.150f; |
|
35 |
private static final float MENU_WIDTH = 0.550f; |
|
36 |
|
|
37 |
public static final int LEVELS_SHOWN = 8; |
|
38 |
|
|
39 |
private final PopupWindow mPopup; |
|
40 |
private final int mMenuTextSize; |
|
41 |
|
|
42 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
43 |
|
|
44 |
MainObjectPopup(Activity act, int ordinal, int width, int height) |
|
45 |
{ |
|
46 |
LayoutInflater layoutInflater = (LayoutInflater)act.getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
|
47 |
final View layout = layoutInflater.inflate(R.layout.object_popup, null); |
|
48 |
mPopup = new PopupWindow(act); |
|
49 |
mPopup.setContentView(layout); |
|
50 |
mPopup.setFocusable(true); |
|
51 |
|
|
52 |
mMenuTextSize = (int)(height*MENU_TEXT_SIZE); |
|
53 |
int padding = (int)(height*MENU_MARGIN); |
|
54 |
int marginH = padding/2; |
|
55 |
int marginV =-padding/4; |
|
56 |
layout.setPadding(padding,0,padding,0); |
|
57 |
int levelHeight = (int)(width*BUTTON_HEIGHT); |
|
58 |
|
|
59 |
RubikObject object = RubikObjectList.getObject(ordinal); |
|
60 |
|
|
61 |
Button b1 = layout.findViewById(R.id.objectSolver); |
|
62 |
|
|
63 |
if( object!=null && object.hasSolver() ) |
|
64 |
{ |
|
65 |
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,levelHeight); |
|
66 |
params.setMargins(marginH,marginV,marginH,marginV); |
|
67 |
b1.setLayoutParams(params); |
|
68 |
b1.setTextSize(TypedValue.COMPLEX_UNIT_PX, mMenuTextSize); |
|
69 |
b1.setOnClickListener(new View.OnClickListener() |
|
70 |
{ |
|
71 |
@Override |
|
72 |
public void onClick(View v) |
|
73 |
{ |
|
74 |
|
|
75 |
} |
|
76 |
}); |
|
77 |
} |
|
78 |
else b1.setVisibility(GONE); |
|
79 |
|
|
80 |
Button b2 = layout.findViewById(R.id.objectPattern); |
|
81 |
|
|
82 |
if( object!=null && object.hasPatterns() ) |
|
83 |
{ |
|
84 |
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,levelHeight); |
|
85 |
params.setMargins(marginH,marginV,marginH,marginV); |
|
86 |
b2.setLayoutParams(params); |
|
87 |
b2.setTextSize(TypedValue.COMPLEX_UNIT_PX, mMenuTextSize); |
|
88 |
b2.setOnClickListener(new View.OnClickListener() |
|
89 |
{ |
|
90 |
@Override |
|
91 |
public void onClick(View v) |
|
92 |
{ |
|
93 |
|
|
94 |
} |
|
95 |
}); |
|
96 |
} |
|
97 |
else b2.setVisibility(GONE); |
|
98 |
|
|
99 |
Button b3 = layout.findViewById(R.id.objectTutorial); |
|
100 |
|
|
101 |
if( object!=null && object.hasExtras() ) |
|
102 |
{ |
|
103 |
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,levelHeight); |
|
104 |
params.setMargins(marginH,marginV,marginH,marginV); |
|
105 |
b3.setLayoutParams(params); |
|
106 |
b3.setTextSize(TypedValue.COMPLEX_UNIT_PX, mMenuTextSize); |
|
107 |
b3.setOnClickListener(new View.OnClickListener() |
|
108 |
{ |
|
109 |
@Override |
|
110 |
public void onClick(View v) |
|
111 |
{ |
|
112 |
|
|
113 |
} |
|
114 |
}); |
|
115 |
} |
|
116 |
else b3.setVisibility(GONE); |
|
117 |
|
|
118 |
Button b4 = layout.findViewById(R.id.objectInfo); |
|
119 |
|
|
120 |
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,levelHeight); |
|
121 |
params.setMargins(marginH,marginV,marginH,marginV); |
|
122 |
b4.setLayoutParams(params); |
|
123 |
b4.setTextSize(TypedValue.COMPLEX_UNIT_PX, mMenuTextSize); |
|
124 |
b4.setOnClickListener( new View.OnClickListener() |
|
125 |
{ |
|
126 |
@Override |
|
127 |
public void onClick(View v) |
|
128 |
{ |
|
129 |
|
|
130 |
} |
|
131 |
}); |
|
132 |
|
|
133 |
TextView levels = layout.findViewById(R.id.objectLevels); |
|
134 |
levels.setTextSize(TypedValue.COMPLEX_UNIT_PX, mMenuTextSize); |
|
135 |
|
|
136 |
setupLevelButtons(act,object,layout,width,padding,marginH); |
|
137 |
} |
|
138 |
|
|
139 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
140 |
|
|
141 |
private void setupLevelButtons(Activity act, RubikObject object, View layout, int width,int padding, int margin) |
|
142 |
{ |
|
143 |
int layoutWidth = (int)(width*MENU_WIDTH); |
|
144 |
int levelHeight = (int)(width*BUTTON_HEIGHT); |
|
145 |
int levelWidth = (layoutWidth-4*padding)/3; |
|
146 |
|
|
147 |
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(levelWidth,levelHeight); |
|
148 |
params.setMargins(margin,-margin,margin,-margin); |
|
149 |
|
|
150 |
Button[] level = new Button[LEVELS_SHOWN+1]; |
|
151 |
|
|
152 |
level[0] = layout.findViewById(R.id.level0); |
|
153 |
level[1] = layout.findViewById(R.id.level1); |
|
154 |
level[2] = layout.findViewById(R.id.level2); |
|
155 |
level[3] = layout.findViewById(R.id.level3); |
|
156 |
level[4] = layout.findViewById(R.id.level4); |
|
157 |
level[5] = layout.findViewById(R.id.level5); |
|
158 |
level[6] = layout.findViewById(R.id.level6); |
|
159 |
level[7] = layout.findViewById(R.id.level7); |
|
160 |
level[8] = layout.findViewById(R.id.levelM); |
|
161 |
|
|
162 |
int numScramble = object==null ? 1 : object.getNumScramble(); |
|
163 |
int min = Math.min(numScramble,LEVELS_SHOWN); |
|
164 |
|
|
165 |
if( numScramble>=1 && numScramble<=7 ) |
|
166 |
{ |
|
167 |
level[numScramble].setText(R.string.levelM); |
|
168 |
for(int i=numScramble+1; i<=8; i++) level[i].setVisibility(GONE); |
|
169 |
} |
|
170 |
|
|
171 |
for(int i=0; i<=min; i++) |
|
172 |
{ |
|
173 |
final int ii = i; |
|
174 |
level[i].setTextSize(TypedValue.COMPLEX_UNIT_PX, mMenuTextSize); |
|
175 |
level[i].setLayoutParams(params); |
|
176 |
level[i].setPadding(0,0,0,0); |
|
177 |
level[i].setOnClickListener( new View.OnClickListener() |
|
178 |
{ |
|
179 |
@Override |
|
180 |
public void onClick(View v) |
|
181 |
{ |
|
182 |
|
|
183 |
} |
|
184 |
}); |
|
185 |
} |
|
186 |
} |
|
187 |
|
|
188 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
189 |
|
|
190 |
void show(View v) |
|
191 |
{ |
|
192 |
View popupView = mPopup.getContentView(); |
|
193 |
popupView.setSystemUiVisibility(MainActivity.FLAGS); |
|
194 |
mPopup.showAtLocation(v, Gravity.CENTER, 0, 0); |
|
195 |
} |
|
196 |
} |
|
197 |
|
src/main/java/org/distorted/main/MainScrollGrid.java | ||
---|---|---|
9 | 9 |
|
10 | 10 |
package org.distorted.main; |
11 | 11 |
|
12 |
import android.app.Activity; |
|
13 |
import android.util.DisplayMetrics; |
|
12 | 14 |
import android.view.View; |
13 | 15 |
import android.widget.GridLayout; |
14 | 16 |
import android.widget.ImageButton; |
15 | 17 |
|
16 | 18 |
import org.distorted.helpers.PopupCreator; |
17 |
import org.distorted.main_old.RubikActivity; |
|
18 | 19 |
import org.distorted.objects.RubikObject; |
19 | 20 |
import org.distorted.objects.RubikObjectList; |
20 | 21 |
|
... | ... | |
22 | 23 |
|
23 | 24 |
public class MainScrollGrid |
24 | 25 |
{ |
25 |
public static final int NUM_COLUMNS = 5; |
|
26 |
public static final int NUM_COLUMNS = 5; |
|
27 |
public static final float POPUP_PADDING= 0.035f; |
|
28 |
public static final float POPUP_MARGIN = 0.024f; |
|
26 | 29 |
|
27 | 30 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
28 | 31 |
|
29 |
public void createGrid(final MainActivity act, int scrW, int scrH)
|
|
32 |
void createGrid(final Activity act, int windowWidth)
|
|
30 | 33 |
{ |
31 | 34 |
int numObjects = RubikObjectList.getNumObjects(); |
32 | 35 |
int rowCount = (numObjects + NUM_COLUMNS-1) / NUM_COLUMNS; |
33 | 36 |
int colCount = NUM_COLUMNS; |
34 |
int objectSize = scrW / NUM_COLUMNS;
|
|
35 |
int margin = (int)(scrH*RubikActivity.POPUP_MARGIN);
|
|
36 |
int padding = (int)(scrH*RubikActivity.POPUP_PADDING);
|
|
37 |
int objectSize = windowWidth / NUM_COLUMNS;
|
|
38 |
int margin = (int)(windowWidth*POPUP_MARGIN);
|
|
39 |
int padding = (int)(windowWidth*POPUP_PADDING);
|
|
37 | 40 |
int cubeSize = objectSize - 2*margin; |
38 | 41 |
|
39 | 42 |
GridLayout objectGrid = act.findViewById(R.id.objectGrid); |
43 |
objectGrid.removeAllViews(); |
|
44 |
|
|
40 | 45 |
PopupCreator.createObjectGrid(objectGrid,act,rowCount,colCount,numObjects,margin,cubeSize,padding); |
41 | 46 |
|
47 |
DisplayMetrics displaymetrics = new DisplayMetrics(); |
|
48 |
act.getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics); |
|
49 |
|
|
42 | 50 |
for(int child=0; child<numObjects; child++) |
43 | 51 |
{ |
44 | 52 |
final RubikObject obj = RubikObjectList.getObject(child); |
... | ... | |
51 | 59 |
@Override |
52 | 60 |
public void onClick(View v) |
53 | 61 |
{ |
54 |
android.util.Log.e("D", "object "+ordinal+" clicked!"); |
|
62 |
int w = displaymetrics.widthPixels; |
|
63 |
int h = displaymetrics.heightPixels; |
|
64 |
MainObjectPopup popup = new MainObjectPopup(act,ordinal,w,h); |
|
65 |
popup.show(v); |
|
55 | 66 |
} |
56 | 67 |
}); |
57 | 68 |
} |
... | ... | |
59 | 70 |
|
60 | 71 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
61 | 72 |
|
62 |
public void updateGrid(final MainActivity act, int scrW, int scrH)
|
|
73 |
void updateGrid(final Activity act, int scrW)
|
|
63 | 74 |
{ |
64 | 75 |
act.runOnUiThread(new Runnable() |
65 | 76 |
{ |
66 | 77 |
@Override |
67 | 78 |
public void run() |
68 | 79 |
{ |
69 |
createGrid(act,scrW,scrH);
|
|
80 |
createGrid(act,scrW); |
|
70 | 81 |
} |
71 | 82 |
}); |
72 | 83 |
} |
src/main/java/org/distorted/objects/RubikObject.java | ||
---|---|---|
29 | 29 |
import org.distorted.main_old.RubikActivity; |
30 | 30 |
import org.distorted.objectlib.main.ObjectType; |
31 | 31 |
import org.distorted.objectlib.patterns.RubikPatternList; |
32 |
import org.distorted.solvers.ImplementedSolversList; |
|
32 | 33 |
|
33 | 34 |
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE; |
34 | 35 |
import static org.distorted.main_old.RubikActivity.SHOW_DOWNLOADED_DEBUG; |
... | ... | |
50 | 51 |
private int mNumScramble; |
51 | 52 |
private int mMeshState; |
52 | 53 |
private int mExtrasOrdinal; |
54 |
private int mSolverOrdinal; |
|
53 | 55 |
|
54 | 56 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
55 | 57 |
|
... | ... | |
70 | 72 |
int patternOrdinal = RubikPatternList.getOrdinal(ordinal); |
71 | 73 |
mPatterns = RubikPatternList.getPatterns(patternOrdinal); |
72 | 74 |
|
75 |
mSolverOrdinal = ImplementedSolversList.getSolverOrdinal(ordinal); |
|
76 |
|
|
73 | 77 |
mMeshState = MESH_NICE; |
74 | 78 |
mExtrasOrdinal = -1; |
75 | 79 |
|
... | ... | |
94 | 98 |
mPatterns = null; |
95 | 99 |
mMeshState = MESH_NICE; |
96 | 100 |
mExtrasOrdinal = -1; |
101 |
mSolverOrdinal = -1; |
|
97 | 102 |
|
98 | 103 |
mMeshID = 0; |
99 | 104 |
mJsonID = -1; |
... | ... | |
304 | 309 |
return mExtrasID!=0; |
305 | 310 |
} |
306 | 311 |
|
312 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
313 |
|
|
314 |
public boolean hasSolver() |
|
315 |
{ |
|
316 |
return mSolverOrdinal>=0; |
|
317 |
} |
|
318 |
|
|
319 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
320 |
|
|
321 |
public int getSolverOrdinal() |
|
322 |
{ |
|
323 |
return mSolverOrdinal; |
|
324 |
} |
|
325 |
|
|
326 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
327 |
|
|
328 |
public boolean hasPatterns() |
|
329 |
{ |
|
330 |
return mPatterns!=null; |
|
331 |
} |
|
332 |
|
|
307 | 333 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
308 | 334 |
|
309 | 335 |
public String[][] getPatterns() |
src/main/java/org/distorted/screens/RubikScreenPlay.java | ||
---|---|---|
596 | 596 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
597 | 597 |
// work around lame bugs in Android's version <= 10 pop-up and split-screen modes |
598 | 598 |
|
599 |
private void displayPopup(RubikActivity act, View view, PopupWindow window, int w, int h, int xoff, int yoff)
|
|
599 |
private void displayPopup(Activity act, View view, PopupWindow window, int w, int h, int xoff, int yoff) |
|
600 | 600 |
{ |
601 | 601 |
View topLayout = act.findViewById(R.id.relativeLayout); |
602 | 602 |
boolean isFullScreen; |
src/main/java/org/distorted/solvers/ImplementedSolversList.java | ||
---|---|---|
53 | 53 |
|
54 | 54 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
55 | 55 |
|
56 |
public static ImplementedSolversList getSolver(int ordinal)
|
|
56 |
public static ImplementedSolversList getSolver(int solverOrdinal)
|
|
57 | 57 |
{ |
58 |
return objects[ordinal]; |
|
58 |
return objects[solverOrdinal]; |
|
59 |
} |
|
60 |
|
|
61 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
62 |
|
|
63 |
public static int getSolverOrdinal(int objectOrdinal) |
|
64 |
{ |
|
65 |
for(int o=0; o<NUM_OBJECTS; o++) |
|
66 |
if( objects[o].mObject==objectOrdinal ) return o; |
|
67 |
|
|
68 |
return -1; |
|
59 | 69 |
} |
60 | 70 |
|
61 | 71 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
src/main/res/layout/new_main.xml | ||
---|---|---|
3 | 3 |
android:id="@+id/relativeLayout" |
4 | 4 |
android:layout_width="match_parent" |
5 | 5 |
android:layout_height="match_parent" |
6 |
android:weightSum="1.0" |
|
6 | 7 |
android:orientation="vertical"> |
7 | 8 |
|
8 | 9 |
<LinearLayout |
9 | 10 |
android:id="@+id/hiddenBar" |
10 | 11 |
android:layout_width="match_parent" |
11 |
android:layout_height="wrap_content" |
|
12 |
android:layout_height="0dp" |
|
13 |
android:layout_weight="0.00" |
|
12 | 14 |
android:gravity="center" |
13 | 15 |
android:orientation="horizontal" |
14 | 16 |
android:background="@color/dark_grey"> |
... | ... | |
17 | 19 |
<LinearLayout |
18 | 20 |
android:id="@+id/upperBar" |
19 | 21 |
android:layout_width="match_parent" |
20 |
android:layout_height="wrap_content" |
|
22 |
android:layout_height="0dp" |
|
23 |
android:layout_weight="0.08" |
|
21 | 24 |
android:gravity="center" |
22 | 25 |
android:weightSum="1.0" |
23 | 26 |
android:orientation="horizontal" |
... | ... | |
77 | 80 |
<ScrollView |
78 | 81 |
android:id="@+id/objectScroll" |
79 | 82 |
android:layout_width="match_parent" |
80 |
android:layout_height="wrap_content" |
|
83 |
android:layout_height="0dp" |
|
84 |
android:layout_weight="0.84" |
|
81 | 85 |
android:background="@color/grey"> |
82 | 86 |
|
83 | 87 |
<GridLayout |
... | ... | |
91 | 95 |
<LinearLayout |
92 | 96 |
android:id="@+id/lowerBar" |
93 | 97 |
android:layout_width="match_parent" |
94 |
android:layout_height="wrap_content" |
|
98 |
android:layout_height="0dp" |
|
99 |
android:layout_weight="0.08" |
|
95 | 100 |
android:orientation="horizontal" |
96 | 101 |
android:background="@color/dark_grey"> |
97 | 102 |
|
src/main/res/layout/object_popup.xml | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8"?> |
|
2 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|
3 |
android:id="@+id/objectGrid" |
|
4 |
android:layout_width="wrap_content" |
|
5 |
android:layout_height="wrap_content" |
|
6 |
android:gravity="center" |
|
7 |
android:layout_marginTop="0dp" |
|
8 |
android:layout_marginBottom="0dp" |
|
9 |
android:padding="0dp" |
|
10 |
android:orientation="vertical"> |
|
11 |
|
|
12 |
<Button |
|
13 |
android:id="@+id/objectSolver" |
|
14 |
android:text="@string/object_solver" |
|
15 |
android:layout_width="match_parent" |
|
16 |
android:layout_height="wrap_content" |
|
17 |
android:paddingRight="10dp" |
|
18 |
android:paddingLeft="10dp" |
|
19 |
android:singleLine="true" |
|
20 |
android:backgroundTint="@color/dark_grey" |
|
21 |
android:gravity="center"/> |
|
22 |
|
|
23 |
<Button |
|
24 |
android:id="@+id/objectPattern" |
|
25 |
android:text="@string/object_pattern" |
|
26 |
android:layout_width="match_parent" |
|
27 |
android:layout_height="wrap_content" |
|
28 |
android:paddingRight="10dp" |
|
29 |
android:paddingLeft="10dp" |
|
30 |
android:singleLine="true" |
|
31 |
android:backgroundTint="@color/dark_grey" |
|
32 |
android:gravity="center"/> |
|
33 |
|
|
34 |
<Button |
|
35 |
android:id="@+id/objectTutorial" |
|
36 |
android:text="@string/object_tutorial" |
|
37 |
android:layout_width="match_parent" |
|
38 |
android:layout_height="wrap_content" |
|
39 |
android:paddingRight="10dp" |
|
40 |
android:paddingLeft="10dp" |
|
41 |
android:singleLine="true" |
|
42 |
android:backgroundTint="@color/dark_grey" |
|
43 |
android:gravity="center"/> |
|
44 |
|
|
45 |
<Button |
|
46 |
android:id="@+id/objectInfo" |
|
47 |
android:text="@string/object_info" |
|
48 |
android:layout_width="match_parent" |
|
49 |
android:layout_height="wrap_content" |
|
50 |
android:paddingRight="10dp" |
|
51 |
android:paddingLeft="10dp" |
|
52 |
android:singleLine="true" |
|
53 |
android:backgroundTint="@color/dark_grey" |
|
54 |
android:gravity="center"/> |
|
55 |
|
|
56 |
<TextView |
|
57 |
android:id="@+id/objectLevels" |
|
58 |
android:layout_width="match_parent" |
|
59 |
android:text="@string/levels" |
|
60 |
android:layout_height="wrap_content" |
|
61 |
android:gravity="center"/> |
|
62 |
|
|
63 |
<LinearLayout |
|
64 |
android:layout_width="match_parent" |
|
65 |
android:layout_height="wrap_content" |
|
66 |
android:gravity="left" |
|
67 |
android:orientation="horizontal"> |
|
68 |
|
|
69 |
<Button |
|
70 |
android:id="@+id/level0" |
|
71 |
android:text="@string/level0" |
|
72 |
android:layout_width="wrap_content" |
|
73 |
android:layout_height="wrap_content" |
|
74 |
android:paddingRight="10dp" |
|
75 |
android:paddingLeft="10dp" |
|
76 |
android:backgroundTint="@color/dark_grey"/> |
|
77 |
<Button |
|
78 |
android:id="@+id/level1" |
|
79 |
android:text="@string/level1" |
|
80 |
android:layout_width="wrap_content" |
|
81 |
android:layout_height="wrap_content" |
|
82 |
android:paddingRight="10dp" |
|
83 |
android:paddingLeft="10dp" |
|
84 |
android:backgroundTint="@color/dark_grey"/> |
|
85 |
<Button |
|
86 |
android:id="@+id/level2" |
|
87 |
android:text="@string/level2" |
|
88 |
android:layout_width="wrap_content" |
|
89 |
android:layout_height="wrap_content" |
|
90 |
android:paddingRight="10dp" |
|
91 |
android:paddingLeft="10dp" |
|
92 |
android:backgroundTint="@color/dark_grey"/> |
|
93 |
</LinearLayout> |
|
94 |
|
|
95 |
<LinearLayout |
|
96 |
android:layout_width="match_parent" |
|
97 |
android:layout_height="wrap_content" |
|
98 |
android:gravity="left" |
|
99 |
android:orientation="horizontal"> |
|
100 |
|
|
101 |
<Button |
|
102 |
android:id="@+id/level3" |
|
103 |
android:text="@string/level3" |
|
104 |
android:layout_width="wrap_content" |
|
105 |
android:layout_height="wrap_content" |
|
106 |
android:paddingRight="10dp" |
|
107 |
android:paddingLeft="10dp" |
|
108 |
android:backgroundTint="@color/dark_grey"/> |
|
109 |
<Button |
|
110 |
android:id="@+id/level4" |
|
111 |
android:text="@string/level4" |
|
112 |
android:layout_width="wrap_content" |
|
113 |
android:layout_height="wrap_content" |
|
114 |
android:paddingRight="10dp" |
|
115 |
android:paddingLeft="10dp" |
|
116 |
android:backgroundTint="@color/dark_grey"/> |
|
117 |
<Button |
|
118 |
android:id="@+id/level5" |
|
119 |
android:text="@string/level5" |
|
120 |
android:layout_width="wrap_content" |
|
121 |
android:layout_height="wrap_content" |
|
122 |
android:paddingRight="10dp" |
|
123 |
android:paddingLeft="10dp" |
|
124 |
android:backgroundTint="@color/dark_grey"/> |
|
125 |
</LinearLayout> |
|
126 |
|
|
127 |
<LinearLayout |
|
128 |
android:layout_width="match_parent" |
|
129 |
android:layout_height="wrap_content" |
|
130 |
android:gravity="left" |
|
131 |
android:orientation="horizontal"> |
|
132 |
|
|
133 |
<Button |
|
134 |
android:id="@+id/level6" |
|
135 |
android:text="@string/level6" |
|
136 |
android:layout_width="wrap_content" |
|
137 |
android:layout_height="wrap_content" |
|
138 |
android:paddingRight="10dp" |
|
139 |
android:paddingLeft="10dp" |
|
140 |
android:backgroundTint="@color/dark_grey"/> |
|
141 |
<Button |
|
142 |
android:id="@+id/level7" |
|
143 |
android:text="@string/level7" |
|
144 |
android:layout_width="wrap_content" |
|
145 |
android:layout_height="wrap_content" |
|
146 |
android:paddingRight="10dp" |
|
147 |
android:paddingLeft="10dp" |
|
148 |
android:backgroundTint="@color/dark_grey"/> |
|
149 |
<Button |
|
150 |
android:id="@+id/levelM" |
|
151 |
android:text="@string/levelM" |
|
152 |
android:layout_width="wrap_content" |
|
153 |
android:layout_height="wrap_content" |
|
154 |
android:paddingRight="10dp" |
|
155 |
android:paddingLeft="10dp" |
|
156 |
android:backgroundTint="@color/dark_grey"/> |
|
157 |
</LinearLayout> |
|
158 |
</LinearLayout> |
src/main/res/values-de/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">Melden Sie einen Fehler, schlagen Sie eine Funktion vor:</string> |
55 | 55 |
<string name="exit_app">App beenden?</string> |
56 | 56 |
|
57 |
<string name="object_solver">Löser</string> |
|
58 |
<string name="object_pattern">Muster</string> |
|
59 |
<string name="object_tutorial">Tutorials</string> |
|
60 |
<string name="object_info">Info</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">Sterne</string> |
58 | 63 |
<string name="scores">Highscores</string> |
59 | 64 |
<string name="patterns">Hübsche Muster</string> |
60 | 65 |
<string name="control">Den Würfel steuern</string> |
61 | 66 |
<string name="solver">Löser</string> |
62 |
<string name="tutorials">Lernprogrammen</string>
|
|
67 |
<string name="tutorials">Tutorials</string>
|
|
63 | 68 |
<string name="about">Über die App</string> |
64 | 69 |
<string name="bandaged">Bandaged</string> |
65 | 70 |
|
src/main/res/values-es/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">Reportar un error, sugerir una función:</string> |
55 | 55 |
<string name="exit_app">¿Salir de la aplicación?</string> |
56 | 56 |
|
57 |
<string name="object_solver">Solucionador</string> |
|
58 |
<string name="object_pattern">Patrones</string> |
|
59 |
<string name="object_tutorial">Tutoriales</string> |
|
60 |
<string name="object_info">Información</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">Estrellas</string> |
58 | 63 |
<string name="scores">Leaderboard</string> |
59 | 64 |
<string name="patterns">Patrones</string> |
src/main/res/values-fr/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">Signaler un bug, suggérer une fonctionnalité :</string> |
55 | 55 |
<string name="exit_app">Quitter l\'application ?</string> |
56 | 56 |
|
57 |
<string name="object_solver">Solveur</string> |
|
58 |
<string name="object_pattern">Motifs</string> |
|
59 |
<string name="object_tutorial">Tutoriels</string> |
|
60 |
<string name="object_info">Info</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">Étoiles</string> |
58 | 63 |
<string name="scores">Meilleurs scores</string> |
59 | 64 |
<string name="patterns">Jolis motifs</string> |
src/main/res/values-ja/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">バグを報告し、機能を提案してください:</string> |
55 | 55 |
<string name="exit_app">アプリを終了しますか?</string> |
56 | 56 |
|
57 |
<string name="object_solver">ソルバー</string> |
|
58 |
<string name="object_pattern">パターン</string> |
|
59 |
<string name="object_tutorial">チュートリアル</string> |
|
60 |
<string name="object_info">情報</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">星</string> |
58 | 63 |
<string name="scores">ハイスコア</string> |
59 | 64 |
<string name="patterns">プリティパターン</string> |
src/main/res/values-ko/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">버그 신고, 기능 제안:</string> |
55 | 55 |
<string name="exit_app">앱을 종료하시겠습니까?</string> |
56 | 56 |
|
57 |
<string name="object_solver">솔버</string> |
|
58 |
<string name="object_pattern">패턴</string> |
|
59 |
<string name="object_tutorial">튜토리얼</string> |
|
60 |
<string name="object_info">정보</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">별</string> |
58 | 63 |
<string name="scores">고득점</string> |
59 | 64 |
<string name="patterns">예쁜 패턴</string> |
src/main/res/values-pl/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">Zaraportuj błąd, zadaj pytanie:</string> |
55 | 55 |
<string name="exit_app">Wyjść z apki?</string> |
56 | 56 |
|
57 |
<string name="object_solver">Rozwiązywacz</string> |
|
58 |
<string name="object_pattern">Wzory</string> |
|
59 |
<string name="object_tutorial">Tutoriale</string> |
|
60 |
<string name="object_info">Info</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">Gwiazdki</string> |
58 | 63 |
<string name="scores">Lista najlepszych</string> |
59 | 64 |
<string name="patterns">Piękne Wzory</string> |
src/main/res/values-ru/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">Сообщить об ошибке, задать вопрос:</string> |
55 | 55 |
<string name="exit_app">Выйти из приложения?</string> |
56 | 56 |
|
57 |
<string name="object_solver">Решатель</string> |
|
58 |
<string name="object_pattern">Узоры</string> |
|
59 |
<string name="object_tutorial">Учебники</string> |
|
60 |
<string name="object_info">Инфо</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">Звезды</string> |
58 | 63 |
<string name="scores">Высокие баллы</string> |
59 | 64 |
<string name="patterns">Красивые узоры</string> |
src/main/res/values-zh-rCN/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">报告错误,提出问题:</string> |
55 | 55 |
<string name="exit_app">退出应用程序?</string> |
56 | 56 |
|
57 |
<string name="object_solver">求解器</string> |
|
58 |
<string name="object_pattern">图案</string> |
|
59 |
<string name="object_tutorial">教程</string> |
|
60 |
<string name="object_info">信息</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">星星</string> |
58 | 63 |
<string name="scores">高分</string> |
59 | 64 |
<string name="patterns">模式</string> |
src/main/res/values-zh-rTW/strings.xml | ||
---|---|---|
54 | 54 |
<string name="email">报告错误,提出问题:</string> |
55 | 55 |
<string name="exit_app">退出應用程式?</string> |
56 | 56 |
|
57 |
<string name="object_solver">求解器</string> |
|
58 |
<string name="object_pattern">圖案</string> |
|
59 |
<string name="object_tutorial">教學</string> |
|
60 |
<string name="object_info">資訊</string> |
|
61 |
|
|
57 | 62 |
<string name="stars">星星</string> |
58 | 63 |
<string name="scores">高分</string> |
59 | 64 |
<string name="patterns">模式</string> |
src/main/res/values/strings.xml | ||
---|---|---|
71 | 71 |
<string name="buy_string1">You have %1$d stars.</string> |
72 | 72 |
<string name="buy_string2">Earn stars by solving puzzles. You can also buy stars.</string> |
73 | 73 |
|
74 |
<string name="object_solver">Solver</string> |
|
75 |
<string name="object_pattern">Patterns</string> |
|
76 |
<string name="object_tutorial">Tutorials</string> |
|
77 |
<string name="object_info">Info</string> |
|
78 |
|
|
79 |
<string name="level0" translatable="false">0</string> |
|
74 | 80 |
<string name="level1" translatable="false">1</string> |
75 | 81 |
<string name="level2" translatable="false">2</string> |
76 | 82 |
<string name="level3" translatable="false">3</string> |
Also available in: Unified diff
Major progress with version 2.0.0.