diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d4a036b..e98a9e609 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +### 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 @@ -86,4 +98,4 @@ ### 1.0.0 (February 19, 2016) -* Initial release \ No newline at end of file +* Initial release diff --git a/app/src/androidTest/java/org/isoron/uhabits/ui/MainTest.java b/app/src/androidTest/java/org/isoron/uhabits/ui/MainTest.java index 89751372f..5dde5c695 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/ui/MainTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/ui/MainTest.java @@ -341,6 +341,6 @@ public class MainTest { clickMenuItem(R.string.settings); clickSettingsItem("Generate bug report"); - intended(hasAction(Intent.ACTION_SENDTO)); + intended(hasAction(Intent.ACTION_SEND)); } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index de4fc85b4..16b86e27a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,8 +21,8 @@ + android:versionCode="19" + android:versionName="1.5.3"> diff --git a/app/src/main/java/org/isoron/uhabits/BaseActivity.java b/app/src/main/java/org/isoron/uhabits/BaseActivity.java index 4b0398495..ba7534489 100644 --- a/app/src/main/java/org/isoron/uhabits/BaseActivity.java +++ b/app/src/main/java/org/isoron/uhabits/BaseActivity.java @@ -148,7 +148,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U try { ex.printStackTrace(); - HabitsApplication.generateLogFile(); + HabitsApplication.dumpBugReportToFile(); } catch(Exception e) { diff --git a/app/src/main/java/org/isoron/uhabits/HabitsApplication.java b/app/src/main/java/org/isoron/uhabits/HabitsApplication.java index 27a8fbf43..dee4ca17d 100644 --- a/app/src/main/java/org/isoron/uhabits/HabitsApplication.java +++ b/app/src/main/java/org/isoron/uhabits/HabitsApplication.java @@ -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 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; + } } diff --git a/app/src/main/java/org/isoron/uhabits/MainActivity.java b/app/src/main/java/org/isoron/uhabits/MainActivity.java index 907a28b7e..ace9bf8d9 100644 --- a/app/src/main/java/org/isoron/uhabits/MainActivity.java +++ b/app/src/main/java/org/isoron/uhabits/MainActivity.java @@ -45,7 +45,6 @@ import org.isoron.uhabits.helpers.ReminderHelper; import org.isoron.uhabits.helpers.UIHelper; import org.isoron.uhabits.models.Habit; -import java.io.File; import java.io.IOException; public class MainActivity extends BaseActivity @@ -230,12 +229,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) diff --git a/app/src/main/java/org/isoron/uhabits/helpers/ReminderHelper.java b/app/src/main/java/org/isoron/uhabits/helpers/ReminderHelper.java index c575ffcf4..35e1a92a1 100644 --- a/app/src/main/java/org/isoron/uhabits/helpers/ReminderHelper.java +++ b/app/src/main/java/org/isoron/uhabits/helpers/ReminderHelper.java @@ -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 diff --git a/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java b/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java index 7e6c8c968..dfb27f1bf 100644 --- a/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java +++ b/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java @@ -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(); diff --git a/app/src/main/java/org/isoron/uhabits/views/CheckmarkWidgetView.java b/app/src/main/java/org/isoron/uhabits/views/CheckmarkWidgetView.java index 01cf98a19..869c91afe 100644 --- a/app/src/main/java/org/isoron/uhabits/views/CheckmarkWidgetView.java +++ b/app/src/main/java/org/isoron/uhabits/views/CheckmarkWidgetView.java @@ -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); } diff --git a/app/src/main/java/org/isoron/uhabits/views/RingView.java b/app/src/main/java/org/isoron/uhabits/views/RingView.java index de7ee345a..cac641a22 100644 --- a/app/src/main/java/org/isoron/uhabits/views/RingView.java +++ b/app/src/main/java/org/isoron/uhabits/views/RingView.java @@ -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); } diff --git a/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java index 6490084f7..9c36fe398 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java @@ -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]); } diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 40edb95e7..b17e91e8b 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -159,4 +159,32 @@ "فشل في توليد تقرير الاعطال" "توليد تقرير الاعطال" "استكشاف الأخطاء وإصلاحها" +"المساعدة في ترجمة هذا البرنامج" +"الوضع الليلي" +"استخدام أسود نقي في الوضع الليلي" +"يستبدل خلفيات رمادية مع أسود نقي في الوضع الليلي. يقلل من استهلاك البطارية في الهواتف مع شاشة AMOLED." +"السطح البيني" +"ترتيب عكسي أيام" +"عرض أيام في ترتيب عكسي على الشاشة الرئيسية" +"يوم" +"أسبوع" +"شهر" + + +"ربع سنه" +"عام" + + + +"مرات في" +"كل %d أيام" +"كل %d أسابيع" +"كل %d أشهر" + + +"النقاط" +"صوت تذكير" + + +"صامت" \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index c5a9e73f4..62be2912f 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -1,6 +1,8 @@ -"Loop Habit Tracker + + +"Loop Habit Tracker" "Zvyky" "Nastavení" "Upravit" @@ -150,4 +152,32 @@ Upomínky mohou být potvrzen, odloženy nebo smazány přímo z tvého zaříze "Generace výpisu chyb selhala." "Generovat výpis chyb" "Řešení problémů" +"Pomozte s překladem aplikace" +"Noční téma" +"Zobrazit čistě černou v nočním tématu" +"Nahradí šedé pozadí čistou černou v nočním tématu. Snižuje spotřebu baterie v telefonech s AMOLED displejem." +"Rozhraní" +"Otočit pořadí dnů" +"Zobrazí dny na úvodní stránce v obráceném pořadí" +"Den" +"Týden" +"Měsíc" + + +"Čtvrtletí" +"Rok" + + + +"krát za" +"Každých %d dní" +"Každých %d týdnů" +"Každých %d měsíců" + + +"Skóre" +"Zvuk upomínky" + + +"Žádný" \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 9b85d78f4..f802621b5 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -149,4 +149,32 @@ Android Wear 端末から直接、リマインダーをチェック、スヌー "バグ報告の生成に失敗しました。" "バグ報告の生成" "トラブルシューティング" +"このアプリの翻訳を支援する" +"夜間モード" +"夜間モードで真黒を使用する" +"夜間モードで灰色の背景を黒で置き換えます。AMOLED ディスプレイの電話でバッテリー使用量を抑えます。" +"インターフェース" +"日の順序を逆転する" +"メイン画面で日を逆順に表示します" +"日" +"週" +"月" + + +"四半期" +"年" + + + +"回 /" +"%d 日ごと" +"%d 週ごと" +"%d ヶ月ごと" + + +"スコア" +"リマインダー サウンド" + + +"なし" \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 42c044142..51147ef4c 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -26,7 +26,9 @@ @dimen/regularTextSize 16sp 14sp + 12sp 10sp 160dp -10dp + 55dp \ No newline at end of file