Project

General

Profile

« Previous | Next » 

Revision d7f0c07d

Added by Leszek Koltunski over 1 year ago

Beginnings of support for 'Overlays': first overlay will be the rotating star which little stars fly to when one solves a level for the first time.

View differences:

src/main/java/org/distorted/external/RubikScores.java
45 45
  private int mNumPlays;
46 46
  private int mNumWins;
47 47
  private int mDeviceID;
48
  private int mNumStars;
48 49

  
49 50
  private static class MapValue
50 51
    {
......
75 76
    mNumRuns = -1;
76 77
    mDeviceID= -1;
77 78
    mNumWins =  0;
79
    mNumStars=  0;
78 80
    }
79 81

  
80 82
///////////////////////////////////////////////////////////////////////////////////////////////////
......
233 235
    return mNumWins;
234 236
    }
235 237

  
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

  
240
  public void changeNumStars(int stars)
241
    {
242
    mNumStars += stars;
243
    }
244

  
245
///////////////////////////////////////////////////////////////////////////////////////////////////
246

  
247
  public int getNumStars()
248
    {
249
    return mNumStars;
250
    }
251

  
236 252
///////////////////////////////////////////////////////////////////////////////////////////////////
237 253

  
238 254
  public void setName(String newName)
......
360 376
    editor.putInt("scores_numPlays", mNumPlays);
361 377
    editor.putInt("scores_numRuns" , mNumRuns );
362 378
    editor.putInt("scores_deviceid", mDeviceID);
363
    editor.putInt("scores_review"  , mNumWins );
379
    editor.putInt("scores_review"  , mNumWins );   // legacy name
380
    editor.putInt("scores_numStars", mNumStars );
364 381
    }
365 382

  
366 383
///////////////////////////////////////////////////////////////////////////////////////////////////
......
431 448
    mNumRuns        = preferences.getInt("scores_numRuns" , 0);
432 449
    mDeviceID       = preferences.getInt("scores_deviceid",-1);
433 450
    mNumWins        = preferences.getInt("scores_review"  , 0);
451
    mNumStars       = preferences.getInt("scores_numStars", 0);
434 452

  
435 453
    if( mDeviceID==-1 ) mDeviceID = privateGetDeviceID();
436 454

  
src/main/java/org/distorted/main/RubikActivity.java
37 37
import org.distorted.bandaged.BandagedCreatorActivity;
38 38
import org.distorted.library.main.DistortedLibrary;
39 39

  
40
import org.distorted.library.main.DistortedScreen;
40 41
import org.distorted.messaging.RubikInAppMessanging;
41 42
import org.distorted.objectlib.main.ObjectControl;
42 43
import org.distorted.objectlib.main.TwistyObject;
......
456 457
      return view.getObjectControl().getObject();
457 458
      }
458 459

  
460
///////////////////////////////////////////////////////////////////////////////////////////////////
461

  
462
    public DistortedScreen getScreen()
463
      {
464
      RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
465
      return view.getRenderer().getScreen();
466
      }
467

  
459 468
///////////////////////////////////////////////////////////////////////////////////////////////////
460 469

  
461 470
    public ObjectControl getControl()
src/main/java/org/distorted/main/RubikObjectLibInterface.java
22 22
import com.google.firebase.analytics.FirebaseAnalytics;
23 23
import com.google.firebase.crashlytics.FirebaseCrashlytics;
24 24

  
25
import org.distorted.library.main.DistortedScreen;
25 26
import org.distorted.library.message.EffectMessageSender;
26 27

  
27 28
import org.distorted.external.RubikNetwork;
......
35 36
import org.distorted.external.RubikScores;
36 37
import org.distorted.objects.RubikObject;
37 38
import org.distorted.objects.RubikObjectList;
39
import org.distorted.overlays.DataStars;
40
import org.distorted.overlays.ListenerOverlay;
41
import org.distorted.overlays.OverlayStars;
38 42
import org.distorted.screens.RubikScreenPlay;
39 43
import org.distorted.screens.RubikScreenReady;
40 44
import org.distorted.screens.RubikScreenSolver;
......
45 49
import java.lang.ref.WeakReference;
46 50

  
47 51
import static org.distorted.external.RubikScores.RECORD_FIRST;
52
import static org.distorted.external.RubikScores.RECORD_NEW;
48 53
import static org.distorted.external.RubikScores.RECORD_NOT_NEW;
49 54

  
50 55
///////////////////////////////////////////////////////////////////////////////////////////////////
51 56

  
52
public class RubikObjectLibInterface implements ObjectLibInterface
57
public class RubikObjectLibInterface implements ObjectLibInterface, ListenerOverlay
53 58
{
54 59
  private final WeakReference<RubikActivity> mAct;
55 60
  private int mIsNewRecord;
......
185 190
      }
