mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Implement intent filter; hide password for now
This commit is contained in:
@@ -68,9 +68,16 @@
|
||||
android:targetActivity=".activities.habits.list.ListHabitsActivity">
|
||||
<intent-filter android:label="@string/main_activity_title">
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https"
|
||||
android:host="loophabits.org"
|
||||
android:pathPrefix="/sync" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity
|
||||
|
||||
@@ -34,8 +34,11 @@ abstract class HabitsActivity : BaseActivity() {
|
||||
|
||||
appComponent = (applicationContext as HabitsApplication).component
|
||||
|
||||
val habit = getHabitFromIntent(appComponent.habitList)
|
||||
?: appComponent.modelFactory.buildHabit()
|
||||
var habit = appComponent.modelFactory.buildHabit()
|
||||
if(intent.action != "android.intent.action.VIEW") {
|
||||
val intentHabit = getHabitFromIntent(appComponent.habitList)
|
||||
if (intentHabit != null) habit = intentHabit
|
||||
}
|
||||
|
||||
component = DaggerHabitsActivityComponent
|
||||
.builder()
|
||||
|
||||
@@ -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.uhabits.activities.common.dialogs;
|
||||
|
||||
import android.content.*;
|
||||
|
||||
import androidx.annotation.*;
|
||||
import androidx.appcompat.app.*;
|
||||
|
||||
import com.google.auto.factory.*;
|
||||
|
||||
import org.isoron.androidbase.activities.*;
|
||||
import org.isoron.uhabits.core.ui.callbacks.*;
|
||||
import org.isoron.uhabits.R;
|
||||
|
||||
import butterknife.*;
|
||||
|
||||
@AutoFactory(allowSubclasses = true)
|
||||
public class ConfirmSyncKeyDialog extends AlertDialog
|
||||
{
|
||||
@BindString(R.string.sync_confirm)
|
||||
protected String question;
|
||||
|
||||
@BindString(R.string.yes)
|
||||
protected String yes;
|
||||
|
||||
@BindString(R.string.no)
|
||||
protected String no;
|
||||
|
||||
protected ConfirmSyncKeyDialog(@Provided @ActivityContext Context context,
|
||||
@NonNull OnConfirmedCallback callback)
|
||||
{
|
||||
super(context);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
setTitle(R.string.device_sync);
|
||||
setMessage(question);
|
||||
setButton(BUTTON_POSITIVE, yes, (dialog, which) -> callback.onConfirmed());
|
||||
setButton(BUTTON_NEGATIVE, no, (dialog, which) -> {});
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ package org.isoron.uhabits.activities.habits.list
|
||||
|
||||
import android.app.*
|
||||
import android.content.*
|
||||
import android.util.*
|
||||
import androidx.annotation.*
|
||||
import dagger.*
|
||||
import org.isoron.androidbase.activities.*
|
||||
@@ -31,7 +32,6 @@ import org.isoron.uhabits.activities.habits.edit.*
|
||||
import org.isoron.uhabits.activities.habits.list.views.*
|
||||
import org.isoron.uhabits.core.commands.*
|
||||
import org.isoron.uhabits.core.models.*
|
||||
import org.isoron.uhabits.core.preferences.*
|
||||
import org.isoron.uhabits.core.tasks.*
|
||||
import org.isoron.uhabits.core.ui.*
|
||||
import org.isoron.uhabits.core.ui.callbacks.*
|
||||
@@ -42,13 +42,13 @@ import org.isoron.uhabits.tasks.*
|
||||
import java.io.*
|
||||
import javax.inject.*
|
||||
|
||||
const val RESULT_IMPORT_DATA = 1
|
||||
const val RESULT_EXPORT_CSV = 2
|
||||
const val RESULT_EXPORT_DB = 3
|
||||
const val RESULT_BUG_REPORT = 4
|
||||
const val RESULT_REPAIR_DB = 5
|
||||
const val REQUEST_OPEN_DOCUMENT = 6
|
||||
const val REQUEST_SETTINGS = 7
|
||||
const val RESULT_IMPORT_DATA = 101
|
||||
const val RESULT_EXPORT_CSV = 102
|
||||
const val RESULT_EXPORT_DB = 103
|
||||
const val RESULT_BUG_REPORT = 104
|
||||
const val RESULT_REPAIR_DB = 105
|
||||
const val REQUEST_OPEN_DOCUMENT = 106
|
||||
const val REQUEST_SETTINGS = 107
|
||||
|
||||
@ActivityScope
|
||||
class ListHabitsScreen
|
||||
@@ -63,6 +63,7 @@ class ListHabitsScreen
|
||||
private val exportDBFactory: ExportDBTaskFactory,
|
||||
private val importTaskFactory: ImportDataTaskFactory,
|
||||
private val confirmDeleteDialogFactory: ConfirmDeleteDialogFactory,
|
||||
private val confirmSyncKeyDialogFactory: ConfirmSyncKeyDialogFactory,
|
||||
private val colorPickerFactory: ColorPickerDialogFactory,
|
||||
private val numberPickerFactory: NumberPickerFactory,
|
||||
private val behavior: Lazy<ListHabitsBehavior>,
|
||||
@@ -82,6 +83,12 @@ class ListHabitsScreen
|
||||
setMenu(menu.get())
|
||||
setSelectionMenu(selectionMenu.get())
|
||||
commandRunner.addListener(this)
|
||||
if(activity.intent.action == "android.intent.action.VIEW") {
|
||||
val uri = activity.intent.data!!.toString()
|
||||
val key = uri.replace(Regex("^.*sync/"), "")
|
||||
Log.i("ListHabitsScreen", key)
|
||||
behavior.get().onSyncKeyOffer(key)
|
||||
}
|
||||
}
|
||||
|
||||
fun onDettached() {
|
||||
@@ -171,13 +178,14 @@ class ListHabitsScreen
|
||||
|
||||
override fun showMessage(m: ListHabitsBehavior.Message) {
|
||||
showMessage(when (m) {
|
||||
COULD_NOT_EXPORT -> R.string.could_not_export
|
||||
IMPORT_SUCCESSFUL -> R.string.habits_imported
|
||||
IMPORT_FAILED -> R.string.could_not_import
|
||||
DATABASE_REPAIRED -> R.string.database_repaired
|
||||
COULD_NOT_GENERATE_BUG_REPORT -> R.string.bug_report_failed
|
||||
FILE_NOT_RECOGNIZED -> R.string.file_not_recognized
|
||||
})
|
||||
COULD_NOT_EXPORT -> R.string.could_not_export
|
||||
IMPORT_SUCCESSFUL -> R.string.habits_imported
|
||||
IMPORT_FAILED -> R.string.could_not_import
|
||||
DATABASE_REPAIRED -> R.string.database_repaired
|
||||
COULD_NOT_GENERATE_BUG_REPORT -> R.string.bug_report_failed
|
||||
FILE_NOT_RECOGNIZED -> R.string.file_not_recognized
|
||||
SYNC_ENABLED -> R.string.sync_enabled
|
||||
})
|
||||
}
|
||||
|
||||
override fun showSendBugReportToDeveloperScreen(log: String) {
|
||||
@@ -204,6 +212,10 @@ class ListHabitsScreen
|
||||
numberPickerFactory.create(value, unit, callback).show()
|
||||
}
|
||||
|
||||
override fun showConfirmInstallSyncKey(callback: OnConfirmedCallback) {
|
||||
activity.showDialog(confirmSyncKeyDialogFactory.create(callback))
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private fun getExecuteString(command: Command): Int? {
|
||||
when (command) {
|
||||
|
||||
@@ -145,7 +145,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
{
|
||||
PreferenceCategory devCategory =
|
||||
(PreferenceCategory) findPreference("devCategory");
|
||||
devCategory.removeAll();
|
||||
devCategory.setVisible(false);
|
||||
}
|
||||
|
||||
@@ -159,6 +158,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
private void updateSyncPreferences()
|
||||
{
|
||||
if(prefs.getSyncKey().isEmpty()) {
|
||||
prefs.setSyncEnabled(false);
|
||||
((CheckBoxPreference) findPreference("pref_sync_enabled")).setChecked(false);
|
||||
}
|
||||
findPreference("pref_sync_base_url").setSummary(prefs.getSyncBaseURL());
|
||||
findPreference("pref_sync_key").setSummary(prefs.getSyncKey());
|
||||
findPreference("pref_sync_display").setVisible(prefs.isSyncEnabled());
|
||||
|
||||
@@ -44,17 +44,16 @@ class SyncActivity : BaseActivity() {
|
||||
private lateinit var preferences: Preferences
|
||||
private lateinit var taskRunner: TaskRunner
|
||||
private lateinit var baseScreen: BaseScreen
|
||||
private lateinit var themeSwitcher: AndroidThemeSwitcher
|
||||
private lateinit var binding: ActivitySyncBinding
|
||||
|
||||
private var styledResources = StyledResources(this)
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
|
||||
baseScreen = BaseScreen(this)
|
||||
|
||||
val component = (application as HabitsApplication).component
|
||||
themeSwitcher = AndroidThemeSwitcher(this, component.preferences)
|
||||
themeSwitcher.apply()
|
||||
taskRunner = component.taskRunner
|
||||
preferences = component.preferences
|
||||
|
||||
@@ -85,7 +84,7 @@ class SyncActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun displayCurrentKey() {
|
||||
displayLink("${preferences.syncBaseURL}/sync/${preferences.syncKey}")
|
||||
displayLink("https://loophabits.org/sync/${preferences.syncKey}")
|
||||
displayPassword("6B2W9F5X")
|
||||
}
|
||||
|
||||
@@ -139,27 +138,36 @@ class SyncActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun displayLink(link: String) {
|
||||
binding.qrCode.visibility = View.VISIBLE
|
||||
binding.progress.visibility = View.GONE
|
||||
binding.qrCode.visibility = View.GONE
|
||||
binding.progress.visibility = View.VISIBLE
|
||||
binding.errorPanel.visibility = View.GONE
|
||||
binding.syncLink.text = link
|
||||
displayQR(link)
|
||||
}
|
||||
|
||||
private fun displayQR(msg: String) {
|
||||
val writer = QRCodeWriter()
|
||||
val matrix = writer.encode(msg, BarcodeFormat.QR_CODE, 1024, 1024)
|
||||
val height = matrix.height
|
||||
val width = matrix.width
|
||||
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
|
||||
val bgColor = StyledResources(this).getColor(R.attr.highContrastReverseTextColor)
|
||||
val fgColor = StyledResources(this).getColor(R.attr.highContrastTextColor)
|
||||
for (x in 0 until width) {
|
||||
for (y in 0 until height) {
|
||||
val color = if (matrix.get(x, y)) fgColor else bgColor
|
||||
bitmap.setPixel(x, y, color)
|
||||
taskRunner.execute(object : Task {
|
||||
lateinit var bitmap: Bitmap
|
||||
override fun doInBackground() {
|
||||
val writer = QRCodeWriter()
|
||||
val matrix = writer.encode(msg, BarcodeFormat.QR_CODE, 1024, 1024)
|
||||
val height = matrix.height
|
||||
val width = matrix.width
|
||||
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
|
||||
val bgColor = styledResources.getColor(R.attr.highContrastReverseTextColor)
|
||||
val fgColor = styledResources.getColor(R.attr.highContrastTextColor)
|
||||
for (x in 0 until width) {
|
||||
for (y in 0 until height) {
|
||||
val color = if (matrix.get(x, y)) fgColor else bgColor
|
||||
bitmap.setPixel(x, y, color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.qrCode.setImageBitmap(bitmap)
|
||||
override fun onPostExecute() {
|
||||
binding.progress.visibility = View.GONE
|
||||
binding.qrCode.visibility = View.VISIBLE
|
||||
binding.qrCode.setImageBitmap(bitmap)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,9 @@
|
||||
</FrameLayout>
|
||||
|
||||
<!-- Password -->
|
||||
<FrameLayout style="@style/FormOuterBox">
|
||||
<FrameLayout
|
||||
style="@style/FormOuterBox"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout style="@style/FormInnerBox">
|
||||
|
||||
|
||||
@@ -206,10 +206,12 @@
|
||||
<string name="device_sync">Device sync</string>
|
||||
<string name="pref_sync_summary">When enabled, an encrypted copy of your data will be uploaded to our servers. See privacy policy.</string>
|
||||
<string name="pref_sync_title">Sync data across devices</string>
|
||||
<string name="display_sync_code">Display sync instructions</string>
|
||||
<string name="sync_instructions"><![CDATA[<b>Instructions:</b><br/>1. Install Loop in your second device.<br/>2. Open the link below in your second device.<br/>3. Provide the 8-character password below.<br/><b>Important:</b> Do not publish this information. It gives anyone access to your data.]]></string>
|
||||
<string name="display_sync_code">Show device sync instructions</string>
|
||||
<string name="sync_instructions"><![CDATA[<b>Instructions:</b><br/>1. Install Loop in your second device.<br/>2. Open the link below in your second device.<br/><b>Important:</b> Do not not make this information public. It gives anyone access to your data.]]></string>
|
||||
<string name="sync_link">Sync link</string>
|
||||
<string name="sync_link_qr">Sync link (QR code)</string>
|
||||
<string name="password">Password</string>
|
||||
<string name="copied_to_the_clipboard">Copied to the clipboard</string>
|
||||
<string name="sync_confirm"><![CDATA[Are you trying to enable device sync?\n\nThis feature allows you to sync your data across multiple devices. When enabled, an encrypted copy of your data will be uploaded to our servers.]]></string>
|
||||
<string name="sync_enabled">Device sync enabled</string>
|
||||
</resources>
|
||||
@@ -329,6 +329,11 @@ public class Preferences
|
||||
return storage.getBoolean("pref_sync_enabled", false);
|
||||
}
|
||||
|
||||
public void setSyncEnabled(boolean enabled)
|
||||
{
|
||||
storage.putBoolean("pref_sync_enabled", enabled);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return An integer representing the first day of the week. Sunday
|
||||
|
||||
@@ -25,7 +25,9 @@ import org.isoron.uhabits.core.commands.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.preferences.*;
|
||||
import org.isoron.uhabits.core.tasks.*;
|
||||
import org.isoron.uhabits.core.ui.callbacks.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
@@ -156,10 +158,19 @@ public class ListHabitsBehavior
|
||||
habit.getId());
|
||||
}
|
||||
|
||||
public void onSyncKeyOffer(@NotNull String key)
|
||||
{
|
||||
screen.showConfirmInstallSyncKey(() -> {
|
||||
prefs.setSyncKey(key);
|
||||
prefs.setSyncEnabled(true);
|
||||
screen.showMessage(Message.SYNC_ENABLED);
|
||||
});
|
||||
}
|
||||
|
||||
public enum Message
|
||||
{
|
||||
COULD_NOT_EXPORT, IMPORT_SUCCESSFUL, IMPORT_FAILED, DATABASE_REPAIRED,
|
||||
COULD_NOT_GENERATE_BUG_REPORT, FILE_NOT_RECOGNIZED
|
||||
COULD_NOT_GENERATE_BUG_REPORT, FILE_NOT_RECOGNIZED, SYNC_ENABLED
|
||||
}
|
||||
|
||||
public interface BugReporter
|
||||
@@ -196,5 +207,7 @@ public class ListHabitsBehavior
|
||||
void showSendBugReportToDeveloperScreen(String log);
|
||||
|
||||
void showSendFileScreen(@NonNull String filename);
|
||||
|
||||
void showConfirmInstallSyncKey(@NonNull OnConfirmedCallback callback);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user