@ -0,0 +1,31 @@
|
|||||||
|
name: Build & Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: macOS-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Install Java Development Kit 1.8
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 1.8
|
||||||
|
- name: Build APK & Run small tests
|
||||||
|
run: android/build.sh build
|
||||||
|
- name: Run medium tests
|
||||||
|
uses: ReactiveCircus/android-emulator-runner@v2.2.0
|
||||||
|
with:
|
||||||
|
api-level: 29
|
||||||
|
script: android/build.sh medium-tests
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: Build
|
||||||
|
path: android/uhabits-android/build/outputs/
|
@ -0,0 +1,40 @@
|
|||||||
|
name: Build, Test & Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: macOS-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Install GPG
|
||||||
|
uses: olafurpg/setup-gpg@v2
|
||||||
|
- name: Decrypt secrets
|
||||||
|
env:
|
||||||
|
GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
|
||||||
|
run: .secret/decrypt.sh
|
||||||
|
- name: Install Java Development Kit 1.8
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 1.8
|
||||||
|
- name: Build APK & Run small tests
|
||||||
|
env:
|
||||||
|
RELEASE: 1
|
||||||
|
run: android/build.sh build
|
||||||
|
- name: Run medium tests
|
||||||
|
uses: ReactiveCircus/android-emulator-runner@v2.2.0
|
||||||
|
env:
|
||||||
|
RELEASE: 1
|
||||||
|
with:
|
||||||
|
api-level: 29
|
||||||
|
script: android/build.sh medium-tests
|
||||||
|
- name: Upload build to GitHub
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: Build
|
||||||
|
path: android/uhabits-android/build/outputs/
|
||||||
|
- name: Upload APK to Google Play
|
||||||
|
run: cd android && ./gradlew publishReleaseApk
|
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
if [ -z "$GPG_PASSWORD" ]; then
|
||||||
|
echo Env variable GPG_PASSWORD must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
gpg \
|
||||||
|
--quiet \
|
||||||
|
--batch \
|
||||||
|
--yes \
|
||||||
|
--decrypt \
|
||||||
|
--passphrase="$GPG_PASSWORD" \
|
||||||
|
--output secret.tar.gz \
|
||||||
|
secret
|
||||||
|
tar -xzf secret.tar.gz
|
||||||
|
rm secret.tar.gz
|
@ -1,155 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.os.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.view.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.text.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
public class AndroidBugReporter
|
|
||||||
{
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public AndroidBugReporter(@NonNull @AppContext Context context)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Captures and returns a bug report. The bug report contains some device
|
|
||||||
* information and the logcat.
|
|
||||||
*
|
|
||||||
* @return a String containing the bug report.
|
|
||||||
* @throws IOException when any I/O error occur.
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public String getBugReport() throws IOException
|
|
||||||
{
|
|
||||||
String logcat = getLogcat();
|
|
||||||
String deviceInfo = getDeviceInfo();
|
|
||||||
|
|
||||||
String log = "---------- BUG REPORT BEGINS ----------\n";
|
|
||||||
log += deviceInfo + "\n" + logcat;
|
|
||||||
log += "---------- BUG REPORT ENDS ------------\n";
|
|
||||||
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceInfo()
|
|
||||||
{
|
|
||||||
if (context == null) return "null context\n";
|
|
||||||
|
|
||||||
WindowManager wm =
|
|
||||||
(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
|
||||||
|
|
||||||
return
|
|
||||||
String.format("App Version Name: %s\n", BuildConfig.VERSION_NAME) +
|
|
||||||
String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE) +
|
|
||||||
String.format("OS Version: %s (%s)\n",
|
|
||||||
System.getProperty("os.version"), Build.VERSION.INCREMENTAL) +
|
|
||||||
String.format("OS API Level: %s\n", Build.VERSION.SDK) +
|
|
||||||
String.format("Device: %s\n", Build.DEVICE) +
|
|
||||||
String.format("Model (Product): %s (%s)\n", Build.MODEL,
|
|
||||||
Build.PRODUCT) +
|
|
||||||
String.format("Manufacturer: %s\n", Build.MANUFACTURER) +
|
|
||||||
String.format("Other tags: %s\n", Build.TAGS) +
|
|
||||||
String.format("Screen Width: %s\n",
|
|
||||||
wm.getDefaultDisplay().getWidth()) +
|
|
||||||
String.format("Screen Height: %s\n",
|
|
||||||
wm.getDefaultDisplay().getHeight()) +
|
|
||||||
String.format("External storage state: %s\n\n",
|
|
||||||
Environment.getExternalStorageState());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLogcat() throws IOException
|
|
||||||
{
|
|
||||||
int maxLineCount = 250;
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
String[] command = new String[]{ "logcat", "-d" };
|
|
||||||
java.lang.Process process = Runtime.getRuntime().exec(command);
|
|
||||||
|
|
||||||
InputStreamReader in = new InputStreamReader(process.getInputStream());
|
|
||||||
BufferedReader bufferedReader = new BufferedReader(in);
|
|
||||||
|
|
||||||
LinkedList<String> log = new LinkedList<>();
|
|
||||||
|
|
||||||
String line;
|
|
||||||
while ((line = bufferedReader.readLine()) != null)
|
|
||||||
{
|
|
||||||
log.addLast(line);
|
|
||||||
if (log.size() > maxLineCount) log.removeFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String l : log)
|
|
||||||
{
|
|
||||||
builder.append(l);
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Captures a bug report and saves it to a file in the SD card.
|
|
||||||
* <p>
|
|
||||||
* The contents of the file are generated by the method {@link
|
|
||||||
* #getBugReport()}. The file is saved in the apps's external private
|
|
||||||
* storage.
|
|
||||||
*
|
|
||||||
* @return the generated file.
|
|
||||||
* @throws IOException when I/O errors occur.
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public void dumpBugReportToFile()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
String date =
|
|
||||||
new SimpleDateFormat("yyyy-MM-dd HHmmss", Locale.US).format(
|
|
||||||
new Date());
|
|
||||||
|
|
||||||
if (context == null) throw new IllegalStateException();
|
|
||||||
|
|
||||||
File dir = new AndroidDirFinder(context).getFilesDir("Logs");
|
|
||||||
if (dir == null)
|
|
||||||
throw new IOException("log dir should not be null");
|
|
||||||
|
|
||||||
File logFile =
|
|
||||||
new File(String.format("%s/Log %s.txt", dir.getPath(), date));
|
|
||||||
FileWriter output = new FileWriter(logFile);
|
|
||||||
output.write(getBugReport());
|
|
||||||
output.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.view.WindowManager
|
||||||
|
import java.io.*
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
open class AndroidBugReporter @Inject constructor(@AppContext private val context: Context) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures and returns a bug report. The bug report contains some device
|
||||||
|
* information and the logcat.
|
||||||
|
*
|
||||||
|
* @return a String containing the bug report.
|
||||||
|
* @throws IOException when any I/O error occur.
|
||||||
|
*/
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun getBugReport(): String {
|
||||||
|
var log = "---------- BUG REPORT BEGINS ----------\n"
|
||||||
|
log += "${getLogcat()}\n"
|
||||||
|
log += "${getDeviceInfo()}\n"
|
||||||
|
log += "---------- BUG REPORT ENDS ------------\n"
|
||||||
|
return log
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun getLogcat(): String {
|
||||||
|
val maxLineCount = 250
|
||||||
|
val builder = StringBuilder()
|
||||||
|
val process = Runtime.getRuntime().exec(arrayOf("logcat", "-d"))
|
||||||
|
val inputReader = InputStreamReader(process.inputStream)
|
||||||
|
val bufferedReader = BufferedReader(inputReader)
|
||||||
|
val log = LinkedList<String>()
|
||||||
|
var line: String?
|
||||||
|
while (true) {
|
||||||
|
line = bufferedReader.readLine()
|
||||||
|
if (line == null) break;
|
||||||
|
log.addLast(line)
|
||||||
|
if (log.size > maxLineCount) log.removeFirst()
|
||||||
|
}
|
||||||
|
for (l in log) {
|
||||||
|
builder.appendln(l)
|
||||||
|
}
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures a bug report and saves it to a file in the SD card.
|
||||||
|
*
|
||||||
|
* The contents of the file are generated by the method [ ][.getBugReport]. The file is saved
|
||||||
|
* in the apps's external private storage.
|
||||||
|
*
|
||||||
|
* @return the generated file.
|
||||||
|
* @throws IOException when I/O errors occur.
|
||||||
|
*/
|
||||||
|
fun dumpBugReportToFile() {
|
||||||
|
try {
|
||||||
|
val date = SimpleDateFormat("yyyy-MM-dd HHmmss", Locale.US).format(Date())
|
||||||
|
val dir = AndroidDirFinder(context).getFilesDir("Logs")
|
||||||
|
?: throw IOException("log dir should not be null")
|
||||||
|
val logFile = File(String.format("%s/Log %s.txt", dir.path, date))
|
||||||
|
val output = FileWriter(logFile)
|
||||||
|
output.write(getBugReport())
|
||||||
|
output.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDeviceInfo(): String {
|
||||||
|
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||||
|
return buildString {
|
||||||
|
appendln("App Version Name: ${BuildConfig.VERSION_NAME}")
|
||||||
|
appendln("App Version Code: ${BuildConfig.VERSION_CODE}")
|
||||||
|
appendln("OS Version: ${System.getProperty("os.version")} (${Build.VERSION.INCREMENTAL})")
|
||||||
|
appendln("OS API Level: ${Build.VERSION.SDK}")
|
||||||
|
appendln("Device: ${Build.DEVICE}")
|
||||||
|
appendln("Model (Product): ${Build.MODEL} (${Build.PRODUCT})")
|
||||||
|
appendln("Manufacturer: ${Build.MANUFACTURER}")
|
||||||
|
appendln("Other tags: ${Build.TAGS}")
|
||||||
|
appendln("Screen Width: ${wm.defaultDisplay.width}")
|
||||||
|
appendln("Screen Height: ${wm.defaultDisplay.height}")
|
||||||
|
appendln("External storage state: ${Environment.getExternalStorageState()}")
|
||||||
|
appendln()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.support.v4.content.*;
|
|
||||||
import android.util.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.utils.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
public class AndroidDirFinder
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public AndroidDirFinder(@NonNull @AppContext Context context)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public File getFilesDir(@Nullable String relativePath)
|
|
||||||
{
|
|
||||||
File externalFilesDirs[] =
|
|
||||||
ContextCompat.getExternalFilesDirs(context, null);
|
|
||||||
if (externalFilesDirs == null)
|
|
||||||
{
|
|
||||||
Log.e("BaseSystem",
|
|
||||||
"getFilesDir: getExternalFilesDirs returned null");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FileUtils.getDir(externalFilesDirs, relativePath);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import org.isoron.androidbase.utils.FileUtils
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AndroidDirFinder @Inject constructor(@param:AppContext private val context: Context) {
|
||||||
|
fun getFilesDir(relativePath: String): File? {
|
||||||
|
return FileUtils.getDir(
|
||||||
|
ContextCompat.getExternalFilesDirs(context, null),
|
||||||
|
relativePath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase;
|
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
|
|
||||||
public class BaseExceptionHandler implements Thread.UncaughtExceptionHandler
|
|
||||||
{
|
|
||||||
@Nullable
|
|
||||||
private Thread.UncaughtExceptionHandler originalHandler;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private BaseActivity activity;
|
|
||||||
|
|
||||||
public BaseExceptionHandler(@NonNull BaseActivity activity)
|
|
||||||
{
|
|
||||||
this.activity = activity;
|
|
||||||
originalHandler = Thread.getDefaultUncaughtExceptionHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void uncaughtException(@Nullable Thread thread,
|
|
||||||
@Nullable Throwable ex)
|
|
||||||
{
|
|
||||||
if (ex == null) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ex.printStackTrace();
|
|
||||||
new AndroidBugReporter(activity).dumpBugReportToFile();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (ex.getCause() instanceof InconsistentDatabaseException)
|
|
||||||
// {
|
|
||||||
// HabitsApplication app = (HabitsApplication) activity.getApplication();
|
|
||||||
// HabitList habits = app.getComponent().getHabitList();
|
|
||||||
// habits.repair();
|
|
||||||
// System.exit(0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (originalHandler != null)
|
|
||||||
originalHandler.uncaughtException(thread, ex);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase
|
||||||
|
|
||||||
|
import org.isoron.androidbase.activities.BaseActivity
|
||||||
|
|
||||||
|
class BaseExceptionHandler(private val activity: BaseActivity) : Thread.UncaughtExceptionHandler {
|
||||||
|
|
||||||
|
private val originalHandler: Thread.UncaughtExceptionHandler? =
|
||||||
|
Thread.getDefaultUncaughtExceptionHandler()
|
||||||
|
|
||||||
|
override fun uncaughtException(thread: Thread?, ex: Throwable?) {
|
||||||
|
if (ex == null) return
|
||||||
|
if (thread == null) return
|
||||||
|
try {
|
||||||
|
ex.printStackTrace()
|
||||||
|
AndroidBugReporter(activity).dumpBugReportToFile()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
originalHandler?.uncaughtException(thread, ex)
|
||||||
|
}
|
||||||
|
}
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.security.*;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
import javax.net.ssl.*;
|
|
||||||
|
|
||||||
public class SSLContextProvider
|
|
||||||
{
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public SSLContextProvider(@NonNull @AppContext Context context)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SSLContext getCACertSSLContext()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
||||||
InputStream caInput = context.getAssets().open("cacert.pem");
|
|
||||||
Certificate ca = cf.generateCertificate(caInput);
|
|
||||||
|
|
||||||
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
|
||||||
ks.load(null, null);
|
|
||||||
ks.setCertificateEntry("ca", ca);
|
|
||||||
|
|
||||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
|
|
||||||
TrustManagerFactory.getDefaultAlgorithm());
|
|
||||||
tmf.init(ks);
|
|
||||||
|
|
||||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
|
||||||
ctx.init(null, tmf.getTrustManagers(), null);
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import java.security.KeyStore
|
||||||
|
import java.security.cert.CertificateFactory
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.TrustManagerFactory
|
||||||
|
|
||||||
|
class SSLContextProvider @Inject constructor(@param:AppContext private val context: Context) {
|
||||||
|
fun getCACertSSLContext(): SSLContext {
|
||||||
|
try {
|
||||||
|
val cf = CertificateFactory.getInstance("X.509")
|
||||||
|
val ca = cf.generateCertificate(context.assets.open("cacert.pem"))
|
||||||
|
val ks = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
|
||||||
|
load(null, null)
|
||||||
|
setCertificateEntry("ca", ca)
|
||||||
|
}
|
||||||
|
val alg = TrustManagerFactory.getDefaultAlgorithm()
|
||||||
|
val tmf = TrustManagerFactory.getInstance(alg).apply {
|
||||||
|
init(ks)
|
||||||
|
}
|
||||||
|
return SSLContext.getInstance("TLS").apply {
|
||||||
|
init(null, tmf.trustManagers, null)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase.utils;
|
|
||||||
|
|
||||||
import android.graphics.*;
|
|
||||||
|
|
||||||
public abstract class ColorUtils
|
|
||||||
{
|
|
||||||
public static int mixColors(int color1, int color2, float amount)
|
|
||||||
{
|
|
||||||
final byte ALPHA_CHANNEL = 24;
|
|
||||||
final byte RED_CHANNEL = 16;
|
|
||||||
final byte GREEN_CHANNEL = 8;
|
|
||||||
final byte BLUE_CHANNEL = 0;
|
|
||||||
|
|
||||||
final float inverseAmount = 1.0f - amount;
|
|
||||||
|
|
||||||
int a = ((int) (((float) (color1 >> ALPHA_CHANNEL & 0xff) * amount) +
|
|
||||||
((float) (color2 >> ALPHA_CHANNEL & 0xff) *
|
|
||||||
inverseAmount))) & 0xff;
|
|
||||||
int r = ((int) (((float) (color1 >> RED_CHANNEL & 0xff) * amount) +
|
|
||||||
((float) (color2 >> RED_CHANNEL & 0xff) *
|
|
||||||
inverseAmount))) & 0xff;
|
|
||||||
int g = ((int) (((float) (color1 >> GREEN_CHANNEL & 0xff) * amount) +
|
|
||||||
((float) (color2 >> GREEN_CHANNEL & 0xff) *
|
|
||||||
inverseAmount))) & 0xff;
|
|
||||||
int b = ((int) (((float) (color1 & 0xff) * amount) +
|
|
||||||
((float) (color2 & 0xff) * inverseAmount))) & 0xff;
|
|
||||||
|
|
||||||
return a << ALPHA_CHANNEL | r << RED_CHANNEL | g << GREEN_CHANNEL |
|
|
||||||
b << BLUE_CHANNEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int setAlpha(int color, float newAlpha)
|
|
||||||
{
|
|
||||||
int intAlpha = (int) (newAlpha * 255);
|
|
||||||
return Color.argb(intAlpha, Color.red(color), Color.green(color),
|
|
||||||
Color.blue(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int setMinValue(int color, float newValue)
|
|
||||||
{
|
|
||||||
float hsv[] = new float[3];
|
|
||||||
Color.colorToHSV(color, hsv);
|
|
||||||
hsv[2] = Math.max(hsv[2], newValue);
|
|
||||||
return Color.HSVToColor(hsv);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase.utils
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
object ColorUtils {
|
||||||
|
private const val ALPHA_CHANNEL = 24
|
||||||
|
private const val RED_CHANNEL = 16
|
||||||
|
private const val GREEN_CHANNEL = 8
|
||||||
|
private const val BLUE_CHANNEL = 0
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun mixColors(color1: Int, color2: Int, amount: Float): Int {
|
||||||
|
val a = mixColorChannel(color1, color2, amount, ALPHA_CHANNEL)
|
||||||
|
val r = mixColorChannel(color1, color2, amount, RED_CHANNEL)
|
||||||
|
val g = mixColorChannel(color1, color2, amount, GREEN_CHANNEL)
|
||||||
|
val b = mixColorChannel(color1, color2, amount, BLUE_CHANNEL)
|
||||||
|
return a or r or g or b
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setAlpha(color: Int, newAlpha: Float): Int {
|
||||||
|
val intAlpha = (newAlpha * 255).toInt()
|
||||||
|
return Color.argb(intAlpha, Color.red(color), Color.green(color), Color.blue(color))
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setMinValue(color: Int, newValue: Float): Int {
|
||||||
|
val hsv = FloatArray(3)
|
||||||
|
Color.colorToHSV(color, hsv)
|
||||||
|
hsv[2] = max(hsv[2], newValue)
|
||||||
|
return Color.HSVToColor(hsv)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mixColorChannel(color1: Int, color2: Int, amount: Float, channel: Int): Int {
|
||||||
|
val fl = (color1 shr channel and 0xff).toFloat() * amount
|
||||||
|
val f2 = (color2 shr channel and 0xff).toFloat() * (1.0f - amount)
|
||||||
|
return (fl + f2).toInt() and 0xff shl channel
|
||||||
|
}
|
||||||
|
}
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase.utils;
|
|
||||||
|
|
||||||
import android.os.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.util.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public abstract class FileUtils
|
|
||||||
{
|
|
||||||
public static void copy(File src, File dst) throws IOException
|
|
||||||
{
|
|
||||||
FileInputStream inStream = new FileInputStream(src);
|
|
||||||
FileOutputStream outStream = new FileOutputStream(dst);
|
|
||||||
copy(inStream, outStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copy(InputStream inStream, File dst) throws IOException
|
|
||||||
{
|
|
||||||
FileOutputStream outStream = new FileOutputStream(dst);
|
|
||||||
copy(inStream, outStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copy(InputStream in, OutputStream out) throws IOException
|
|
||||||
{
|
|
||||||
int numBytes;
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
|
|
||||||
while ((numBytes = in.read(buffer)) != -1)
|
|
||||||
out.write(buffer, 0, numBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static File getDir(@NonNull File potentialParentDirs[],
|
|
||||||
@Nullable String relativePath)
|
|
||||||
{
|
|
||||||
if (relativePath == null) relativePath = "";
|
|
||||||
|
|
||||||
File chosenDir = null;
|
|
||||||
for (File dir : potentialParentDirs)
|
|
||||||
{
|
|
||||||
if (dir == null || !dir.canWrite()) continue;
|
|
||||||
chosenDir = dir;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chosenDir == null)
|
|
||||||
{
|
|
||||||
Log.e("FileUtils",
|
|
||||||
"getDir: all potential parents are null or non-writable");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
File dir = new File(
|
|
||||||
String.format("%s/%s/", chosenDir.getAbsolutePath(), relativePath));
|
|
||||||
if (!dir.exists() && !dir.mkdirs())
|
|
||||||
{
|
|
||||||
Log.e("FileUtils",
|
|
||||||
"getDir: chosen dir does not exist and cannot be created");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static File getSDCardDir(@Nullable String relativePath)
|
|
||||||
{
|
|
||||||
File parents[] =
|
|
||||||
new File[]{ Environment.getExternalStorageDirectory() };
|
|
||||||
return getDir(parents, relativePath);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase.utils
|
||||||
|
|
||||||
|
import android.os.Environment
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.*
|
||||||
|
|
||||||
|
|
||||||
|
fun File.copyTo(dst: File) {
|
||||||
|
val inStream = FileInputStream(this)
|
||||||
|
val outStream = FileOutputStream(dst)
|
||||||
|
inStream.copyTo(outStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun InputStream.copyTo(dst: File) {
|
||||||
|
val outStream = FileOutputStream(dst)
|
||||||
|
this.copyTo(outStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun InputStream.copyTo(out: OutputStream) {
|
||||||
|
var numBytes: Int
|
||||||
|
val buffer = ByteArray(1024)
|
||||||
|
while (this.read(buffer).also { numBytes = it } != -1) {
|
||||||
|
out.write(buffer, 0, numBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object FileUtils {
|
||||||
|
@JvmStatic
|
||||||
|
fun getDir(potentialParentDirs: Array<File>, relativePath: String): File? {
|
||||||
|
val chosenDir: File? = potentialParentDirs.firstOrNull { dir -> dir.canWrite() }
|
||||||
|
if (chosenDir == null) {
|
||||||
|
Log.e("FileUtils", "getDir: all potential parents are null or non-writable")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val dir = File("${chosenDir.absolutePath}/${relativePath}/")
|
||||||
|
if (!dir.exists() && !dir.mkdirs()) {
|
||||||
|
Log.e("FileUtils", "getDir: chosen dir does not exist and cannot be created")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getSDCardDir(relativePath: String): File? {
|
||||||
|
val parents = arrayOf(Environment.getExternalStorageDirectory())
|
||||||
|
return getDir(parents, relativePath)
|
||||||
|
}
|
||||||
|
}
|
@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase.utils;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.content.res.*;
|
|
||||||
import android.graphics.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.support.v4.view.*;
|
|
||||||
import android.util.*;
|
|
||||||
import android.view.*;
|
|
||||||
import android.widget.*;
|
|
||||||
|
|
||||||
public abstract class InterfaceUtils
|
|
||||||
{
|
|
||||||
private static Typeface fontAwesome;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Float fixedResolution = null;
|
|
||||||
|
|
||||||
public static void setFixedResolution(@NonNull Float f)
|
|
||||||
{
|
|
||||||
fixedResolution = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Typeface getFontAwesome(Context context)
|
|
||||||
{
|
|
||||||
if(fontAwesome == null) fontAwesome =
|
|
||||||
Typeface.createFromAsset(context.getAssets(),
|
|
||||||
"fontawesome-webfont.ttf");
|
|
||||||
|
|
||||||
return fontAwesome;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float dpToPixels(Context context, float dp)
|
|
||||||
{
|
|
||||||
if(fixedResolution != null) return dp * fixedResolution;
|
|
||||||
|
|
||||||
Resources resources = context.getResources();
|
|
||||||
DisplayMetrics metrics = resources.getDisplayMetrics();
|
|
||||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float spToPixels(Context context, float sp)
|
|
||||||
{
|
|
||||||
if(fixedResolution != null) return sp * fixedResolution;
|
|
||||||
|
|
||||||
Resources resources = context.getResources();
|
|
||||||
DisplayMetrics metrics = resources.getDisplayMetrics();
|
|
||||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, metrics);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float getDimension(Context context, int id)
|
|
||||||
{
|
|
||||||
float dim = context.getResources().getDimension(id);
|
|
||||||
if (fixedResolution == null) return dim;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
|
||||||
float actualDensity = dm.density;
|
|
||||||
return dim / actualDensity * fixedResolution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setupEditorAction(@NonNull ViewGroup parent,
|
|
||||||
@NonNull TextView.OnEditorActionListener listener)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < parent.getChildCount(); i++)
|
|
||||||
{
|
|
||||||
View child = parent.getChildAt(i);
|
|
||||||
|
|
||||||
if (child instanceof ViewGroup)
|
|
||||||
setupEditorAction((ViewGroup) child, listener);
|
|
||||||
|
|
||||||
if (child instanceof TextView)
|
|
||||||
((TextView) child).setOnEditorActionListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLayoutRtl(View view)
|
|
||||||
{
|
|
||||||
return ViewCompat.getLayoutDirection(view) ==
|
|
||||||
ViewCompat.LAYOUT_DIRECTION_RTL;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase.utils
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.graphics.*
|
||||||
|
import android.util.*
|
||||||
|
import android.view.*
|
||||||
|
import android.widget.*
|
||||||
|
import android.widget.TextView.*
|
||||||
|
import androidx.core.view.*
|
||||||
|
|
||||||
|
object InterfaceUtils {
|
||||||
|
private var fontAwesome: Typeface? = null
|
||||||
|
private var fixedResolution: Float? = null
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setFixedResolution(f: Float) {
|
||||||
|
fixedResolution = f
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getFontAwesome(context: Context): Typeface? {
|
||||||
|
if (fontAwesome == null) {
|
||||||
|
fontAwesome = Typeface.createFromAsset(context.assets, "fontawesome-webfont.ttf")
|
||||||
|
}
|
||||||
|
return fontAwesome
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun dpToPixels(context: Context, dp: Float): Float {
|
||||||
|
if (fixedResolution != null) return dp * fixedResolution!!
|
||||||
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||||
|
dp,
|
||||||
|
context.resources.displayMetrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun spToPixels(context: Context, sp: Float): Float {
|
||||||
|
if (fixedResolution != null) return sp * fixedResolution!!
|
||||||
|
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
sp,
|
||||||
|
context.resources.displayMetrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getDimension(context: Context, id: Int): Float {
|
||||||
|
val dim = context.resources.getDimension(id)
|
||||||
|
if (fixedResolution != null) {
|
||||||
|
val actualDensity = context.resources.displayMetrics.density
|
||||||
|
return dim / actualDensity * fixedResolution!!
|
||||||
|
}
|
||||||
|
return dim
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setupEditorAction(parent: ViewGroup,
|
||||||
|
listener: OnEditorActionListener) {
|
||||||
|
for (i in 0 until parent.childCount) {
|
||||||
|
val child = parent.getChildAt(i)
|
||||||
|
if (child is ViewGroup) setupEditorAction(child, listener)
|
||||||
|
if (child is TextView) child.setOnEditorActionListener(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isLayoutRtl(view: View?): Boolean {
|
||||||
|
return ViewCompat.getLayoutDirection(view!!) ==
|
||||||
|
ViewCompat.LAYOUT_DIRECTION_RTL
|
||||||
|
}
|
||||||
|
}
|
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.androidbase.utils;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.content.res.*;
|
|
||||||
import android.graphics.drawable.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.*;
|
|
||||||
|
|
||||||
public class StyledResources
|
|
||||||
{
|
|
||||||
private static Integer fixedTheme;
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public StyledResources(@NonNull Context context)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setFixedTheme(Integer theme)
|
|
||||||
{
|
|
||||||
fixedTheme = theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getBoolean(@AttrRes int attrId)
|
|
||||||
{
|
|
||||||
TypedArray ta = getTypedArray(attrId);
|
|
||||||
boolean bool = ta.getBoolean(0, false);
|
|
||||||
ta.recycle();
|
|
||||||
|
|
||||||
return bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDimension(@AttrRes int attrId)
|
|
||||||
{
|
|
||||||
TypedArray ta = getTypedArray(attrId);
|
|
||||||
int dim = ta.getDimensionPixelSize(0, 0);
|
|
||||||
ta.recycle();
|
|
||||||
|
|
||||||
return dim;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getColor(@AttrRes int attrId)
|
|
||||||
{
|
|
||||||
TypedArray ta = getTypedArray(attrId);
|
|
||||||
int color = ta.getColor(0, 0);
|
|
||||||
ta.recycle();
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Drawable getDrawable(@AttrRes int attrId)
|
|
||||||
{
|
|
||||||
TypedArray ta = getTypedArray(attrId);
|
|
||||||
Drawable drawable = ta.getDrawable(0);
|
|
||||||
ta.recycle();
|
|
||||||
|
|
||||||
return drawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getFloat(@AttrRes int attrId)
|
|
||||||
{
|
|
||||||
TypedArray ta = getTypedArray(attrId);
|
|
||||||
float f = ta.getFloat(0, 0);
|
|
||||||
ta.recycle();
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getPalette()
|
|
||||||
{
|
|
||||||
int resourceId = getResource(R.attr.palette);
|
|
||||||
if (resourceId < 0) throw new RuntimeException("resource not found");
|
|
||||||
|
|
||||||
return context.getResources().getIntArray(resourceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getResource(@AttrRes int attrId)
|
|
||||||
{
|
|
||||||
TypedArray ta = getTypedArray(attrId);
|
|
||||||
int resourceId = ta.getResourceId(0, -1);
|
|
||||||
ta.recycle();
|
|
||||||
|
|
||||||
return resourceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypedArray getTypedArray(@AttrRes int attrId)
|
|
||||||
{
|
|
||||||
int[] attrs = new int[]{ attrId };
|
|
||||||
|
|
||||||
if (fixedTheme != null)
|
|
||||||
return context.getTheme().obtainStyledAttributes(fixedTheme, attrs);
|
|
||||||
|
|
||||||
return context.obtainStyledAttributes(attrs);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.isoron.androidbase.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.TypedArray
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import androidx.annotation.AttrRes
|
||||||
|
import org.isoron.androidbase.R
|
||||||
|
|
||||||
|
class StyledResources(private val context: Context) {
|
||||||
|
|
||||||
|
fun getBoolean(@AttrRes attrId: Int): Boolean {
|
||||||
|
val ta = getTypedArray(attrId)
|
||||||
|
val bool = ta.getBoolean(0, false)
|
||||||
|
ta.recycle()
|
||||||
|
return bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDimension(@AttrRes attrId: Int): Int {
|
||||||
|
val ta = getTypedArray(attrId)
|
||||||
|
val dim = ta.getDimensionPixelSize(0, 0)
|
||||||
|
ta.recycle()
|
||||||
|
return dim
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getColor(@AttrRes attrId: Int): Int {
|
||||||
|
val ta = getTypedArray(attrId)
|
||||||
|
val color = ta.getColor(0, 0)
|
||||||
|
ta.recycle()
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDrawable(@AttrRes attrId: Int): Drawable? {
|
||||||
|
val ta = getTypedArray(attrId)
|
||||||
|
val drawable = ta.getDrawable(0)
|
||||||
|
ta.recycle()
|
||||||
|
return drawable
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFloat(@AttrRes attrId: Int): Float {
|
||||||
|
val ta = getTypedArray(attrId)
|
||||||
|
val f = ta.getFloat(0, 0f)
|
||||||
|
ta.recycle()
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPalette(): IntArray {
|
||||||
|
val resourceId = getResource(R.attr.palette)
|
||||||
|
if (resourceId < 0) throw RuntimeException("palette resource not found")
|
||||||
|
return context.resources.getIntArray(resourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getResource(@AttrRes attrId: Int): Int {
|
||||||
|
val ta = getTypedArray(attrId)
|
||||||
|
val resourceId = ta.getResourceId(0, -1)
|
||||||
|
ta.recycle()
|
||||||
|
return resourceId
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTypedArray(@AttrRes attrId: Int): TypedArray {
|
||||||
|
val attrs = intArrayOf(attrId)
|
||||||
|
if (fixedTheme != null) {
|
||||||
|
return context.theme.obtainStyledAttributes(fixedTheme!!, attrs)
|
||||||
|
}
|
||||||
|
return context.obtainStyledAttributes(attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private var fixedTheme: Int? = null
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setFixedTheme(theme: Int?) {
|
||||||
|
fixedTheme = theme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,18 @@
|
|||||||
VERSION_CODE = 39
|
VERSION_CODE = 51
|
||||||
VERSION_NAME = 1.8.0
|
VERSION_NAME = 1.8.8
|
||||||
|
|
||||||
MIN_SDK_VERSION = 19
|
MIN_SDK_VERSION = 21
|
||||||
TARGET_SDK_VERSION = 29
|
TARGET_SDK_VERSION = 29
|
||||||
COMPILE_SDK_VERSION = 29
|
COMPILE_SDK_VERSION = 29
|
||||||
|
|
||||||
DAGGER_VERSION = 2.25.2
|
DAGGER_VERSION = 2.25.4
|
||||||
KOTLIN_VERSION = 1.3.50
|
KOTLIN_VERSION = 1.3.61
|
||||||
SUPPORT_LIBRARY_VERSION = 28.0.0
|
SUPPORT_LIBRARY_VERSION = 28.0.0
|
||||||
AUTO_FACTORY_VERSION = 1.0-beta6
|
AUTO_FACTORY_VERSION = 1.0-beta6
|
||||||
BUILD_TOOLS_VERSION = 3.5.2
|
BUILD_TOOLS_VERSION = 4.0.0
|
||||||
|
|
||||||
org.gradle.parallel=false
|
org.gradle.parallel=false
|
||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms2048m -Xmx2048m -XX:MaxPermSize=2048m
|
org.gradle.jvmargs=-Xms2048m -Xmx2048m -XX:MaxPermSize=2048m
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#Wed Sep 04 13:05:58 MSK 2019
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
uhabits-android/src/main/play/
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
|
||||||
*
|
|
||||||
* This file is part of Loop Habit Tracker.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.isoron.uhabits;
|
|
||||||
|
|
||||||
import android.os.*;
|
|
||||||
import android.support.test.filters.*;
|
|
||||||
import android.support.test.runner.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.junit.runner.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
|
||||||
import static org.hamcrest.MatcherAssert.*;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@MediumTest
|
|
||||||
public class HabitLoggerTest extends BaseAndroidTest
|
|
||||||
{
|
|
||||||
@Test
|
|
||||||
public void testLogReminderScheduled() throws IOException
|
|
||||||
{
|
|
||||||
if (!isLogcatAvailable()) return;
|
|
||||||
|
|
||||||
long time = 1422277200000L; // 13:00 jan 26, 2015 (UTC)
|
|
||||||
Habit habit = fixtures.createEmptyHabit();
|
|
||||||
habit.setName("Write journal");
|
|
||||||
|
|
||||||
logger.logReminderScheduled(habit, time);
|
|
||||||
|
|
||||||
String expectedMsg = "Setting alarm (2015-01-26 130000): Wri\n";
|
|
||||||
assertLogcatContains(expectedMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void assertLogcatContains(String expectedMsg) throws IOException
|
|
||||||
{
|
|
||||||
String logcat = new AndroidBugReporter(targetContext).getLogcat();
|
|
||||||
assertThat(logcat, containsString(expectedMsg));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isLogcatAvailable()
|
|
||||||
{
|
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.isoron.uhabits.activities.habits.show.views;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.MediumTest;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.BaseViewTest;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.core.models.Habit;
|
||||||
|
import org.isoron.uhabits.core.models.Reminder;
|
||||||
|
import org.isoron.uhabits.core.models.WeekdayList;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@MediumTest
|
||||||
|
public class NotesCardTest extends BaseViewTest
|
||||||
|
{
|
||||||
|
public static final String PATH = "habits/show/NotesCard/";
|
||||||
|
|
||||||
|
private NotesCard view;
|
||||||
|
|
||||||
|
private Habit habit;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
habit = fixtures.createLongHabit();
|
||||||
|
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
|
||||||
|
|
||||||
|
view = LayoutInflater
|
||||||
|
.from(targetContext)
|
||||||
|
.inflate(R.layout.show_habit, null)
|
||||||
|
.findViewById(R.id.notesCard);
|
||||||
|
|
||||||
|
view.setHabit(habit);
|
||||||
|
view.refreshData();
|
||||||
|
|
||||||
|
measureView(view, 800, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRender() throws Exception
|
||||||
|
{
|
||||||
|
assertRenders(view, PATH + "render.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRenderEmptyDescription() throws Exception
|
||||||
|
{
|
||||||
|
habit.setDescription("");
|
||||||
|
view.refreshData();
|
||||||
|
assertRenders(view, PATH + "render-empty-description.png");
|
||||||
|
}
|
||||||
|
}
|