186 191
    }
187 192

  
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189

  
190
  public void onWinEffectFinished(long startTime, long endTime, String debug, int scrambleNum)
191
    {
192
    if( ScreenList.getCurrentScreen()== ScreenList.SOLV )
193
      {
194
      RubikActivity act = mAct.get();
195
      Bundle bundle = new Bundle();
196
      bundle.putLong("time", mNewRecord );
197

  
198
      reportRecord(act,startTime,endTime,debug,scrambleNum);
199
      requestReview(act);
200

  
201
      if( mIsNewRecord!=RECORD_NOT_NEW )
202
        {
203
        if( mIsNewRecord==RECORD_FIRST && RubikObjectList.thereAreLockedObjects() )
204
          {
205

  
206
          }
207
        else
208
          {
209
          RubikDialogNewRecord dialog = new RubikDialogNewRecord();
210
          dialog.setArguments(bundle);
211
          dialog.show( act.getSupportFragmentManager(), RubikDialogNewRecord.getDialogTag() );
212
          }
213
        }
214
      else
215
        {
216
        RubikDialogSolved dialog = new RubikDialogSolved();
217
        dialog.setArguments(bundle);
218
        dialog.show( act.getSupportFragmentManager(), RubikDialogSolved.getDialogTag() );
219
        }
220

  
221
      act.runOnUiThread(new Runnable()
222
        {
223
        @Override
224
        public void run()
225
          {
226
          ScreenList.switchScreen( act, ScreenList.DONE);
227
          }
228
        });
229
      }
230
    }
231

  
232 193
///////////////////////////////////////////////////////////////////////////////////////////////////
233 194

  
234 195
  public void onScrambleEffectFinished()
......
473 434
      mLastCubitColor = -1;
474 435
      }
475 436
    }
437

  
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

  
440
  public void onWinEffectFinished(long startTime, long endTime, String debug, int scrambleNum)
441
    {
442
    if( ScreenList.getCurrentScreen()== ScreenList.SOLV )
443
      {
444
      RubikActivity act = mAct.get();
445
      Bundle bundle = new Bundle();
446
      bundle.putLong("time", mNewRecord );
447

  
448
      reportRecord(act,startTime,endTime,debug,scrambleNum);
449
      requestReview(act);
450

  
451
      switch(mIsNewRecord)
452
        {
453
        case RECORD_FIRST  : RubikScreenPlay play = (RubikScreenPlay) ScreenList.PLAY.getScreenClass();
454
                             int level = play.getLevel();
455
                             RubikScores scores = RubikScores.getInstance();
456
                             int totStars = scores.getNumStars();
457
                             int newStars = RubikObjectList.computeNumStars(level);
458
                             DistortedScreen screen = act.getScreen();
459

  
460
                             OverlayStars stars = new OverlayStars();
461
                             DataStars data  = new DataStars(totStars,newStars,act.getResources());
462
                             stars.startOverlay(screen,this,data);
463
                             break;
464
        case RECORD_NEW    : RubikDialogNewRecord d2 = new RubikDialogNewRecord();
465
                             d2.setArguments(bundle);
466
                             d2.show( act.getSupportFragmentManager(), RubikDialogNewRecord.getDialogTag() );
467
                             break;
468
        case RECORD_NOT_NEW: RubikDialogSolved d3 = new RubikDialogSolved();
469
                             d3.setArguments(bundle);
470
                             d3.show( act.getSupportFragmentManager(), RubikDialogSolved.getDialogTag() );
471
                             break;
472
        }
473

  
474
      act.runOnUiThread(new Runnable()
475
        {
476
        @Override
477
        public void run()
478
          {
479
          ScreenList.switchScreen( act, ScreenList.DONE);
480
          }
481
        });
482
      }
483
    }
