Improve documentation

pull/145/head
Alinson S. Xavier 9 years ago
parent 9a44774284
commit 9a6dafaa79

@ -259,7 +259,7 @@ public class Habit
return id; return id;
} }
public void setId(Long id) public void setId(@Nullable Long id)
{ {
this.id = id; this.id = id;
} }
@ -267,12 +267,13 @@ public class Habit
/** /**
* Name of the habit * Name of the habit
*/ */
@NonNull
public String getName() public String getName()
{ {
return name; return name;
} }
public void setName(String name) public void setName(@NonNull String name)
{ {
this.name = name; this.name = name;
} }

@ -0,0 +1,23 @@
/*
* 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/>.
*/
/**
* Provides classes that represent rows in the SQLite database.
*/
package org.isoron.uhabits.models.sqlite.records;

@ -19,8 +19,18 @@
package org.isoron.uhabits.tasks; package org.isoron.uhabits.tasks;
/**
* Simple progress bar, used to indicate the progress of a task.
*/
public interface ProgressBar public interface ProgressBar
{ {
/**
* Shows the progress bar.
*/
void show(); void show();
/**
* Hides the progress bar.
*/
void hide(); void hide();
} }

@ -19,29 +19,32 @@
package org.isoron.uhabits.ui; package org.isoron.uhabits.ui;
import android.view.View; import android.view.*;
import org.isoron.uhabits.tasks.ProgressBar; import org.isoron.uhabits.tasks.*;
public class ProgressBarWrapper implements ProgressBar /**
* Android implementation of {@link ProgressBar}.
*/
public class AndroidProgressBar implements ProgressBar
{ {
private final android.widget.ProgressBar progressBar; private final android.widget.ProgressBar progressBar;
public ProgressBarWrapper(android.widget.ProgressBar progressBar) public AndroidProgressBar(android.widget.ProgressBar progressBar)
{ {
this.progressBar = progressBar; this.progressBar = progressBar;
} }
@Override @Override
public void show() public void hide()
{ {
progressBar.setIndeterminate(true); progressBar.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
} }
@Override @Override
public void hide() public void show()
{ {
progressBar.setVisibility(View.GONE); progressBar.setIndeterminate(true);
progressBar.setVisibility(View.VISIBLE);
} }
} }

@ -19,17 +19,25 @@
package org.isoron.uhabits.ui; package org.isoron.uhabits.ui;
import android.content.Intent; import android.content.*;
import android.os.Bundle; import android.os.*;
import android.support.annotation.Nullable; import android.support.annotation.*;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.*;
import android.view.Menu; import android.view.*;
import android.view.MenuItem;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.*;
/** /**
* Base class for all activities in the application. * Base class for all activities in the application.
* <p>
* This class delegates the responsibilities of an Android activity to other
* classes. For example, callbacks related to menus are forwarded to a {@link
* BaseMenu}, while callbacks related to activity results are forwarded to a
* {@link BaseScreen}.
* <p>
* A BaseActivity also installs an {@link java.lang.Thread.UncaughtExceptionHandler}
* to the main thread that logs the exception to the disk before the application
* crashes.
*/ */
abstract public class BaseActivity extends AppCompatActivity abstract public class BaseActivity extends AppCompatActivity
implements Thread.UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler
@ -48,7 +56,8 @@ abstract public class BaseActivity extends AppCompatActivity
{ {
if (menu == null) return false; if (menu == null) return false;
if (baseMenu == null) return false; if (baseMenu == null) return false;
return baseMenu.onCreate(getMenuInflater(), menu); baseMenu.onCreate(getMenuInflater(), menu);
return true;
} }
@Override @Override
@ -79,7 +88,8 @@ abstract public class BaseActivity extends AppCompatActivity
{ {
ex.printStackTrace(); ex.printStackTrace();
new BaseSystem(this).dumpBugReportToFile(); new BaseSystem(this).dumpBugReportToFile();
} catch (Exception e) }
catch (Exception e)
{ {
// ignored // ignored
} }

