Implement intent filter; hide password for now

pull/699/head
Alinson S. Xavier 5 years ago
parent 23f2978a64
commit 0859cec853

@ -68,9 +68,16 @@
android:targetActivity=".activities.habits.list.ListHabitsActivity"> android:targetActivity=".activities.habits.list.ListHabitsActivity">
<intent-filter android:label="@string/main_activity_title"> <intent-filter android:label="@string/main_activity_title">
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </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-alias>
<activity <activity

@ -34,8 +34,11 @@ abstract class HabitsActivity : BaseActivity() {
appComponent = (applicationContext as HabitsApplication).component appComponent = (applicationContext as HabitsApplication).component
val habit = getHabitFromIntent(appComponent.habitList) var habit = appComponent.modelFactory.buildHabit()
?: appComponent.modelFactory.buildHabit() if(intent.action != "android.intent.action.VIEW") {
val intentHabit = getHabitFromIntent(appComponent.habitList)
if (intentHabit != null) habit = intentHabit
}
component = DaggerHabitsActivityComponent component = DaggerHabitsActivityComponent
.builder() .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.app.*
import android.content.* import android.content.*
import android.util.*
import androidx.annotation.* import androidx.annotation.*
import dagger.* import dagger.*
import org.isoron.androidbase.activities.* 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.activities.habits.list.views.*
import org.isoron.uhabits.core.commands.* import org.isoron.uhabits.core.commands.*
import org.isoron.uhabits.core.models.* import org.isoron.uhabits.core.models.*
import org.isoron.uhabits.core.preferences.*
import org.isoron.uhabits.core.tasks.* import org.isoron.uhabits.core.tasks.*
import org.isoron.uhabits.core.ui.* import org.isoron.uhabits.core.ui.*
import org.isoron.uhabits.core.ui.callbacks.* import org.isoron.uhabits.core.ui.callbacks.*
@ -42,13 +42,13 @@ import org.isoron.uhabits.tasks.*
import java.io.* import java.io.*
import javax.inject.* import javax.inject.*
const val RESULT_IMPORT_DATA = 1 const val RESULT_IMPORT_DATA = 101
const val RESULT_EXPORT_CSV = 2 const val RESULT_EXPORT_CSV = 102
const val RESULT_EXPORT_DB = 3 const val RESULT_EXPORT_DB = 103
const val RESULT_BUG_REPORT = 4 const val RESULT_BUG_REPORT = 104
const val RESULT_REPAIR_DB = 5 const val RESULT_REPAIR_DB = 105
const val REQUEST_OPEN_DOCUMENT = 6 const val REQUEST_OPEN_DOCUMENT = 106
const val REQUEST_SETTINGS = 7 const val REQUEST_SETTINGS = 107
@ActivityScope @ActivityScope
class ListHabitsScreen class ListHabitsScreen
@ -63,6 +63,7 @@ class ListHabitsScreen
private val exportDBFactory: ExportDBTaskFactory, private val exportDBFactory: ExportDBTaskFactory,
private val importTaskFactory: ImportDataTaskFactory, private val importTaskFactory: ImportDataTaskFactory,
private val confirmDeleteDialogFactory: ConfirmDeleteDialogFactory, private val confirmDeleteDialogFactory: ConfirmDeleteDialogFactory,
private val confirmSyncKeyDialogFactory: ConfirmSyncKeyDialogFactory,
private val colorPickerFactory: ColorPickerDialogFactory, private val colorPickerFactory: ColorPickerDialogFactory,
private val numberPickerFactory: NumberPickerFactory, private val numberPickerFactory: NumberPickerFactory,
private val behavior: Lazy<ListHabitsBehavior>, private val behavior: Lazy<ListHabitsBehavior>,
@ -82,6 +83,12 @@ class ListHabitsScreen
setMenu(menu.get()) setMenu(menu.get())
setSelectionMenu(selectionMenu.get()) setSelectionMenu(selectionMenu.get())
commandRunner.addListener(this) 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() { fun onDettached() {
@ -171,13 +178,14 @@ class ListHabitsScreen
override fun showMessage(m: ListHabitsBehavior.Message) { override fun showMessage(m: ListHabitsBehavior.Message) {
showMessage(when (m) { showMessage(when (m) {
COULD_NOT_EXPORT -> R.string.could_not_export COULD_NOT_EXPORT -> R.string.could_not_export
IMPORT_SUCCESSFUL -> R.string.habits_imported IMPORT_SUCCESSFUL -> R.string.habits_imported
IMPORT_FAILED -> R.string.could_not_import IMPORT_FAILED -> R.string.could_not_import
DATABASE_REPAIRED -> R.string.database_repaired DATABASE_REPAIRED -> R.string.database_repaired
COULD_NOT_GENERATE_BUG_REPORT -> R.string.bug_report_failed COULD_NOT_GENERATE_BUG_REPORT -> R.string.bug_report_failed
FILE_NOT_RECOGNIZED -> R.string.file_not_recognized FILE_NOT_RECOGNIZED -> R.string.file_not_recognized
}) SYNC_ENABLED -> R.string.sync_enabled
})
} }
override fun showSendBugReportToDeveloperScreen(log: String) { override fun showSendBugReportToDeveloperScreen(log: String) {
@ -204,6 +212,10 @@ class ListHabitsScreen
numberPickerFactory.create(value, unit, callback).show() numberPickerFactory.create(value, unit, callback).show()
} }
override fun showConfirmInstallSyncKey(callback: OnConfirmedCallback) {
activity.showDialog(confirmSyncKeyDialogFactory.create(callback))
}
@StringRes @StringRes
private fun getExecuteString(command: Command): Int? { private fun getExecuteString(command: Command): Int? {
when (command) { when (command) {

@ -145,7 +145,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
{ {
PreferenceCategory devCategory = PreferenceCategory devCategory =
(PreferenceCategory) findPreference("devCategory"); (PreferenceCategory) findPreference("devCategory");
devCategory.removeAll();
devCategory.setVisible(false); devCategory.setVisible(false);
} }
@ -159,6 +158,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
private void updateSyncPreferences() 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_base_url").setSummary(prefs.getSyncBaseURL());
findPreference("pref_sync_key").setSummary(prefs.getSyncKey()); findPreference("pref_sync_key").setSummary(prefs.getSyncKey());
findPreference("pref_sync_display").setVisible(prefs.isSyncEnabled()); findPreference("pref_sync_display").setVisible(prefs.isSyncEnabled());

@ -44,17 +44,16 @@ class SyncActivity : BaseActivity() {
private lateinit var preferences: Preferences private lateinit var preferences: Preferences
private lateinit var taskRunner: TaskRunner private lateinit var taskRunner: TaskRunner
private lateinit var baseScreen: BaseScreen private lateinit var baseScreen: BaseScreen
private lateinit var themeSwitcher: AndroidThemeSwitcher
private lateinit var binding: ActivitySyncBinding private lateinit var binding: ActivitySyncBinding
private var styledResources = StyledResources(this)
override fun onCreate(state: Bundle?) { override fun onCreate(state: Bundle?) {
super.onCreate(state) super.onCreate(state)
baseScreen = BaseScreen(this) baseScreen = BaseScreen(this)
val component = (application as HabitsApplication).component val component = (application as HabitsApplication).component
themeSwitcher = AndroidThemeSwitcher(this, component.preferences)
themeSwitcher.apply()
taskRunner = component.taskRunner taskRunner = component.taskRunner
preferences = component.preferences preferences = component.preferences
@ -85,7 +84,7 @@ class SyncActivity : BaseActivity() {
} }
private fun displayCurrentKey() { private fun displayCurrentKey() {
displayLink("${preferences.syncBaseURL}/sync/${preferences.syncKey}") displayLink("https://loophabits.org/sync/${preferences.syncKey}")
displayPassword("6B2W9F5X") displayPassword("6B2W9F5X")
} }
@ -139,27 +138,36 @@ class SyncActivity : BaseActivity() {
} }
private fun displayLink(link: String) { private fun displayLink(link: String) {
binding.qrCode.visibility = View.VISIBLE binding.qrCode.visibility = View.GONE
binding.progress.visibility = View.GONE binding.progress.visibility = View.VISIBLE
binding.errorPanel.visibility = View.GONE binding.errorPanel.visibility = View.GONE
binding.syncLink.text = link binding.syncLink.text = link
displayQR(link) displayQR(link)
} }
private fun displayQR(msg: String) { private fun displayQR(msg: String) {
val writer = QRCodeWriter() taskRunner.execute(object : Task {
val matrix = writer.encode(msg, BarcodeFormat.QR_CODE, 1024, 1024) lateinit var bitmap: Bitmap
val height = matrix.height override fun doInBackground() {
val width = matrix.width val writer = QRCodeWriter()
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) val matrix = writer.encode(msg, BarcodeFormat.QR_CODE, 1024, 1024)
val bgColor = StyledResources(this).getColor(R.attr.highContrastReverseTextColor) val height = matrix.height
val fgColor = StyledResources(this).getColor(R.attr.highContrastTextColor) val width = matrix.width
for (x in 0 until width) { bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
for (y in 0 until height) { val bgColor = styledResources.getColor(R.attr.highContrastReverseTextColor)
val color = if (matrix.get(x, y)) fgColor else bgColor val fgColor = styledResources.getColor(R.attr.highContrastTextColor)
bitmap.setPixel(x, y, color) 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)
}
}
} }
} override fun onPostExecute() {
binding.qrCode.setImageBitmap(bitmap) binding.progress.visibility = View.GONE
binding.qrCode.visibility = View.VISIBLE
binding.qrCode.setImageBitmap(bitmap)
}
})
} }
} }

@ -123,7 +123,9 @@
</FrameLayout> </FrameLayout>
<!-- Password --> <!-- Password -->
<FrameLayout style="@style/FormOuterBox"> <FrameLayout
style="@style/FormOuterBox"
android:visibility="gone">
<LinearLayout style="@style/FormInnerBox"> <LinearLayout style="@style/FormInnerBox">

@ -206,10 +206,12 @@
<string name="device_sync">Device sync</string> <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_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="pref_sync_title">Sync data across devices</string>
<string name="display_sync_code">Display sync instructions</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/>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="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">Sync link</string>
<string name="sync_link_qr">Sync link (QR code)</string> <string name="sync_link_qr">Sync link (QR code)</string>
<string name="password">Password</string> <string name="password">Password</string>
<string name="copied_to_the_clipboard">Copied to the clipboard</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> </resources>

@ -329,6 +329,11 @@ public class Preferences
return storage.getBoolean("pref_sync_enabled", false); 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 * @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.models.*;
import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.core.ui.callbacks.*;
import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.core.utils.*;
import org.jetbrains.annotations.*;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@ -156,10 +158,19 @@ public class ListHabitsBehavior
habit.getId()); habit.getId());
} }
public void onSyncKeyOffer(@NotNull String key)
{
screen.showConfirmInstallSyncKey(() -> {
prefs.setSyncKey(key);
prefs.setSyncEnabled(true);
screen.showMessage(Message.SYNC_ENABLED);
});
}
public enum Message public enum Message
{ {
COULD_NOT_EXPORT, IMPORT_SUCCESSFUL, IMPORT_FAILED, DATABASE_REPAIRED, 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 public interface BugReporter
@ -196,5 +207,7 @@ public class ListHabitsBehavior
void showSendBugReportToDeveloperScreen(String log); void showSendBugReportToDeveloperScreen(String log);
void showSendFileScreen(@NonNull String filename); void showSendFileScreen(@NonNull String filename);
void showConfirmInstallSyncKey(@NonNull OnConfirmedCallback callback);
} }
} }

Loading…
Cancel
Save