484

  
485
///////////////////////////////////////////////////////////////////////////////////////////////////
486

  
487
  public void overlayFinished(long id)
488
    {
489
    RubikActivity act = mAct.get();
490
    Bundle bundle = new Bundle();
491
    bundle.putLong("time", mNewRecord );
492

  
493
    RubikDialogNewRecord d2 = new RubikDialogNewRecord();
494
    d2.setArguments(bundle);
495
    d2.show( act.getSupportFragmentManager(), RubikDialogNewRecord.getDialogTag() );
496
    }
476 497
}
src/main/java/org/distorted/objects/RubikObjectList.java
20 20
import org.distorted.main.RubikActivity;
21 21
import org.distorted.objectlib.main.ObjectSignatures;
22 22
import org.distorted.objectlib.main.ObjectType;
23
import org.distorted.screens.RubikScreenPlay;
24 23

  
25 24
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
26 25
import static org.distorted.objectlib.main.ObjectType.NUM_OBJECTS;
27 26
import static org.distorted.main.RubikActivity.SHOW_DOWNLOADED_DEBUG;
28 27
import static org.distorted.main.RubikActivity.SHOW_SOLVED_DEBUG;
28
import static org.distorted.screens.RubikScreenPlay.LEVELS_SHOWN;
29 29

  
30 30
///////////////////////////////////////////////////////////////////////////////////////////////////
31 31

  
......
147 147
    return true;
148 148
    }
149 149

  
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

  
152
  public static int computeNumStars(int level)
153
    {
154
    return level>=LEVELS_SHOWN ? 50 : level+1;
155
    }
156

  
150 157
///////////////////////////////////////////////////////////////////////////////////////////////////
151 158

  
152 159
  private static void restoreFreedObjects(SharedPreferences preferences)