@ -19,11 +19,18 @@
package org.isoron.uhabits.ui; package org.isoron.uhabits.ui;
import android.support.annotation.NonNull; import android.support.annotation.*;
import android.view.Menu; import android.view.*;
import android.view.MenuInflater;
import android.view.MenuItem;
import javax.annotation.*;
/**
* Base class for all the menus in the application.
* <p>
* This class receives from BaseActivity all callbacks related to menus, such as
* menu creation and click events. It also handles some implementation details
* of creating menus in Android, such as inflating the resources.
*/
public abstract class BaseMenu public abstract class BaseMenu
{ {
private final BaseActivity activity; private final BaseActivity activity;
@ -33,28 +40,59 @@ public abstract class BaseMenu
this.activity = activity; this.activity = activity;
} }
public final boolean onCreate(@NonNull MenuInflater inflater, /**
@NonNull Menu menu) * Declare that the menu has changed, and should be recreated.
*/
public void invalidate()
{ {
menu.clear(); activity.invalidateOptionsMenu();
inflater.inflate(getMenuResourceId(), menu);
onCreate(menu);
return true;
} }
/**
* Called when the menu is first displayed.
* <p>
* The given menu is already inflated and ready to receive items. The
* application should override this method and add items to the menu here.
*
* @param menu the menu that is being created.
*/
public void onCreate(@NonNull Menu menu) public void onCreate(@NonNull Menu menu)
{ {
} }
/**
* Called when the menu is first displayed.
* <p>
* This method cannot be overridden. The application should override the
* methods onCreate(Menu) and getMenuResourceId instead.
*
* @param inflater a menu inflater, for creating the menu
* @param menu the menu that is being created.
*/
public final void onCreate(@NonNull MenuInflater inflater,
@NonNull Menu menu)
{
menu.clear();
inflater.inflate(getMenuResourceId(), menu);
onCreate(menu);
}
/**
* Called whenever an item on the menu is selected.
*
* @param item the item that was selected.
* @return true if the event was consumed, or false otherwise
*/
public boolean onItemSelected(@NonNull MenuItem item) public boolean onItemSelected(@NonNull MenuItem item)
{ {
return true; return true;
} }
/**
* Returns the id of the resource that should be used to inflate this menu.
*
* @return id of the menu resource.
*/
@Resource
protected abstract int getMenuResourceId(); protected abstract int getMenuResourceId();
public void invalidate()
{
activity.invalidateOptionsMenu();
}
} }

