mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 00774368d4 | |||
| cbf1bd3e19 | |||
| 4061921b93 | |||
| 59d42fe62f | |||
| 88e8aad0d8 | |||
| a4b6728721 | |||
| 33bc8f78e7 | |||
| 0f223f8504 | |||
| 007996c69e | |||
| ff9d50b32a | |||
| 38024d71ce | |||
| 9ec1afc208 | |||
| e0888a9b4d | |||
| 8aade2f145 | |||
| 1ba1d775f7 | |||
| bd6cba8303 | |||
| befc3a0ad8 | |||
| f4c963e2c1 | |||
| e9a4a047c1 | |||
| 7ce1988d2e | |||
| 53911fa410 | |||
| f5f43d9a16 | |||
| d0e475ad78 | |||
| b3199cf092 | |||
| 73e6f2a2d4 |
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,5 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
### 1.5.4 (May 29, 2016)
|
||||
|
||||
* Fix crash upon opening settings screen in some phones
|
||||
* Fix missing folders in CSV archive
|
||||
* Add Serbian translation
|
||||
|
||||
### 1.5.3 (May 22, 2016)
|
||||
|
||||
* Complete Arabic and Czech translations
|
||||
* Fix crash at startup
|
||||
* Fix checkmark widget on custom launchers
|
||||
|
||||
### 1.5.2 (May 19, 2016)
|
||||
|
||||
* Fix missing attachment on bug reports
|
||||
* Fix bug that prevents some widgets from rendering
|
||||
* Complete Japanese translation
|
||||
|
||||
### 1.5.1 (May 17, 2016)
|
||||
|
||||
* Fix build on F-Droid
|
||||
|
||||
### 1.5.0 (May 15, 2016)
|
||||
|
||||
* Add night mode, with AMOLED support
|
||||
@@ -82,4 +104,4 @@
|
||||
|
||||
### 1.0.0 (February 19, 2016)
|
||||
|
||||
* Initial release
|
||||
* Initial release
|
||||
|
||||
@@ -39,8 +39,9 @@ dependencies {
|
||||
compile 'com.github.paolorotolo:appintro:3.4.0'
|
||||
compile 'org.apmem.tools:layouts:1.10@aar'
|
||||
compile 'com.opencsv:opencsv:3.7'
|
||||
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
|
||||
|
||||
compile project(':libs:drag-sort-listview:library')
|
||||
compile files('libs/ActiveAndroid.jar')
|
||||
|
||||
androidTestCompile 'com.android.support:support-annotations:23.3.0'
|
||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
||||
|
||||
Binary file not shown.
@@ -21,8 +21,8 @@
|
||||
<manifest
|
||||
package="org.isoron.uhabits"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="16"
|
||||
android:versionName="1.5.0">
|
||||
android:versionCode="20"
|
||||
android:versionName="1.5.4">
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
|
||||
try
|
||||
{
|
||||
ex.printStackTrace();
|
||||
HabitsApplication.generateLogFile();
|
||||
HabitsApplication.dumpBugReportToFile();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class HabitsApplication extends Application
|
||||
{
|
||||
@@ -87,6 +88,7 @@ public class HabitsApplication extends Application
|
||||
|
||||
public static String getLogcat() throws IOException
|
||||
{
|
||||
int maxNLines = 250;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
String[] command = new String[] { "logcat", "-d"};
|
||||
@@ -95,10 +97,18 @@ public class HabitsApplication extends Application
|
||||
InputStreamReader in = new InputStreamReader(process.getInputStream());
|
||||
BufferedReader bufferedReader = new BufferedReader(in);
|
||||
|
||||
LinkedList<String> log = new LinkedList<>();
|
||||
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null)
|
||||
{
|
||||
builder.append(line);
|
||||
log.addLast(line);
|
||||
if(log.size() > maxNLines) log.removeFirst();
|
||||
}
|
||||
|
||||
for(String l : log)
|
||||
{
|
||||
builder.append(l);
|
||||
builder.append('\n');
|
||||
}
|
||||
|
||||
@@ -130,10 +140,8 @@ public class HabitsApplication extends Application
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static File generateLogFile() throws IOException
|
||||
public static File dumpBugReportToFile() throws IOException
|
||||
{
|
||||
String logcat = getLogcat();
|
||||
String deviceInfo = getDeviceInfo();
|
||||
String date = DateHelper.getBackupDateFormat().format(DateHelper.getLocalTime());
|
||||
|
||||
if(context == null) throw new RuntimeException("application context should not be null");
|
||||
@@ -142,10 +150,17 @@ public class HabitsApplication extends Application
|
||||
|
||||
File logFile = new File(String.format("%s/Log %s.txt", dir.getPath(), date));
|
||||
FileWriter output = new FileWriter(logFile);
|
||||
output.write(deviceInfo);
|
||||
output.write(logcat);
|
||||
output.write(generateBugReport());
|
||||
output.close();
|
||||
|
||||
return logFile;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String generateBugReport() throws IOException
|
||||
{
|
||||
String logcat = getLogcat();
|
||||
String deviceInfo = getDeviceInfo();
|
||||
return deviceInfo + "\n" + logcat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ import org.isoron.uhabits.widgets.HistoryWidgetProvider;
|
||||
import org.isoron.uhabits.widgets.ScoreWidgetProvider;
|
||||
import org.isoron.uhabits.widgets.StreakWidgetProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MainActivity extends BaseActivity
|
||||
@@ -239,12 +238,25 @@ public class MainActivity extends BaseActivity
|
||||
{
|
||||
try
|
||||
{
|
||||
File logFile = HabitsApplication.generateLogFile();
|
||||
HabitsApplication.dumpBugReportToFile();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String log = "---------- BUG REPORT BEGINS ----------\n";
|
||||
log += HabitsApplication.generateBugReport();
|
||||
log += "---------- BUG REPORT ENDS ------------\n";
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_SENDTO);
|
||||
intent.setData(Uri.parse(getString(R.string.bugReportURL)));
|
||||
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(logFile));
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.setType("message/rfc822");
|
||||
intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "dev@loophabits.org" });
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, "Bug Report - Loop Habit Tracker");
|
||||
intent.putExtra(Intent.EXTRA_TEXT, log);
|
||||
startActivity(intent);
|
||||
}
|
||||
catch (IOException e)
|
||||
|
||||
@@ -134,6 +134,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
private void updateRingtoneDescription()
|
||||
{
|
||||
String ringtoneName = ReminderHelper.getRingtoneName(getContext());
|
||||
if(ringtoneName == null) return;
|
||||
Preference ringtonePreference = findPreference("reminderSound");
|
||||
ringtonePreference.setSummary(ringtoneName);
|
||||
}
|
||||
|
||||
@@ -93,8 +93,9 @@ public class ReminderHelper
|
||||
else
|
||||
manager.set(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent);
|
||||
|
||||
String name = habit.name.substring(0, Math.min(3, habit.name.length()));
|
||||
Log.d("ReminderHelper", String.format("Setting alarm (%s): %s",
|
||||
DateFormat.getDateTimeInstance().format(new Date(reminderTime)), habit.name));
|
||||
DateFormat.getDateTimeInstance().format(new Date(reminderTime)), name));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -143,21 +144,30 @@ public class ReminderHelper
|
||||
fragment.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getRingtoneName(Context context)
|
||||
{
|
||||
Uri ringtoneUri = getRingtoneUri(context);
|
||||
String ringtoneName = context.getResources().getString(R.string.none);
|
||||
|
||||
if(ringtoneUri != null)
|
||||
try
|
||||
{
|
||||
Ringtone ringtone = RingtoneManager.getRingtone(context, ringtoneUri);
|
||||
if(ringtone != null)
|
||||
{
|
||||
ringtoneName = ringtone.getTitle(context);
|
||||
ringtone.stop();
|
||||
}
|
||||
}
|
||||
Uri ringtoneUri = getRingtoneUri(context);
|
||||
String ringtoneName = context.getResources().getString(R.string.none);
|
||||
|
||||
return ringtoneName;
|
||||
if (ringtoneUri != null)
|
||||
{
|
||||
Ringtone ringtone = RingtoneManager.getRingtone(context, ringtoneUri);
|
||||
if (ringtone != null)
|
||||
{
|
||||
ringtoneName = ringtone.getTitle(context);
|
||||
ringtone.stop();
|
||||
}
|
||||
}
|
||||
|
||||
return ringtoneName;
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ public abstract class UIHelper
|
||||
{
|
||||
// TODO: Move this to another place, or detect automatically
|
||||
String fullyTranslatedLanguages[] = { "ca", "zh", "en", "de", "in", "it", "ko", "pl", "pt",
|
||||
"es", "tk", "uk"};
|
||||
"es", "tk", "uk", "ja"};
|
||||
|
||||
final String currentLanguage = Locale.getDefault().getLanguage();
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
package org.isoron.uhabits.io;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.isoron.uhabits.helpers.DateHelper;
|
||||
import org.isoron.uhabits.models.CheckmarkList;
|
||||
import org.isoron.uhabits.models.Habit;
|
||||
@@ -64,7 +66,10 @@ public class HabitsCSVExporter
|
||||
|
||||
for(Habit h : habits)
|
||||
{
|
||||
String habitDirName = String.format("%03d %s/", h.position + 1, h.name);
|
||||
String sane = sanitizeFilename(h.name);
|
||||
String habitDirName = String.format("%03d %s", h.position + 1, sane);
|
||||
habitDirName = habitDirName.trim() + "/";
|
||||
|
||||
new File(exportDirName + habitDirName).mkdirs();
|
||||
generateDirs.add(habitDirName);
|
||||
|
||||
@@ -73,6 +78,13 @@ public class HabitsCSVExporter
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String sanitizeFilename(String name)
|
||||
{
|
||||
String s = name.replaceAll("[^a-zA-Z0-9\\._-]+", "");
|
||||
return s.substring(0, Math.min(s.length(), 100));
|
||||
}
|
||||
|
||||
private void writeScores(String habitDirName, ScoreList scores) throws IOException
|
||||
{
|
||||
String path = habitDirName + "Scores.csv";
|
||||
|
||||
@@ -489,7 +489,7 @@ public class Habit extends Model
|
||||
*/
|
||||
public static void writeCSV(List<Habit> habits, Writer out) throws IOException
|
||||
{
|
||||
String header[] = { "Name", "Description", "NumRepetitions", "Interval", "Color" };
|
||||
String header[] = { "Position", "Name", "Description", "NumRepetitions", "Interval", "Color" };
|
||||
|
||||
CSVWriter csv = new CSVWriter(out);
|
||||
csv.writeNext(header, false);
|
||||
@@ -498,6 +498,7 @@ public class Habit extends Model
|
||||
{
|
||||
String[] cols =
|
||||
{
|
||||
String.format("%03d", habit.position + 1),
|
||||
habit.name,
|
||||
habit.description,
|
||||
Integer.toString(habit.freqNum),
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.isoron.uhabits.R;
|
||||
@@ -40,7 +41,6 @@ public class CheckmarkWidgetView extends HabitWidgetView implements HabitDataVie
|
||||
@Nullable
|
||||
private String name;
|
||||
|
||||
@Nullable
|
||||
private RingView ring;
|
||||
private TextView label;
|
||||
private int checkmarkValue;
|
||||
@@ -147,8 +147,22 @@ public class CheckmarkWidgetView extends HabitWidgetView implements HabitDataVie
|
||||
w *= scale;
|
||||
h *= scale;
|
||||
|
||||
if(h < getResources().getDimension(R.dimen.checkmarkWidget_heightBreakpoint))
|
||||
ring.setVisibility(GONE);
|
||||
else
|
||||
ring.setVisibility(VISIBLE);
|
||||
|
||||
widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) w, MeasureSpec.EXACTLY);
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) h, MeasureSpec.EXACTLY);
|
||||
|
||||
float textSize = 0.15f * h;
|
||||
float maxTextSize = getResources().getDimension(R.dimen.smallerTextSize);
|
||||
textSize = Math.min(textSize, maxTextSize);
|
||||
|
||||
label.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
|
||||
ring.setTextSize(textSize);
|
||||
ring.setThickness(0.15f * textSize);
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextPaint;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
@@ -57,8 +58,10 @@ public class RingView extends View
|
||||
private float textSize;
|
||||
private boolean enableFontAwesome;
|
||||
|
||||
@Nullable
|
||||
private Bitmap drawingCache;
|
||||
private Canvas cacheCanvas;
|
||||
|
||||
private boolean isTransparencyEnabled;
|
||||
|
||||
public RingView(Context context)
|
||||
@@ -106,6 +109,11 @@ public class RingView extends View
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
public void setTextSize(float textSize)
|
||||
{
|
||||
this.textSize = textSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(int backgroundColor)
|
||||
{
|
||||
@@ -175,12 +183,14 @@ public class RingView extends View
|
||||
{
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
if(isTransparencyEnabled)
|
||||
{
|
||||
if (drawingCache != null) drawingCache.recycle();
|
||||
drawingCache = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
|
||||
cacheCanvas = new Canvas(drawingCache);
|
||||
}
|
||||
if(isTransparencyEnabled) reallocateCache();
|
||||
}
|
||||
|
||||
private void reallocateCache()
|
||||
{
|
||||
if (drawingCache != null) drawingCache.recycle();
|
||||
drawingCache = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
|
||||
cacheCanvas = new Canvas(drawingCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,6 +201,7 @@ public class RingView extends View
|
||||
|
||||
if(isTransparencyEnabled)
|
||||
{
|
||||
if(drawingCache == null) reallocateCache();
|
||||
activeCanvas = cacheCanvas;
|
||||
drawingCache.eraseColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
@@ -45,9 +45,11 @@ import java.io.IOException;
|
||||
|
||||
public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
{
|
||||
|
||||
private int portraitWidth, portraitHeight;
|
||||
private int landscapeWidth, landscapeHeight;
|
||||
private class WidgetDimensions
|
||||
{
|
||||
public int portraitWidth, portraitHeight;
|
||||
public int landscapeWidth, landscapeHeight;
|
||||
}
|
||||
|
||||
protected abstract int getDefaultHeight();
|
||||
|
||||
@@ -71,7 +73,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
|
||||
|
||||
for(Integer id : appWidgetIds)
|
||||
prefs.edit().remove(getHabitIdKey(id));
|
||||
prefs.edit().remove(getHabitIdKey(id)).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,7 +100,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
private void updateWidget(Context context, AppWidgetManager manager,
|
||||
int widgetId, Bundle options)
|
||||
{
|
||||
updateWidgetSize(context, options);
|
||||
WidgetDimensions dim = getWidgetDimensions(context, options);
|
||||
|
||||
Context appContext = context.getApplicationContext();
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
|
||||
@@ -113,7 +115,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
return;
|
||||
}
|
||||
|
||||
new RenderWidgetTask(widgetId, context, habit, manager).execute();
|
||||
new RenderWidgetTask(widgetId, context, habit, dim, manager).execute();
|
||||
}
|
||||
|
||||
private void drawErrorWidget(Context context, AppWidgetManager manager, int widgetId)
|
||||
@@ -159,7 +161,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWidgetSize(Context context, Bundle options)
|
||||
private WidgetDimensions getWidgetDimensions(Context context, Bundle options)
|
||||
{
|
||||
int maxWidth = getDefaultWidth();
|
||||
int minWidth = getDefaultWidth();
|
||||
@@ -178,11 +180,12 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT));
|
||||
}
|
||||
|
||||
portraitWidth = minWidth;
|
||||
portraitHeight = maxHeight;
|
||||
|
||||
landscapeWidth = maxWidth;
|
||||
landscapeHeight = minHeight;
|
||||
WidgetDimensions ws = new WidgetDimensions();
|
||||
ws.portraitWidth = minWidth;
|
||||
ws.portraitHeight = maxHeight;
|
||||
ws.landscapeWidth = maxWidth;
|
||||
ws.landscapeHeight = minHeight;
|
||||
return ws;
|
||||
}
|
||||
|
||||
private void measureCustomView(Context context, int w, int h, View customView)
|
||||
@@ -212,16 +215,18 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
private final Context context;
|
||||
private final Habit habit;
|
||||
private final AppWidgetManager manager;
|
||||
public RemoteViews portraitRemoteViews, landscapeRemoteViews;
|
||||
public View portraitWidgetView, landscapeWidgetView;
|
||||
private RemoteViews portraitRemoteViews, landscapeRemoteViews;
|
||||
private View portraitWidgetView, landscapeWidgetView;
|
||||
private WidgetDimensions dim;
|
||||
|
||||
public RenderWidgetTask(int widgetId, Context context, Habit habit,
|
||||
public RenderWidgetTask(int widgetId, Context context, Habit habit, WidgetDimensions ws,
|
||||
AppWidgetManager manager)
|
||||
{
|
||||
this.widgetId = widgetId;
|
||||
this.context = context;
|
||||
this.habit = habit;
|
||||
this.manager = manager;
|
||||
this.dim = ws;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -232,11 +237,12 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
|
||||
portraitRemoteViews = new RemoteViews(context.getPackageName(), getLayoutId());
|
||||
portraitWidgetView = buildCustomView(context, habit);
|
||||
measureCustomView(context, portraitWidth, portraitHeight, portraitWidgetView);
|
||||
measureCustomView(context, dim.portraitWidth, dim.portraitHeight, portraitWidgetView);
|
||||
|
||||
landscapeRemoteViews = new RemoteViews(context.getPackageName(), getLayoutId());
|
||||
landscapeWidgetView = buildCustomView(context, habit);
|
||||
measureCustomView(context, landscapeWidth, landscapeHeight, landscapeWidgetView);
|
||||
measureCustomView(context, dim.landscapeWidth, dim.landscapeHeight,
|
||||
landscapeWidgetView);
|
||||
}
|
||||
|
||||
private void updateAppWidget()
|
||||
@@ -260,8 +266,10 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
{
|
||||
try
|
||||
{
|
||||
buildRemoteViews(portraitWidgetView, portraitRemoteViews, portraitWidth, portraitHeight);
|
||||
buildRemoteViews(landscapeWidgetView, landscapeRemoteViews, landscapeWidth, landscapeHeight);
|
||||
buildRemoteViews(portraitWidgetView, portraitRemoteViews,
|
||||
dim.portraitWidth, dim.portraitHeight);
|
||||
buildRemoteViews(landscapeWidgetView, landscapeRemoteViews,
|
||||
dim.landscapeWidth, dim.landscapeHeight);
|
||||
updateAppWidget();
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -273,7 +281,8 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
super.onPostExecute(aVoid);
|
||||
}
|
||||
|
||||
private void buildRemoteViews(View widgetView, RemoteViews remoteViews, int width, int height)
|
||||
private void buildRemoteViews(View widgetView, RemoteViews remoteViews, int width,
|
||||
int height)
|
||||
{
|
||||
widgetView.invalidate();
|
||||
widgetView.setDrawingCacheEnabled(true);
|
||||
@@ -287,7 +296,6 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
|
||||
int imageWidth = widgetView.getMeasuredWidth();
|
||||
int imageHeight = widgetView.getMeasuredHeight();
|
||||
int p[] = getPadding(width, height, imageWidth, imageHeight);
|
||||
|
||||
remoteViews.setViewPadding(R.id.buttonOverlay, p[0], p[1], p[2], p[3]);
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,10 @@
|
||||
style="@style/About.Item"
|
||||
android:text="Robin (Svenska)"/>
|
||||
|
||||
<TextView
|
||||
style="@style/About.Item"
|
||||
android:text="Đorđe Vasiljević (српски)"/>
|
||||
|
||||
<TextView
|
||||
style="@style/About.Item"
|
||||
android:text="Caner Başaran (Türkçe)"/>
|
||||
|
||||
@@ -159,4 +159,32 @@
|
||||
<string name="bug_report_failed">"فشل في توليد تقرير الاعطال"</string>
|
||||
<string name="generate_bug_report">"توليد تقرير الاعطال"</string>
|
||||
<string name="troubleshooting">"استكشاف الأخطاء وإصلاحها"</string>
|
||||
<string name="help_translate">"المساعدة في ترجمة هذا البرنامج"</string>
|
||||
<string name="night_mode">"الوضع الليلي"</string>
|
||||
<string name="use_pure_black">"استخدام أسود نقي في الوضع الليلي"</string>
|
||||
<string name="pure_black_description">"يستبدل خلفيات رمادية مع أسود نقي في الوضع الليلي. يقلل من استهلاك البطارية في الهواتف مع شاشة AMOLED."</string>
|
||||
<string name="interface_preferences">"السطح البيني"</string>
|
||||
<string name="reverse_days">"ترتيب عكسي أيام"</string>
|
||||
<string name="reverse_days_description">"عرض أيام في ترتيب عكسي على الشاشة الرئيسية"</string>
|
||||
<string name="day">"يوم"</string>
|
||||
<string name="week">"أسبوع"</string>
|
||||
<string name="month">"شهر"</string>
|
||||
|
||||
<!-- Three-month period -->
|
||||
<string name="quarter">"ربع سنه"</string>
|
||||
<string name="year">"عام"</string>
|
||||
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<string name="time_every">"مرات في"</string>
|
||||
<string name="every_x_days">"كل %d أيام"</string>
|
||||
<string name="every_x_weeks">"كل %d أسابيع"</string>
|
||||
<string name="every_x_months">"كل %d أشهر"</string>
|
||||
|
||||
<!-- The old "habit strength" has been replaced by "score". Feel free to translate "score" as "strength" or "stability" if it sounds more natural in your language. -->
|
||||
<string name="score">"النقاط"</string>
|
||||
<string name="reminder_sound">"صوت تذكير"</string>
|
||||
|
||||
<!-- Appears when the user disables the reminder sound. Could also be "no sound", "mute" or "silent". -->
|
||||
<string name="none">"صامت"</string>
|
||||
</resources>
|
||||
@@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">"Loop Habit Tracker</string>
|
||||
|
||||
<!-- Fuzzy -->
|
||||
<string name="app_name">"Loop Habit Tracker"</string>
|
||||
<string name="main_activity_title">"Zvyky"</string>
|
||||
<string name="action_settings">"Nastavení"</string>
|
||||
<string name="edit">"Upravit"</string>
|
||||
@@ -150,4 +152,32 @@ Upomínky mohou být potvrzen, odloženy nebo smazány přímo z tvého zaříze
|
||||
<string name="bug_report_failed">"Generace výpisu chyb selhala."</string>
|
||||
<string name="generate_bug_report">"Generovat výpis chyb"</string>
|
||||
<string name="troubleshooting">"Řešení problémů"</string>
|
||||
<string name="help_translate">"Pomozte s překladem aplikace"</string>
|
||||
<string name="night_mode">"Noční téma"</string>
|
||||
<string name="use_pure_black">"Zobrazit čistě černou v nočním tématu"</string>
|
||||
<string name="pure_black_description">"Nahradí šedé pozadí čistou černou v nočním tématu. Snižuje spotřebu baterie v telefonech s AMOLED displejem."</string>
|
||||
<string name="interface_preferences">"Rozhraní"</string>
|
||||
<string name="reverse_days">"Otočit pořadí dnů"</string>
|
||||
<string name="reverse_days_description">"Zobrazí dny na úvodní stránce v obráceném pořadí"</string>
|
||||
<string name="day">"Den"</string>
|
||||
<string name="week">"Týden"</string>
|
||||
<string name="month">"Měsíc"</string>
|
||||
|
||||
<!-- Three-month period -->
|
||||
<string name="quarter">"Čtvrtletí"</string>
|
||||
<string name="year">"Rok"</string>
|
||||
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<string name="time_every">"krát za"</string>
|
||||
<string name="every_x_days">"Každých %d dní"</string>
|
||||
<string name="every_x_weeks">"Každých %d týdnů"</string>
|
||||
<string name="every_x_months">"Každých %d měsíců"</string>
|
||||
|
||||
<!-- The old "habit strength" has been replaced by "score". Feel free to translate "score" as "strength" or "stability" if it sounds more natural in your language. -->
|
||||
<string name="score">"Skóre"</string>
|
||||
<string name="reminder_sound">"Zvuk upomínky"</string>
|
||||
|
||||
<!-- Appears when the user disables the reminder sound. Could also be "no sound", "mute" or "silent". -->
|
||||
<string name="none">"Žádný"</string>
|
||||
</resources>
|
||||
@@ -149,4 +149,32 @@ Android Wear 端末から直接、リマインダーをチェック、スヌー
|
||||
<string name="bug_report_failed">"バグ報告の生成に失敗しました。"</string>
|
||||
<string name="generate_bug_report">"バグ報告の生成"</string>
|
||||
<string name="troubleshooting">"トラブルシューティング"</string>
|
||||
<string name="help_translate">"このアプリの翻訳を支援する"</string>
|
||||
<string name="night_mode">"夜間モード"</string>
|
||||
<string name="use_pure_black">"夜間モードで真黒を使用する"</string>
|
||||
<string name="pure_black_description">"夜間モードで灰色の背景を黒で置き換えます。AMOLED ディスプレイの電話でバッテリー使用量を抑えます。"</string>
|
||||
<string name="interface_preferences">"インターフェース"</string>
|
||||
<string name="reverse_days">"日の順序を逆転する"</string>
|
||||
<string name="reverse_days_description">"メイン画面で日を逆順に表示します"</string>
|
||||
<string name="day">"日"</string>
|
||||
<string name="week">"週"</string>
|
||||
<string name="month">"月"</string>
|
||||
|
||||
<!-- Three-month period -->
|
||||
<string name="quarter">"四半期"</string>
|
||||
<string name="year">"年"</string>
|
||||
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<string name="time_every">"回 /"</string>
|
||||
<string name="every_x_days">"%d 日ごと"</string>
|
||||
<string name="every_x_weeks">"%d 週ごと"</string>
|
||||
<string name="every_x_months">"%d ヶ月ごと"</string>
|
||||
|
||||
<!-- The old "habit strength" has been replaced by "score". Feel free to translate "score" as "strength" or "stability" if it sounds more natural in your language. -->
|
||||
<string name="score">"スコア"</string>
|
||||
<string name="reminder_sound">"リマインダー サウンド"</string>
|
||||
|
||||
<!-- Appears when the user disables the reminder sound. Could also be "no sound", "mute" or "silent". -->
|
||||
<string name="none">"なし"</string>
|
||||
</resources>
|
||||
180
app/src/main/res/values-sr/strings.xml
Normal file
180
app/src/main/res/values-sr/strings.xml
Normal file
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">"Loop – праћење навика"</string>
|
||||
<string name="main_activity_title">"Навике"</string>
|
||||
<string name="action_settings">"Поставке"</string>
|
||||
<string name="edit">"Уреди"</string>
|
||||
<string name="delete">"Обриши"</string>
|
||||
<string name="archive">"Архивирај"</string>
|
||||
<string name="unarchive">"Врати из архива"</string>
|
||||
<string name="add_habit">"Додај навику"</string>
|
||||
<string name="color_picker_default_title">"Промена боје"</string>
|
||||
<string name="toast_habit_created">"Навика је створена."</string>
|
||||
<string name="toast_habit_deleted">"Навике су обрисане."</string>
|
||||
<string name="toast_habit_restored">"Навике су враћене."</string>
|
||||
<string name="toast_nothing_to_undo">"Нема шта да се опозове."</string>
|
||||
<string name="toast_nothing_to_redo">"Нема шта да се понови."</string>
|
||||
<string name="toast_habit_changed">"Навика је промењена."</string>
|
||||
|
||||
<!-- This appears when the user edits a habit, and then undoes the action. The habit is "changed back" to what is was before. Alternatively, "Habit restored". -->
|
||||
<string name="toast_habit_changed_back">"Навика је враћена."</string>
|
||||
<string name="toast_habit_archived">"Навике су архивиране."</string>
|
||||
<string name="toast_habit_unarchived">"Навике су враћене из архива."</string>
|
||||
<string name="overview">"Преглед"</string>
|
||||
<string name="habit_strength">"Снага навике"</string>
|
||||
<string name="history">"Историја"</string>
|
||||
<string name="clear">"Очисти"</string>
|
||||
<string name="description_hint">"Питање (нпр. „Да ли сте трчали данас?)"</string>
|
||||
|
||||
<!-- This and the next two terms form the sentence "Repeat 3 times in 7 days" that you see when you create a habit. Let me know if you have trouble adapting this into your language. -->
|
||||
<string name="repeat">"Понови"</string>
|
||||
<string name="times_every">"пута у"</string>
|
||||
<string name="days">"дана"</string>
|
||||
<string name="reminder">"Подсетник"</string>
|
||||
<string name="discard">"Одбаци"</string>
|
||||
<string name="save">"Сачувај"</string>
|
||||
|
||||
<!-- Streak as in "winning streak". That is, the number of times a user has performed a habit consecutively. Similar terms are "chains" or "series". -->
|
||||
<string name="streaks">"Низови"</string>
|
||||
<string name="no_habits_found">"Немате активних навика."</string>
|
||||
<string name="long_press_to_toggle">"Притисните и држите да бисте маркирали или демаркирали."</string>
|
||||
<string name="reminder_off">"искључен"</string>
|
||||
<string name="validation_name_should_not_be_blank">"Име не може бити празно."</string>
|
||||
<string name="validation_number_should_be_positive">"Број мора бити позитиван."</string>
|
||||
<string name="validation_at_most_one_rep_per_day">"Можете имати највише једно понављање на дан."</string>
|
||||
<string name="create_habit">"Стварање навике"</string>
|
||||
<string name="edit_habit">"Уређивање навике"</string>
|
||||
<string name="check">"Маркирај"</string>
|
||||
<string name="snooze">"Касније"</string>
|
||||
|
||||
<!-- App introduction -->
|
||||
<string name="intro_title_1">"Добро дошли"</string>
|
||||
<string name="intro_description_1">"Loop вам помаже да створите и одржавате здраве навике."</string>
|
||||
<string name="intro_title_2">"Створите нове навике"</string>
|
||||
<string name="intro_description_2">"Сваког дана, након што обавите навику, означите поље у апликацији."</string>
|
||||
<string name="intro_title_3">"Будите истрајни"</string>
|
||||
<string name="intro_description_3">"Навике којих се доследно придржавате дужи период биће означене пуном звездом."</string>
|
||||
<string name="intro_title_4">"Пратите свој напредак"</string>
|
||||
<string name="intro_description_4">"Детаљни графикони показују вам колико су се ваше навике временом побољшале."</string>
|
||||
<string name="interval_15_minutes">"15 минута"</string>
|
||||
<string name="interval_30_minutes">"30 минута"</string>
|
||||
<string name="interval_1_hour">"1 сат"</string>
|
||||
<string name="interval_2_hour">"2 сата"</string>
|
||||
<string name="interval_4_hour">"4 сата"</string>
|
||||
<string name="interval_8_hour">"8 сати"</string>
|
||||
<string name="pref_toggle_title">"Маркирај кратким додиром"</string>
|
||||
<string name="pref_toggle_description">"Практичније, али може доћи до случајног маркирања."</string>
|
||||
<string name="pref_snooze_interval_title">"Одлагање подсетника"</string>
|
||||
<string name="pref_rate_this_app">"Оцени апликацију"</string>
|
||||
<string name="pref_send_feedback">"Повратне информације"</string>
|
||||
<string name="pref_view_source_code">"Изворни кôд на GitHub-у"</string>
|
||||
<string name="pref_view_app_introduction">"Увод апликације"</string>
|
||||
<string name="links">"Везе"</string>
|
||||
<string name="behavior">"Понашање"</string>
|
||||
<string name="name">"Име"</string>
|
||||
<string name="show_archived">"Прикажи архивиране"</string>
|
||||
<string name="settings">"Поставке"</string>
|
||||
<string name="snooze_interval">"Време одлагања"</string>
|
||||
<string name="hint_title">"Да ли сте знали?"</string>
|
||||
<string name="hint_drag">"Притисните и држите име навике да бисте је прераспоредили."</string>
|
||||
<string name="hint_landscape">"Положите уређај да бисте видели више дана."</string>
|
||||
<string name="delete_habits">"Брисање навика"</string>
|
||||
<string name="delete_habits_message">"Навике ће бити трајно обрисане. Ова радња је неповратна."</string>
|
||||
<string name="weekends">"викендом"</string>
|
||||
<string name="any_weekday">"понедељак–петак"</string>
|
||||
<string name="any_day">"сваког дана"</string>
|
||||
<string name="select_weekdays">"Избор дана"</string>
|
||||
<string name="export_to_csv">"Извези као CSV"</string>
|
||||
<string name="done_label">"Готово"</string>
|
||||
<string name="clear_label">"Очисти"</string>
|
||||
<string name="select_hours">"Избор часова"</string>
|
||||
<string name="select_minutes">"Избор минута"</string>
|
||||
|
||||
<!-- Short description used on the Google Play store. There is an 80-character limit. -->
|
||||
<string name="store_short_description">"Створите здраве навике и пратите напредак (без огласа)."</string>
|
||||
<string name="store_description_1">"Loop вам помаже да створите и одржавате здраве навике, самим тим и да достигнете дугорочне циљеве. Детаљна статистика и графикони показују вам колико су се ваше навике временом побољшале. Апликација је отвореног кода и не садржи огласе."</string>
|
||||
<string name="store_feature_interface">"<b>Једноставан, леп и модеран дизајн</b>
|
||||
Loop има минималистички интерфејс који је једноставан за коришћење и прати смернице за материјални дизајн."</string>
|
||||
<string name="store_feature_score">"<b>Оцена навике</b>
|
||||
Поред приказа тренутног низа, Loop поседује напредни алгоритам за израчунавање снаге ваших навика. Ваша навика са сваким понављањем постаје јача, а са сваким пропуштеним даном слабија. Неколико пропуштених дана након дугог низа, пак, неће у потпуности упропастити ваш резултат."</string>
|
||||
<string name="store_feature_statistics">"<b>Детаљни графикони и статистика</b>
|
||||
Пратите свој напредак уз лепе и детаљне графиконе. Вратите се уназад да бисте видели целу историју навика."</string>
|
||||
<string name="store_feature_schedules">"<b>Флексибилни распоред</b>
|
||||
Подржава како дневне навике, тако и оне са сложенијим понављањем (трипут недељно, једанпут сваке друге недеље, сваки други дан и сл.)."</string>
|
||||
<string name="store_feature_reminders">"<b>Подсетници</b>
|
||||
Направите појединачни подсетник за сваку навику у жељено доба дана. С лакоћом маркирајте, одложите или откажите навику директно из обавештења, без отварања апликације."</string>
|
||||
<string name="store_feature_opensource">"<b>У потпуности отвореног кода и без огласа</b>
|
||||
Апликација не садржи никакве огласе, досадна обавештења или наметљиве дозволе; никада и неће. Изворни кôд је у целости доступан под лиценцом GPLv3."</string>
|
||||
<string name="store_feature_wear">"<b>Оптимизовано за паметне сатове</b>
|
||||
Навике можете маркирати, одложити или отказати директно помоћу Android Wear сата."</string>
|
||||
<string name="about">"О апликацији"</string>
|
||||
<string name="translators">"Преводиоци"</string>
|
||||
<string name="developers">"Програмери"</string>
|
||||
|
||||
<!-- %s will get replaced by the version number. For example, "Versão %d" will become "Versão 1.2.0". -->
|
||||
<string name="version_n">"Верзија %s"</string>
|
||||
<string name="frequency">"Учесталост"</string>
|
||||
<string name="checkmark">"Штрикла"</string>
|
||||
|
||||
<!-- This is a shorter version of "Habit Strength" -->
|
||||
<string name="strength">"Снага"</string>
|
||||
<string name="best_streaks">"Најбољи низови"</string>
|
||||
<string name="current_streaks">"Тренутни низ"</string>
|
||||
<string name="number_of_repetitions">"Број понављања"</string>
|
||||
<string name="last_x_days">"посл. %d дана"</string>
|
||||
<string name="last_x_weeks">"посл. %d нед."</string>
|
||||
<string name="last_x_months">"посл. %d мес."</string>
|
||||
<string name="last_x_years">"посл. %d год."</string>
|
||||
|
||||
<!-- "All time" number of repetitions. Or number of repetitions "since the beginning". -->
|
||||
<string name="all_time">"одувек"</string>
|
||||
<string name="every_day">"сваког дана"</string>
|
||||
<string name="every_week">"сваке недеље"</string>
|
||||
<string name="two_times_per_week">"2 пута недељно"</string>
|
||||
<string name="five_times_per_week">"5 пута недељно"</string>
|
||||
<string name="custom_frequency">"прилагоди…"</string>
|
||||
<string name="help">"Помоћ"</string>
|
||||
<string name="could_not_export">"Не могу да извезем податке."</string>
|
||||
<string name="could_not_import">"Не могу да увезем податке."</string>
|
||||
|
||||
<!-- Appears when the user tries to import a file which we do not support or recognize. -->
|
||||
<string name="file_not_recognized">"Датотека није препозната."</string>
|
||||
<string name="habits_imported">"Резервна копија је враћена."</string>
|
||||
<string name="full_backup_success">"Направљена је резервна копија."</string>
|
||||
<string name="import_data">"Врати резервну копију"</string>
|
||||
<string name="export_full_backup">"Направи резервну копију"</string>
|
||||
<string name="import_data_summary">"Поред матичног формата, апликација подржава и увоз датотека које је направио Tickmate, HabitBull и Rewire. Детаљније у ЧПП."</string>
|
||||
<string name="export_as_csv_summary">"Направите датотеку коју можете отворити у програму за рад са табелама (нпр. Microsoft Excel или OpenOffice Calc). Њу не можете да увезете назад у апликацију."</string>
|
||||
<string name="export_full_backup_summary">"Направите датотеку са свим подацима апликације. Њу касније можете да увезете."</string>
|
||||
<string name="bug_report_failed">"Не могу да направим извештај о грешци."</string>
|
||||
<string name="generate_bug_report">"Направи извештај о грешци"</string>
|
||||
<string name="troubleshooting">"Решавање проблема"</string>
|
||||
<string name="help_translate">"Помоћ у преводу"</string>
|
||||
<string name="night_mode">"Ноћни режим"</string>
|
||||
<string name="use_pure_black">"Чиста црна у ноћном режиму"</string>
|
||||
<string name="pure_black_description">"Замењује сиву позадину са чистом црном у ноћном режиму. Смањује потрошњу батерије код телефона са AMOLED екраном."</string>
|
||||
<string name="interface_preferences">"Интерфејс"</string>
|
||||
<string name="reverse_days">"Обрнути редослед дана"</string>
|
||||
<string name="reverse_days_description">"Прикажите дане у обрнутом редоследу на главном екрану."</string>
|
||||
<string name="day">"дан"</string>
|
||||
<string name="week">"недеља"</string>
|
||||
<string name="month">"месец"</string>
|
||||
|
||||
<!-- Three-month period -->
|
||||
<string name="quarter">"тромесечје"</string>
|
||||
<string name="year">"година"</string>
|
||||
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<!-- Middle part of the sentence '1 time in xx days' -->
|
||||
<string name="time_every">"пут у"</string>
|
||||
<string name="every_x_days">"Сваких %d дана"</string>
|
||||
<string name="every_x_weeks">"Сваких %d недеља"</string>
|
||||
<string name="every_x_months">"Сваких %d месеци"</string>
|
||||
|
||||
<!-- The old "habit strength" has been replaced by "score". Feel free to translate "score" as "strength" or "stability" if it sounds more natural in your language. -->
|
||||
<string name="score">"снага"</string>
|
||||
<string name="reminder_sound">"Звук подсетника"</string>
|
||||
|
||||
<!-- Appears when the user disables the reminder sound. Could also be "no sound", "mute" or "silent". -->
|
||||
<string name="none">"Без звука"</string>
|
||||
</resources>
|
||||
@@ -26,7 +26,9 @@
|
||||
<dimen name="history_max_font_size">@dimen/regularTextSize</dimen>
|
||||
<dimen name="regularTextSize">16sp</dimen>
|
||||
<dimen name="smallTextSize">14sp</dimen>
|
||||
<dimen name="smallerTextSize">12sp</dimen>
|
||||
<dimen name="tinyTextSize">10sp</dimen>
|
||||
<dimen name="habitNameWidth">160dp</dimen>
|
||||
<dimen name="progressbarOffset">-10dp</dimen>
|
||||
<dimen name="checkmarkWidget_heightBreakpoint">55dp</dimen>
|
||||
</resources>
|
||||
@@ -3,6 +3,7 @@ buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
}
|
||||
@@ -11,6 +12,7 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user