......
210 217
    {
211 218
    RubikScores scores = RubikScores.getInstance();
212 219
    int numObjects = RubikObjectList.getNumObjects();
213
    int level = RubikScreenPlay.LEVELS_SHOWN;
220
    int level = LEVELS_SHOWN;
214 221
    int ret = 0;
215 222

  
216 223
    for(int obj=0; obj<numObjects; obj++)
src/main/java/org/distorted/overlays/DataGeneric.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.overlays;
11

  
12
///////////////////////////////////////////////////////////////////////////////////////////////////
13

  
14
public abstract class DataGeneric
15
{
16

  
17

  
18
}
src/main/java/org/distorted/overlays/DataStars.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.overlays;
11

  
12
///////////////////////////////////////////////////////////////////////////////////////////////////
13

  
14
import android.content.res.Resources;
15

  
16
public class DataStars extends DataGeneric
17
{
18
  private final int mTotStars, mNewStars;
19
  private final Resources mRes;
20

  
21
///////////////////////////////////////////////////////////////////////////////////////////////////
22

  
23
  public DataStars(int totStars, int newStars, Resources res)
24
    {
25
    mTotStars = totStars;
26
    mNewStars = newStars;
27
    mRes = res;
28
    }
29

  
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31

  
32
  int getTotal()
33
    {
34
    return mTotStars;
35
    }
36

  
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

  
39
  int getNew()
40
    {
41
    return mNewStars;
42
    }
43

  
44
///////////////////////////////////////////////////////////////////////////////////////////////////
45

  
46
  Resources getResources()
47
    {
48
    return mRes;
49
    }
50
}
src/main/java/org/distorted/overlays/ListenerOverlay.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.overlays;
11

  
12
///////////////////////////////////////////////////////////////////////////////////////////////////
13

  
14
public interface ListenerOverlay
15
{
16
  void overlayFinished(long id);
17
}
src/main/java/org/distorted/overlays/OverlayGeneric.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.overlays;
11

  
12
import org.distorted.library.main.DistortedScreen;
13

  
14
///////////////////////////////////////////////////////////////////////////////////////////////////
15

  
16
public abstract class OverlayGeneric
17
{
18
   public abstract long startOverlay(DistortedScreen screen, ListenerOverlay listener, DataGeneric data);
19
}
src/main/java/org/distorted/overlays/OverlayStars.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.overlays;
11

  
12
import android.content.res.Resources;
13
import android.graphics.Bitmap;
14
import android.graphics.BitmapFactory;
15

  
16
import org.distorted.library.effect.MatrixEffectRotate;
17
import org.distorted.library.effect.MatrixEffectScale;
18
import org.distorted.library.main.DistortedEffects;
19
import org.distorted.library.main.DistortedNode;
20
import org.distorted.library.main.DistortedScreen;
21
import org.distorted.library.main.DistortedTexture;
22
import org.distorted.library.mesh.MeshQuad;
23
import org.distorted.library.message.EffectListener;
24
import org.distorted.library.type.Dynamic1D;
25
import org.distorted.library.type.Static1D;
26
import org.distorted.library.type.Static3D;
27
import org.distorted.main.R;
28

  
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30

  
31
public class OverlayStars extends OverlayGeneric implements EffectListener
32
{
33
   private ListenerOverlay mListener;
34
   private DistortedNode mNode;
35
   private DistortedScreen mScreen;
36

  
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

  
39
   private DistortedNode createNode(Resources res, int totS, int newS)
40
      {
41
      Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable.star);
42
      DistortedTexture texture = new DistortedTexture();
43
      texture.setTexture(bmp);
44

  
45
      float scale = 10;
46

  
47
      Static1D point0   = new Static1D(0);
48
      Static1D point360 = new Static1D(360);
49
      Dynamic1D angle   = new Dynamic1D();
50
      angle.add(point0);
51
      angle.add(point360);
52
      angle.setCount(1.0f);
53
      angle.setDuration(5000);
54
      Static3D axis = new Static3D(0,0,1);
55
      Static3D center = new Static3D(0,0,0);
56

  
57
      DistortedEffects effects = new DistortedEffects();
58
      MatrixEffectScale scaleEffect = new MatrixEffectScale(scale);
59
      MatrixEffectRotate rotateEffect = new MatrixEffectRotate(angle,axis,center);
60
      effects.apply(scaleEffect);
61
      effects.apply(rotateEffect);
62

  
63
      rotateEffect.notifyWhenFinished(this);
64

  
65
      MeshQuad mesh = new MeshQuad();
66

  
67
      return new DistortedNode(texture,effects,mesh);
68
      }
69

  
70
///////////////////////////////////////////////////////////////////////////////////////////////////
71

  
72
   public long startOverlay(DistortedScreen screen, ListenerOverlay listener, DataGeneric data)
73
      {
74
      mScreen = screen;
75
      mListener= listener;
76
      DataStars stars = (DataStars)data;
77
      int totS = stars.getTotal();
78
      int newS = stars.getNew();
79
      Resources res = stars.getResources();
80

  
81
      mNode = createNode(res,totS,newS);
82
      mScreen.attach(mNode);
83

  
84
      return 0;
85
      }
86

  
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

  
89
   public void effectFinished(long id)
90
      {
91
      mScreen.detach(mNode);
92
      mListener.overlayFinished(id);
93
      }
94
}
src/main/res/layout/dialog_new_record.xml
26 26
            android:layout_marginRight="10dp"
27 27
            android:layout_marginBottom="10dp"/>
28 28

  
29
         <TextView
29
        <TextView
30 30
            android:id="@+id/new_record_submit"
31 31
            android:layout_width="match_parent"
32 32
            android:layout_height="match_parent"
src/main/res/values-de/strings.xml
92 92

  
93 93
    <string name="ms_placeholder">%1$d ms</string>
94 94
    <string name="lv_placeholder">Level %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
97 95
    <string name="ti_placeholder">%1$.2f Sekunden</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values-es/strings.xml
92 92

  
93 93
    <string name="ms_placeholder">%1$d ms</string>
94 94
    <string name="lv_placeholder">Nivel %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
97 95
    <string name="ti_placeholder">%1$.2f segundos</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values-fr/strings.xml
92 92

  
93 93
    <string name="ms_placeholder">%1$d ms</string>