@ -19,26 +19,30 @@
package org.isoron.uhabits.ui; package org.isoron.uhabits.ui;
import android.content.Intent; import android.content.*;
import android.graphics.Color; import android.graphics.*;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.*;
import android.net.Uri; import android.net.*;
import android.os.Build; import android.os.*;
import android.support.annotation.NonNull; import android.support.annotation.*;
import android.support.annotation.Nullable; import android.support.v7.app.*;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDialogFragment;
import android.support.v7.view.ActionMode; import android.support.v7.view.ActionMode;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.Menu; import android.view.*;
import android.view.MenuItem; import android.widget.*;
import android.widget.Toast;
import org.isoron.uhabits.tasks.ProgressBar; import org.isoron.uhabits.tasks.ProgressBar;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.*;
import java.io.File; import java.io.*;
/**
* Base class for all screens in the application.
* <p>
* Screens are responsible for deciding what root views and what menus should be
* attached to the main window. They are also responsible for showing other
* screens and for receiving their results.
*/
public abstract class BaseScreen public abstract class BaseScreen
{ {
protected BaseActivity activity; protected BaseActivity activity;
@ -56,34 +60,72 @@ public abstract class BaseScreen
this.activity = activity; this.activity = activity;
} }
/**
* Ends the current selection operation.
*/
public void finishSelection() public void finishSelection()
{ {
if (selectionMenu == null) return; if (selectionMenu == null) return;
selectionMenu.finish(); selectionMenu.finish();
} }
/**
* Returns the progress bar that is currently visible on the screen.
* <p>
* If the root view attached to the screen does not provide any progress
* bars, returns null.
*
* @return current progress bar, or null if there are none.
*/
@Nullable @Nullable
public ProgressBar getProgressBar() public ProgressBar getProgressBar()
{ {
if (rootView == null) return null; if (rootView == null) return null;
return new ProgressBarWrapper(rootView.getProgressBar()); return new AndroidProgressBar(rootView.getProgressBar());
} }
/**
* Notifies the screen that its contents should be updated.
*/
public void invalidate() public void invalidate()
{ {
if (rootView == null) return; if (rootView == null) return;
rootView.invalidate(); rootView.invalidate();
} }
/**
* Called when another Activity has finished, and has returned some result.
*
* @param requestCode the request code originally supplied to {@link
* android.app.Activity#startActivityForResult(Intent,
* int, Bundle)}.
* @param resultCode the result code sent by the other activity.
* @param data an Intent containing extra data sent by the other
* activity.
* @see {@link android.app.Activity#onActivityResult(int, int, Intent)}
*/
public void onResult(int requestCode, int resultCode, Intent data) public void onResult(int requestCode, int resultCode, Intent data)
{ {
} }
/**
* Sets the menu to be shown by this screen.
* <p>
* This menu will be visible if when there is no active selection operation.
* If the provided menu is null, then no menu will be shown.
*
* @param menu the menu to be shown.
*/
public void setMenu(@Nullable BaseMenu menu) public void setMenu(@Nullable BaseMenu menu)
{ {
activity.setBaseMenu(menu); activity.setBaseMenu(menu);
} }
/**
* Sets the root view for this screen.
*
* @param rootView the root view for this screen.
*/
public void setRootView(@Nullable BaseRootView rootView) public void setRootView(@Nullable BaseRootView rootView)
{ {
this.rootView = rootView; this.rootView = rootView;
@ -94,7 +136,7 @@ public abstract class BaseScreen
} }
/** /**
* Set the menu to be shown when a selection is active on the screen. * Sets the menu to be shown when a selection is active on the screen.
* *
* @param menu the menu to be shown during a selection * @param menu the menu to be shown during a selection
*/ */
@ -103,6 +145,11 @@ public abstract class BaseScreen
this.selectionMenu = menu; this.selectionMenu = menu;
} }
/**
* Shows a message on the screen.
*
* @param stringId the string resource id for this message.
*/
public void showMessage(@Nullable Integer stringId) public void showMessage(@Nullable Integer stringId)
{ {
if (stringId == null) return; if (stringId == null) return;
@ -134,14 +181,21 @@ public abstract class BaseScreen
} }
/** /**
* Instructs the screen to start a selection. If a selection menu was * Instructs the screen to start a selection.
* provided, this menu will be shown instead of the regular one. * <p>
* If a selection menu was provided, this menu will be shown instead of the
* regular one.
*/ */
public void startSelection() public void startSelection()
{ {
activity.startSupportActionMode(new ActionModeWrapper()); activity.startSupportActionMode(new ActionModeWrapper());
} }
protected void showDialog(AppCompatDialogFragment dialog, String tag)
{
dialog.show(activity.getSupportFragmentManager(), tag);
}
private void initToolbar() private void initToolbar()
{ {
if (rootView == null) return; if (rootView == null) return;
@ -174,11 +228,6 @@ public abstract class BaseScreen
} }
} }
protected void showDialog(AppCompatDialogFragment dialog, String tag)
{
dialog.show(activity.getSupportFragmentManager(), tag);
}
private class ActionModeWrapper implements ActionMode.Callback private class ActionModeWrapper implements ActionMode.Callback
{ {
@Override @Override
@ -203,7 +252,7 @@ public abstract class BaseScreen
public void onDestroyActionMode(@Nullable ActionMode mode) public void onDestroyActionMode(@Nullable ActionMode mode)
{ {
if (selectionMenu == null) return; if (selectionMenu == null) return;
selectionMenu.onDestroy(); selectionMenu.onFinish();
} }
@Override @Override

@ -19,13 +19,22 @@
package org.isoron.uhabits.ui; package org.isoron.uhabits.ui;
import android.support.annotation.NonNull; import android.support.annotation.*;
import android.support.annotation.Nullable;
import android.support.v7.view.ActionMode; import android.support.v7.view.ActionMode;
import android.view.Menu; import android.view.*;
import android.view.MenuInflater;
import android.view.MenuItem;
/**
* Base class for all the selection menus in the application.
* <p>
* A selection menu is a menu that appears when the screen starts a selection
* operation. It contains actions that modify the selected items, such as delete
* or archive. Since it replaces the toolbar, it also has a title.
* <p>
* This class hides many implementation details of creating such menus in
* Android. The interface is supposed to look very similar to {@link BaseMenu},
* with a few additional methods, such as finishing the selection operation.
* Internally, it uses an {@link ActionMode}.
*/
public abstract class BaseSelectionMenu public abstract class BaseSelectionMenu
{ {
@Nullable @Nullable
@ -39,35 +48,69 @@ public abstract class BaseSelectionMenu
if (actionMode != null) actionMode.finish(); if (actionMode != null) actionMode.finish();
} }
/**
* Declare that the menu has changed, and should be recreated.
*/
public void invalidate() public void invalidate()
{ {
if (actionMode != null) actionMode.invalidate(); if (actionMode != null) actionMode.invalidate();
} }
public final void onCreate(@NonNull MenuInflater menuInflater, /**
* Called when the menu is first displayed.
* <p>
* This method cannot be overridden. The application should override the
* methods onCreate(Menu) and getMenuResourceId instead.
*
* @param inflater a menu inflater, for creating the menu
* @param mode the action mode associated with this menu.
* @param menu the menu that is being created.
*/
public final void onCreate(@NonNull MenuInflater inflater,
@NonNull ActionMode mode, @NonNull ActionMode mode,
@NonNull Menu menu) @NonNull Menu menu)
{ {
this.actionMode = mode; this.actionMode = mode;
menuInflater.inflate(getResourceId(), menu); inflater.inflate(getResourceId(), menu);
onCreate(menu); onCreate(menu);
} }
public void onDestroy() /**
* Called when the selection operation is about to finish.
*/
public void onFinish()
{ {
} }
/**
* Called whenever an item on the menu is selected.
*
* @param item the item that was selected.
* @return true if the event was consumed, or false otherwise
*/
public boolean onItemClicked(@NonNull MenuItem item) public boolean onItemClicked(@NonNull MenuItem item)
{ {
return false; return false;
} }
/**
* Called whenever the menu is invalidated.
*
* @param menu the menu to be refreshed
* @return true if the menu has changes, false otherwise
*/
public boolean onPrepare(@NonNull Menu menu) public boolean onPrepare(@NonNull Menu menu)
{ {
return false; return false;
} }
/**
* Sets the title of the selection menu.
*
* @param title the new title.
*/
public void setTitle(String title) public void setTitle(String title)
{ {
if (actionMode != null) actionMode.setTitle(title); if (actionMode != null) actionMode.setTitle(title);
@ -76,10 +119,9 @@ public abstract class BaseSelectionMenu
protected abstract int getResourceId(); protected abstract int getResourceId();
/** /**
* Called when the menu is first created, right after the menu has been * Called when the menu is first created.
* inflated.
* *
* @param menu the menu containing the buttons * @param menu the menu being created
*/ */
protected void onCreate(@NonNull Menu menu) protected void onCreate(@NonNull Menu menu)
{ {

@ -19,29 +19,31 @@
package org.isoron.uhabits.ui; package org.isoron.uhabits.ui;
import android.content.Context; import android.content.*;
import android.os.Environment; import android.os.*;
import android.support.annotation.NonNull; import android.support.annotation.*;
import android.view.WindowManager; import android.view.*;
import org.isoron.uhabits.BuildConfig; import org.isoron.uhabits.*;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.models.HabitList; import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.utils.DateUtils; import org.isoron.uhabits.widgets.*;
import org.isoron.uhabits.utils.FileUtils;
import org.isoron.uhabits.utils.ReminderUtils; import java.io.*;
import org.isoron.uhabits.widgets.WidgetManager; import java.lang.Process;
import java.util.*;
import java.io.BufferedReader;
import java.io.File; import javax.inject.*;
import java.io.FileWriter;
import java.io.IOException; /**
import java.io.InputStreamReader; * Base class for all systems class in the application.
import java.util.LinkedList; * <p>
* Classes derived from BaseSystem are responsible for handling events and
import javax.inject.Inject; * sending requests to the Android operating system. Examples include capturing
* a bug report, obtaining device information, or requesting runtime
* permissions.
*/
public class BaseSystem public class BaseSystem
{ {
private Context context; private Context context;
@ -55,69 +57,16 @@ public class BaseSystem
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
} }
public String getLogcat() throws IOException /**
{ * Captures a bug report and saves it to a file in the SD card.
int maxNLines = 250; * <p>
StringBuilder builder = new StringBuilder(); * The contents of the file are generated by the method {@link
* #getBugReport()}. The file is saved in the apps's external private
String[] command = new String[]{"logcat", "-d"}; * storage.
Process process = Runtime.getRuntime().exec(command); *
* @return the generated file.
InputStreamReader in = new InputStreamReader(process.getInputStream()); * @throws IOException when I/O errors occur.
BufferedReader bufferedReader = new BufferedReader(in); */
LinkedList<String> log = new LinkedList<>();
String line;
while ((line = bufferedReader.readLine()) != null)
{
log.addLast(line);
if (log.size() > maxNLines) log.removeFirst();
}
for (String l : log)
{
builder.append(l);
builder.append('\n');
}
return builder.toString();
}
public String getDeviceInfo()
{
if (context == null) return "";
StringBuilder b = new StringBuilder();
WindowManager wm =
(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
b.append(
String.format("App Version Name: %s\n", BuildConfig.VERSION_NAME));
b.append(
String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE));
b.append(String.format("OS Version: %s (%s)\n",
java.lang.System.getProperty("os.version"),
android.os.Build.VERSION.INCREMENTAL));
b.append(
String.format("OS API Level: %s\n", android.os.Build.VERSION.SDK));
b.append(String.format("Device: %s\n", android.os.Build.DEVICE));
b.append(
String.format("Model (Product): %s (%s)\n", android.os.Build.MODEL,
android.os.Build.PRODUCT));
b.append(
String.format("Manufacturer: %s\n", android.os.Build.MANUFACTURER));
b.append(String.format("Other tags: %s\n", android.os.Build.TAGS));
b.append(String.format("Screen Width: %s\n",
wm.getDefaultDisplay().getWidth()));
b.append(String.format("Screen Height: %s\n",
wm.getDefaultDisplay().getHeight()));
b.append(String.format("SD Card state: %s\n\n",
Environment.getExternalStorageState()));
return b.toString();
}
@NonNull @NonNull
public File dumpBugReportToFile() throws IOException public File dumpBugReportToFile() throws IOException
{ {
@ -138,6 +87,14 @@ public class BaseSystem
return logFile; return logFile;
} }
/**
* Captures and returns a bug report.
* <p>
* 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 @NonNull
public String getBugReport() throws IOException public String getBugReport() throws IOException
{ {
@ -146,6 +103,9 @@ public class BaseSystem
return deviceInfo + "\n" + logcat; return deviceInfo + "\n" + logcat;
} }
/**
* Recreates all application reminders.
*/
public void scheduleReminders() public void scheduleReminders()
{ {
new BaseTask() new BaseTask()
@ -159,6 +119,9 @@ public class BaseSystem
}.execute(); }.execute();
} }
/**
* Refreshes all application widgets.
*/
public void updateWidgets() public void updateWidgets()
{ {
new BaseTask() new BaseTask()
@ -171,4 +134,59 @@ public class BaseSystem
} }
}.execute(); }.execute();
} }
private 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());
}
private String getLogcat() throws IOException
{
int maxLineCount = 250;
StringBuilder builder = new StringBuilder();
String[] command = new String[]{"logcat", "-d"};
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();
}
} }

@ -59,10 +59,10 @@ public class ListHabitsSelectionMenu extends BaseSelectionMenu
} }
@Override @Override
public void onDestroy() public void onFinish()
{ {
if (adapter != null) adapter.clearSelection(); if (adapter != null) adapter.clearSelection();
super.onDestroy(); super.onFinish();
} }
@Override @Override

Loading…
Cancel
Save