add hint to add site, rework intro flow.

multisite
Floens 8 years ago
parent a15e70630e
commit 9b38f11efe
  1. 23
      Clover/app/src/main/java/org/floens/chan/core/presenter/SitesSetupPresenter.java
  2. 4
      Clover/app/src/main/java/org/floens/chan/core/site/SiteManager.java
  3. 23
      Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
  4. 5
      Clover/app/src/main/java/org/floens/chan/ui/controller/IntroController.java
  5. 2
      Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
  6. 28
      Clover/app/src/main/java/org/floens/chan/ui/controller/SitesSetupController.java
  7. 75
      Clover/app/src/main/java/org/floens/chan/ui/helper/HintPopup.java
  8. 18
      Clover/app/src/main/java/org/floens/chan/ui/helper/VersionHandler.java
  9. 12
      Clover/app/src/main/java/org/floens/chan/ui/layout/SiteAddLayout.java
  10. 1
      Clover/app/src/main/res/layout/controller_intro.xml
  11. 48
      Clover/app/src/main/res/layout/popup_hint_top.xml
  12. 1
      Clover/app/src/main/res/values/strings.xml

@ -50,7 +50,17 @@ public class SitesSetupPresenter {
this.callback.setAddedSites(sites); this.callback.setAddedSites(sites);
this.callback.setNextAllowed(!sites.isEmpty(), false); this.callback.setNextAllowed(!sites.isEmpty());
if (sites.isEmpty()) {
callback.presentIntro();
}
}
public void onIntroDismissed() {
if (sites.isEmpty()) {
callback.showHint();
}
} }
public void bindAddDialog(AddCallback addCallback) { public void bindAddDialog(AddCallback addCallback) {
@ -74,6 +84,7 @@ public class SitesSetupPresenter {
@Override @Override
public void onSiteAdded(Site site) { public void onSiteAdded(Site site) {
siteAdded(site); siteAdded(site);
addCallback.dismissDialog();
} }
@Override @Override
@ -96,7 +107,7 @@ public class SitesSetupPresenter {
callback.setAddedSites(sites); callback.setAddedSites(sites);
callback.setNextAllowed(!sites.isEmpty(), true); callback.setNextAllowed(!sites.isEmpty());
} }
public void onSiteCellSettingsClicked(Site site) { public void onSiteCellSettingsClicked(Site site) {
@ -104,16 +115,22 @@ public class SitesSetupPresenter {
} }
public interface Callback { public interface Callback {
void presentIntro();
void showHint();
void showAddDialog(); void showAddDialog();
void setAddedSites(List<Site> sites); void setAddedSites(List<Site> sites);
void setNextAllowed(boolean nextAllowed, boolean animate); void setNextAllowed(boolean nextAllowed);
void openSiteConfiguration(Site site); void openSiteConfiguration(Site site);
} }
public interface AddCallback { public interface AddCallback {
void showAddError(String error); void showAddError(String error);
void dismissDialog();
} }
} }

@ -46,6 +46,10 @@ public class SiteManager {
this.resolver = resolver; this.resolver = resolver;
} }
public boolean areSitesSetup() {
return !Sites.allSites().isEmpty();
}
public void addSite(String url, SiteAddCallback callback) { public void addSite(String url, SiteAddCallback callback) {
Site existing = resolver.findSiteForUrl(url); Site existing = resolver.findSiteForUrl(url);
if (existing != null) { if (existing != null) {

@ -45,12 +45,13 @@ import org.floens.chan.core.model.orm.Loadable;
import org.floens.chan.core.model.orm.Pin; import org.floens.chan.core.model.orm.Pin;
import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.core.site.Site; import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.SiteManager;
import org.floens.chan.core.site.SiteResolver; import org.floens.chan.core.site.SiteResolver;
import org.floens.chan.core.site.Sites; import org.floens.chan.core.site.Sites;
import org.floens.chan.ui.controller.BrowseController; import org.floens.chan.ui.controller.BrowseController;
import org.floens.chan.ui.controller.DoubleNavigationController; import org.floens.chan.ui.controller.DoubleNavigationController;
import org.floens.chan.ui.controller.DrawerController; import org.floens.chan.ui.controller.DrawerController;
import org.floens.chan.ui.controller.SetupController; import org.floens.chan.ui.controller.SitesSetupController;
import org.floens.chan.ui.controller.SplitNavigationController; import org.floens.chan.ui.controller.SplitNavigationController;
import org.floens.chan.ui.controller.StyledToolbarNavigationController; import org.floens.chan.ui.controller.StyledToolbarNavigationController;
import org.floens.chan.ui.controller.ThreadSlideController; import org.floens.chan.ui.controller.ThreadSlideController;
@ -98,6 +99,9 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
@Inject @Inject
SiteResolver siteResolver; SiteResolver siteResolver;
@Inject
SiteManager siteManager;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -146,11 +150,14 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
// Not from a state or from an url, launch the setup controller if no boards are setup up yet, // Not from a state or from an url, launch the setup controller if no boards are setup up yet,
// otherwise load the default saved board. // otherwise load the default saved board.
if (!handled) { if (!handled) {
/*if (boardManager.getSavedBoards().isEmpty()) { restoreFresh();
setupWithNoBoards(); }
} else { }
browseController.loadWithDefaultBoard();
}*/ private void restoreFresh() {
if (!siteManager.areSitesSetup()) {
mainNavigationController.pushController(new SitesSetupController(this), false);
} else {
browseController.loadWithDefaultBoard(); browseController.loadWithDefaultBoard();
} }
} }
@ -209,10 +216,6 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
return handled; return handled;
} }
private void setupWithNoBoards() {
mainNavigationController.presentController(new SetupController(this), false);
}
private Pair<Loadable, Loadable> resolveChanState(ChanState state) { private Pair<Loadable, Loadable> resolveChanState(ChanState state) {
DatabaseLoadableManager loadableManager = databaseManager.getDatabaseLoadableManager(); DatabaseLoadableManager loadableManager = databaseManager.getDatabaseLoadableManager();

@ -23,7 +23,6 @@ import android.widget.Button;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.controller.Controller; import org.floens.chan.controller.Controller;
import org.floens.chan.core.presenter.SetupPresenter;
public class IntroController extends Controller implements View.OnClickListener { public class IntroController extends Controller implements View.OnClickListener {
private Button start; private Button start;
@ -45,8 +44,8 @@ public class IntroController extends Controller implements View.OnClickListener
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (v == start) { if (v == start) {
SetupPresenter presenter = ((SetupController) navigationController).getPresenter(); ((SitesSetupController) presentedByController).onIntroDismissed();
presenter.startClicked(); stopPresenting();
} }
} }
} }

@ -77,7 +77,7 @@ public class MainSettingsController extends SettingsController implements Toolba
private ChanSettings.LayoutMode previousLayoutMode; private ChanSettings.LayoutMode previousLayoutMode;
private PopupWindow advancedSettingsHint; private HintPopup advancedSettingsHint;
@Inject @Inject
DatabaseManager databaseManager; DatabaseManager databaseManager;

@ -36,6 +36,7 @@ import org.floens.chan.R;
import org.floens.chan.core.presenter.SitesSetupPresenter; import org.floens.chan.core.presenter.SitesSetupPresenter;
import org.floens.chan.core.site.Site; import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.SiteIcon; import org.floens.chan.core.site.SiteIcon;
import org.floens.chan.ui.helper.HintPopup;
import org.floens.chan.ui.layout.SiteAddLayout; import org.floens.chan.ui.layout.SiteAddLayout;
import org.floens.chan.ui.toolbar.ToolbarMenu; import org.floens.chan.ui.toolbar.ToolbarMenu;
import org.floens.chan.ui.toolbar.ToolbarMenuItem; import org.floens.chan.ui.toolbar.ToolbarMenuItem;
@ -132,6 +133,22 @@ public class SitesSetupController extends StyledToolbarNavigationController impl
} }
} }
@Override
public void presentIntro() {
presentController(new IntroController(context), false);
}
public void onIntroDismissed() {
presenter.onIntroDismissed();
}
@Override
public void showHint() {
String s = context.getString(R.string.setup_sites_add_hint);
HintPopup popup = new HintPopup(context, addButton, s, 0, 0, true);
popup.show();
}
@Override @Override
public void showAddDialog() { public void showAddDialog() {
@SuppressLint("InflateParams") final SiteAddLayout dialogView = @SuppressLint("InflateParams") final SiteAddLayout dialogView =
@ -145,7 +162,11 @@ public class SitesSetupController extends StyledToolbarNavigationController impl
.setTitle(R.string.setup_sites_add_title) .setTitle(R.string.setup_sites_add_title)
.setPositiveButton(R.string.add, null) .setPositiveButton(R.string.add, null)
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .create();
dialogView.setDialog(dialog);
dialog.show();
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnClickListener((v) -> { positiveButton.setOnClickListener((v) -> {
@ -168,10 +189,13 @@ public class SitesSetupController extends StyledToolbarNavigationController impl
} }
@Override @Override
public void setNextAllowed(boolean nextAllowed, boolean animate) { public void setNextAllowed(boolean nextAllowed) {
if (doneMenuItem != null) { if (doneMenuItem != null) {
doneMenuItem.getView().animate().alpha(nextAllowed ? 1f : 0f).start(); doneMenuItem.getView().animate().alpha(nextAllowed ? 1f : 0f).start();
} }
if (!nextAllowed) {
navigationItem.swipeable = false;
}
} }
private void onSiteCellSettingsClicked(Site site) { private void onSiteCellSettingsClicked(Site site) {

@ -17,6 +17,7 @@
*/ */
package org.floens.chan.ui.helper; package org.floens.chan.ui.helper;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
@ -28,51 +29,79 @@ import android.widget.PopupWindow;
import android.widget.TextView; import android.widget.TextView;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.utils.AndroidUtils;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AndroidUtils.getString; import static org.floens.chan.utils.AndroidUtils.getString;
public class HintPopup { public class HintPopup {
public static PopupWindow show(Context context, View anchor, int text) { public static HintPopup show(Context context, View anchor, int text) {
return show(context, anchor, getString(text)); return show(context, anchor, getString(text));
} }
public static PopupWindow show(final Context context, final View anchor, final String text) { public static HintPopup show(final Context context, final View anchor, final String text) {
return show(context, anchor, text, 0, 0); return show(context, anchor, text, 0, 0);
} }
public static PopupWindow show(final Context context, final View anchor, final String text, final int offsetX, final int offsetY) { public static HintPopup show(final Context context, final View anchor, final String text, final int offsetX, final int offsetY) {
final LinearLayout popupView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.popup_hint, null); HintPopup hintPopup = new HintPopup(context, anchor, text, offsetX, offsetY, false);
hintPopup.show();
return hintPopup;
}
private TextView textView;
private PopupWindow popupWindow;
private LinearLayout popupView;
private final View anchor;
private String text;
private final int offsetX;
private final int offsetY;
private final boolean top;
private boolean dismissed;
public HintPopup(Context context, final View anchor, final String text, final int offsetX, final int offsetY, final boolean top) {
this.anchor = anchor;
this.text = text;
this.offsetX = offsetX;
this.offsetY = offsetY;
this.top = top;
createView(context);
}
TextView textView = (TextView) popupView.findViewById(R.id.text); @SuppressLint("InflateParams")
private void createView(Context context) {
popupView = (LinearLayout) LayoutInflater.from(context)
.inflate(top ? R.layout.popup_hint_top : R.layout.popup_hint, null);
textView = popupView.findViewById(R.id.text);
textView.setText(text); textView.setText(text);
final PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setOutsideTouchable(true); popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupView.setOnClickListener(new View.OnClickListener() { popupView.setOnClickListener(v -> {
@Override // popupWindow.dismiss();
public void onClick(View v) {
popupWindow.dismiss();
}
}); });
}
popupView.postDelayed(new Runnable() { public void show() {
@Override AndroidUtils.runOnUiThread(() -> {
public void run() { if (!dismissed) {
popupView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); popupView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
popupWindow.showAsDropDown(anchor, -popupView.getMeasuredWidth() + anchor.getWidth() + offsetX, -dp(25) + offsetY); // TODO: cleanup
int xoff = -popupView.getMeasuredWidth() + anchor.getWidth() + offsetX - dp(2);
int yoff = -dp(25) + offsetY + (top ? -anchor.getHeight() - dp(30) : 0);
popupWindow.showAsDropDown(anchor, xoff, yoff);
} }
}, 100); }, 400);
popupView.postDelayed(new Runnable() { // popupView.postDelayed(popupWindow::dismiss, 5000);
@Override }
public void run() {
popupWindow.dismiss();
}
}, 5000);
return popupWindow; public void dismiss() {
popupWindow.dismiss();
dismissed = true;
} }
} }

@ -92,13 +92,11 @@ public class VersionHandler implements UpdateManager.UpdateCallback {
public void run() { public void run() {
int previous = ChanSettings.previousVersion.get(); int previous = ChanSettings.previousVersion.get();
if (previous < CURRENT_VERSION) { if (previous < CURRENT_VERSION) {
if (previous < 1) { handleUpdate(previous);
cleanupOutdatedIonFolder(context);
}
// Add more previous version checks here
showMessage(CURRENT_VERSION); if (previous != 0) {
showMessage(CURRENT_VERSION);
}
ChanSettings.previousVersion.set(CURRENT_VERSION); ChanSettings.previousVersion.set(CURRENT_VERSION);
@ -111,6 +109,14 @@ public class VersionHandler implements UpdateManager.UpdateCallback {
} }
} }
private void handleUpdate(int previous) {
if (previous < 1) {
cleanupOutdatedIonFolder(context);
}
// Add more previous version checks here
}
public boolean isUpdatingAvailable() { public boolean isUpdatingAvailable() {
return updateManager.isUpdatingAvailable(); return updateManager.isUpdatingAvailable();
} }

@ -1,5 +1,6 @@
package org.floens.chan.ui.layout; package org.floens.chan.ui.layout;
import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.support.constraint.ConstraintLayout; import android.support.constraint.ConstraintLayout;
import android.support.design.widget.TextInputLayout; import android.support.design.widget.TextInputLayout;
@ -12,6 +13,8 @@ import org.floens.chan.core.presenter.SitesSetupPresenter;
public class SiteAddLayout extends ConstraintLayout implements SitesSetupPresenter.AddCallback { public class SiteAddLayout extends ConstraintLayout implements SitesSetupPresenter.AddCallback {
private EditText url; private EditText url;
private TextInputLayout urlContainer; private TextInputLayout urlContainer;
private Dialog dialog;
private SitesSetupPresenter presenter; private SitesSetupPresenter presenter;
public SiteAddLayout(Context context) { public SiteAddLayout(Context context) {
@ -34,6 +37,10 @@ public class SiteAddLayout extends ConstraintLayout implements SitesSetupPresent
url = findViewById(R.id.url); url = findViewById(R.id.url);
} }
public void setDialog(Dialog dialog) {
this.dialog = dialog;
}
public void setPresenter(SitesSetupPresenter presenter) { public void setPresenter(SitesSetupPresenter presenter) {
this.presenter = presenter; this.presenter = presenter;
} }
@ -58,4 +65,9 @@ public class SiteAddLayout extends ConstraintLayout implements SitesSetupPresent
public void showAddError(String error) { public void showAddError(String error) {
urlContainer.setError(error); urlContainer.setError(error);
} }
@Override
public void dismissDialog() {
dialog.dismiss();
}
} }

@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?backcolor"
android:orientation="vertical"> android:orientation="vertical">
<ImageView <ImageView

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?><!--
Clover - 4chan browser https://github.com/Floens/Clover/
Copyright (C) 2014 Floens
This program 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.
This program 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/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<FrameLayout
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/background_accent_rounded">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textColor="#ffffff" />
</FrameLayout>
<FrameLayout
android:id="@+id/arrow"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_gravity="right"
android:layout_marginRight="14dp"
android:background="@drawable/background_hint_arrow"
android:rotation="180" />
</LinearLayout>

@ -169,6 +169,7 @@ Re-enable this permission in the app settings if you permanently disabled it."</
<string name="intro_start">Get started</string> <string name="intro_start">Get started</string>
<string name="setup_sites_title">Your sites</string> <string name="setup_sites_title">Your sites</string>
<string name="setup_sites_add_hint">Add sites</string>
<string name="setup_sites_add_title">Add site</string> <string name="setup_sites_add_title">Add site</string>
<string name="setup_sites_url">Site url</string> <string name="setup_sites_url">Site url</string>
<string name="setup_sites_url_hint">http://</string> <string name="setup_sites_url_hint">http://</string>

Loading…
Cancel
Save