94 94
    <string name="lv_placeholder">Niveau %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
97 95
    <string name="ti_placeholder">%1$.2f secondes</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values-ja/strings.xml
6 6
    <string name="error">エラー</string>
7 7
    <string name="effects">エフェクト</string>
8 8
    <string name="choose_pattern">パターンを選択</string>
9
    <string name="solved">解答済</string>
9
    <string name="solved">解決済み</string>
10 10
    <string name="new_record">新記録</string>
11 11
    <string name="new_record_submit">ハイスコアに提出しますか?</string>
12 12
    <string name="back">戻る</string>
......
92 92

  
93 93
    <string name="ms_placeholder">%1$d ms</string>
94 94
    <string name="lv_placeholder">レベル %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
97 95
    <string name="ti_placeholder">%1$.2f 秒</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values-ko/strings.xml
92 92

  
93 93
    <string name="ms_placeholder">%1$d ms</string>
94 94
    <string name="lv_placeholder">레벨 %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
97 95
    <string name="ti_placeholder">%1$.2f 초</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values-pl/strings.xml
92 92

  
93 93
    <string name="ms_placeholder">%1$d ms</string>
94 94
    <string name="lv_placeholder">Poziom %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
97 95
    <string name="ti_placeholder">%1$.2f sekund</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values-ru/strings.xml
92 92

  
93 93
    <string name="ms_placeholder">%1$d мс</string>
94 94
    <string name="lv_placeholder">Уровень %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
97 95
    <string name="ti_placeholder">%1$.2f сек.</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values-zh-rCN/strings.xml
96 96
    <string name="color_red">红色的</string>
97 97
    <string name="color_orange">橙色的</string>
98 98

  
99
    <string name="ms_placeholder">%1$d 毫秒</string>
100
    <string name="lv_placeholder">级别 %1$d</string>
101
    <string name="tm_placeholder">%1$02d:%2$02d</string>
102
    <string name="ap_placeholder">%1$s %2$s</string>
99
    <string name="ms_placeholder">%1$d毫秒</string>
100
    <string name="lv_placeholder">%1$d级</string>
103 101
    <string name="ti_placeholder">%1$.2f 秒</string>
104
    <string name="mo_placeholder">%1$d/%2$d</string>
105 102
</resources>
src/main/res/values-zh-rTW/strings.xml
90 90
    <string name="color_red">紅色的</string>
91 91
    <string name="color_orange">橙色的</string>
92 92

  
93
    <string name="ms_placeholder">%1$d 毫秒</string>
94
    <string name="lv_placeholder">級別 %1$d</string>
95
    <string name="tm_placeholder">%1$02d:%2$02d</string>
96
    <string name="ap_placeholder">%1$s %2$s</string>
93
    <string name="ms_placeholder">%1$d毫秒</string>
94
    <string name="lv_placeholder">%1$d級</string>
97 95
    <string name="ti_placeholder">%1$.2f 秒</string>
98
    <string name="mo_placeholder">%1$d/%2$d</string>
99 96
</resources>
src/main/res/values/strings.xml
110 110
    <string name="color_red">red</string>
111 111
    <string name="color_orange">orange</string>
112 112

  
113
    <string name="ns_placeholder" translatable="false">+%1$d</string>
114
    <string name="sq_placeholder" translatable="false">%1$2d.</string>
115
    <string name="mo_placeholder" translatable="false">%1$d/%2$d</string>
116
    <string name="tm_placeholder" translatable="false">%1$02d:%2$02d</string>
117
    <string name="ap_placeholder" translatable="false">%1$s %2$s</string>
118

  
113 119
    <string name="ms_placeholder">%1$d ms</string>
114 120
    <string name="lv_placeholder">Level %1$d</string>
115
    <string name="tm_placeholder">%1$02d:%2$02d</string>
116
    <string name="ap_placeholder">%1$s %2$s</string>
117 121
    <string name="ti_placeholder">%1$.2f seconds</string>
118
    <string name="mo_placeholder">%1$d/%2$d</string>
119
    <string name="sq_placeholder" translatable="false">%1$2d.</string>
120 122

  
121 123
</resources>

Also available in: Unified diff