mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Bug 1157539 - Create "speed dial" dynamic home panel layout. r=mhaigh
--HG-- extra : commitid : J69tandSl6o extra : rebase_source : 0b7b26a376938ae42beb7d0f872b3f1df68eb7c3
This commit is contained in:
parent
7d0591a53a
commit
f511089b41
@ -335,11 +335,13 @@ public class BrowserContract {
|
||||
public static final String TITLE = "title";
|
||||
public static final String DESCRIPTION = "description";
|
||||
public static final String IMAGE_URL = "image_url";
|
||||
public static final String BACKGROUND_COLOR = "background_color";
|
||||
public static final String BACKGROUND_URL = "background_url";
|
||||
public static final String CREATED = "created";
|
||||
public static final String FILTER = "filter";
|
||||
|
||||
public static final String[] DEFAULT_PROJECTION =
|
||||
new String[] { _ID, DATASET_ID, URL, TITLE, DESCRIPTION, IMAGE_URL, FILTER };
|
||||
new String[] { _ID, DATASET_ID, URL, TITLE, DESCRIPTION, IMAGE_URL, BACKGROUND_COLOR, BACKGROUND_URL, FILTER };
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
|
@ -27,7 +27,7 @@ public class HomeProvider extends SQLiteBridgeContentProvider {
|
||||
private static final String LOGTAG = "GeckoHomeProvider";
|
||||
|
||||
// This should be kept in sync with the db version in mobile/android/modules/HomeProvider.jsm
|
||||
private static final int DB_VERSION = 2;
|
||||
private static final int DB_VERSION = 3;
|
||||
private static final String DB_FILENAME = "home.sqlite";
|
||||
private static final String TELEMETRY_TAG = "SQLITEBRIDGE_PROVIDER_HOME";
|
||||
|
||||
|
@ -524,7 +524,8 @@ public final class HomeConfig {
|
||||
|
||||
public static enum ItemType implements Parcelable {
|
||||
ARTICLE("article"),
|
||||
IMAGE("image");
|
||||
IMAGE("image"),
|
||||
ICON("icon");
|
||||
|
||||
private final String mId;
|
||||
|
||||
|
@ -5,13 +5,8 @@
|
||||
|
||||
package org.mozilla.gecko.home;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.db.BrowserContract.HomeItems;
|
||||
import org.mozilla.gecko.home.HomeConfig.ItemHandler;
|
||||
import org.mozilla.gecko.home.HomeConfig.ViewConfig;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.PanelLayout.DatasetBacked;
|
||||
import org.mozilla.gecko.home.PanelLayout.FilterManager;
|
||||
import org.mozilla.gecko.home.PanelLayout.OnItemOpenListener;
|
||||
@ -36,7 +31,8 @@ public class PanelGridView extends GridView
|
||||
private HomeContextMenuInfo.Factory mContextMenuInfoFactory;
|
||||
|
||||
public PanelGridView(Context context, ViewConfig viewConfig) {
|
||||
super(context, null, R.attr.panelGridViewStyle);
|
||||
super(context, null, (viewConfig.getItemType() == HomeConfig.ItemType.ICON) ?
|
||||
R.attr.panelIconGridViewStyle : R.attr.panelGridViewStyle);
|
||||
|
||||
this.viewConfig = viewConfig;
|
||||
itemHandler = new PanelViewItemHandler(viewConfig);
|
||||
|
@ -11,6 +11,7 @@ import org.mozilla.gecko.home.HomeConfig.ItemType;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -18,22 +19,22 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
class PanelItemView extends LinearLayout {
|
||||
private final TextView title;
|
||||
private final TextView description;
|
||||
private final ImageView image;
|
||||
private final LinearLayout titleDescContainer;
|
||||
private final TextView titleView;
|
||||
private final TextView descriptionView;
|
||||
private final ImageView imageView;
|
||||
private final LinearLayout titleDescContainerView;
|
||||
private final ImageView backgroundView;
|
||||
|
||||
private PanelItemView(Context context, int layoutId) {
|
||||
super(context);
|
||||
|
||||
LayoutInflater.from(context).inflate(layoutId, this);
|
||||
title = (TextView) findViewById(R.id.title);
|
||||
description = (TextView) findViewById(R.id.description);
|
||||
image = (ImageView) findViewById(R.id.image);
|
||||
titleDescContainer = (LinearLayout) findViewById(R.id.title_desc_container);
|
||||
titleView = (TextView) findViewById(R.id.title);
|
||||
descriptionView = (TextView) findViewById(R.id.description);
|
||||
imageView = (ImageView) findViewById(R.id.image);
|
||||
backgroundView = (ImageView) findViewById(R.id.background);
|
||||
titleDescContainerView = (LinearLayout) findViewById(R.id.title_desc_container);
|
||||
}
|
||||
|
||||
public void updateFromCursor(Cursor cursor) {
|
||||
@ -42,35 +43,58 @@ class PanelItemView extends LinearLayout {
|
||||
|
||||
// Only show title if the item has one
|
||||
final boolean hasTitle = !TextUtils.isEmpty(titleText);
|
||||
title.setVisibility(hasTitle ? View.VISIBLE : View.GONE);
|
||||
titleDescContainer.setVisibility(hasTitle ? View.VISIBLE : View.GONE);
|
||||
titleView.setVisibility(hasTitle ? View.VISIBLE : View.GONE);
|
||||
if (hasTitle) {
|
||||
title.setText(titleText);
|
||||
titleView.setText(titleText);
|
||||
}
|
||||
|
||||
int descriptionIndex = cursor.getColumnIndexOrThrow(HomeItems.DESCRIPTION);
|
||||
final String descriptionText = cursor.getString(descriptionIndex);
|
||||
|
||||
// Only show description if the item has one
|
||||
// Descriptions are not supported for IconItemView objects (Bug 1157539)
|
||||
final boolean hasDescription = !TextUtils.isEmpty(descriptionText);
|
||||
description.setVisibility(hasDescription ? View.VISIBLE : View.GONE);
|
||||
if (descriptionView != null) {
|
||||
descriptionView.setVisibility(hasDescription ? View.VISIBLE : View.GONE);
|
||||
if (hasDescription) {
|
||||
description.setText(descriptionText);
|
||||
descriptionView.setText(descriptionText);
|
||||
}
|
||||
}
|
||||
if (titleDescContainerView != null) {
|
||||
titleDescContainerView.setVisibility(hasTitle || hasDescription ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
titleDescContainer.setVisibility(hasTitle || hasDescription ? View.VISIBLE : View.GONE);
|
||||
|
||||
int imageIndex = cursor.getColumnIndexOrThrow(HomeItems.IMAGE_URL);
|
||||
final String imageUrl = cursor.getString(imageIndex);
|
||||
|
||||
// Only try to load the image if the item has define image URL
|
||||
final boolean hasImageUrl = !TextUtils.isEmpty(imageUrl);
|
||||
image.setVisibility(hasImageUrl ? View.VISIBLE : View.GONE);
|
||||
imageView.setVisibility(hasImageUrl ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (hasImageUrl) {
|
||||
ImageLoader.with(getContext())
|
||||
.load(imageUrl)
|
||||
.into(image);
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
final int columnIndexBackgroundColor = cursor.getColumnIndex(HomeItems.BACKGROUND_COLOR);
|
||||
if (columnIndexBackgroundColor != -1) {
|
||||
final String color = cursor.getString(columnIndexBackgroundColor);
|
||||
if (!TextUtils.isEmpty(color)) {
|
||||
setBackgroundColor(Color.parseColor(color));
|
||||
}
|
||||
}
|
||||
|
||||
// Backgrounds are only supported for IconItemView objects (Bug 1157539)
|
||||
final int columnIndexBackgroundUrl = cursor.getColumnIndex(HomeItems.BACKGROUND_URL);
|
||||
if (columnIndexBackgroundUrl != -1) {
|
||||
final String backgroundUrl = cursor.getString(columnIndexBackgroundUrl);
|
||||
if (backgroundView != null && !TextUtils.isEmpty(backgroundUrl)) {
|
||||
ImageLoader.with(getContext())
|
||||
.load(backgroundUrl)
|
||||
.fit()
|
||||
.into(backgroundView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +112,12 @@ class PanelItemView extends LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private static class IconItemView extends PanelItemView {
|
||||
private IconItemView(Context context) {
|
||||
super(context, R.layout.panel_icon_item);
|
||||
}
|
||||
}
|
||||
|
||||
public static PanelItemView create(Context context, ItemType itemType) {
|
||||
switch(itemType) {
|
||||
case ARTICLE:
|
||||
@ -96,6 +126,9 @@ class PanelItemView extends LinearLayout {
|
||||
case IMAGE:
|
||||
return new ImageItemView(context);
|
||||
|
||||
case ICON:
|
||||
return new IconItemView(context);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Could not create panel item view from " + itemType);
|
||||
}
|
||||
|
@ -525,6 +525,7 @@ gbjar.sources += [
|
||||
'widget/ResizablePathDrawable.java',
|
||||
'widget/SiteLogins.java',
|
||||
'widget/SquaredImageView.java',
|
||||
'widget/SquaredRelativeLayout.java',
|
||||
'widget/SwipeDismissListViewTouchListener.java',
|
||||
'widget/TabThumbnailWrapper.java',
|
||||
'widget/ThumbnailView.java',
|
||||
|
36
mobile/android/base/resources/layout/panel_icon_item.xml
Normal file
36
mobile/android/base/resources/layout/panel_icon_item.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<org.mozilla.gecko.widget.SquaredRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:scaleType="centerInside"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textColor="@android:color/white"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:textSize="12sp"
|
||||
android:padding="8dp"
|
||||
android:background="@color/panel_icon_item_title_background"
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
|
||||
</org.mozilla.gecko.widget.SquaredRelativeLayout>
|
@ -6,5 +6,6 @@
|
||||
<resources>
|
||||
|
||||
<integer name="number_of_top_sites_cols">3</integer>
|
||||
<integer name="panel_icon_grid_view_columns">6</integer>
|
||||
|
||||
</resources>
|
||||
|
@ -7,5 +7,6 @@
|
||||
|
||||
<integer name="number_of_top_sites">9</integer>
|
||||
<integer name="number_of_top_sites_cols">3</integer>
|
||||
<integer name="panel_icon_grid_view_columns">6</integer>
|
||||
|
||||
</resources>
|
||||
|
@ -37,8 +37,10 @@
|
||||
<!-- Default style for the TopSitesGridItemView -->
|
||||
<attr name="topSitesGridItemViewStyle" format="reference" />
|
||||
|
||||
<!-- Style for the PanelGridView -->
|
||||
<!-- Styles for dynamic panel grid views -->
|
||||
<attr name="panelGridViewStyle" format="reference" />
|
||||
<attr name="panelIconGridViewStyle" format="reference" />
|
||||
<attr name="panelIconViewStyle" format="reference" />
|
||||
|
||||
<!-- Style for the TabsGridLayout -->
|
||||
<attr name="tabGridLayoutViewStyle" format="reference" />
|
||||
|
@ -125,6 +125,7 @@
|
||||
<color name="home_button_bar_bg">#FFF5F7F9</color>
|
||||
|
||||
<color name="panel_image_item_background">#D1D9E1</color>
|
||||
<color name="panel_icon_item_title_background">#32000000</color>
|
||||
|
||||
<!-- Swipe to refresh colors for dynamic panel -->
|
||||
<color name="swipe_refresh_orange">#FFFFC26C</color>
|
||||
|
@ -8,5 +8,6 @@
|
||||
<integer name="number_of_top_sites">6</integer>
|
||||
<integer name="number_of_top_sites_cols">2</integer>
|
||||
<integer name="max_icon_grid_columns">4</integer>
|
||||
<integer name="panel_icon_grid_view_columns">3</integer>
|
||||
|
||||
</resources>
|
||||
|
@ -191,6 +191,17 @@
|
||||
<item name="android:drawSelectorOnTop">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.PanelIconGridView" parent="Widget.GridView">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:numColumns">@integer/panel_icon_grid_view_columns</item>
|
||||
<item name="android:horizontalSpacing">6dp</item>
|
||||
<item name="android:verticalSpacing">6dp</item>
|
||||
<item name="android:drawSelectorOnTop">true</item>
|
||||
<item name="android:padding">6dp</item>
|
||||
<item name="android:clipToPadding">false</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.TabsGridLayout" parent="Widget.GridView">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
|
@ -95,6 +95,7 @@
|
||||
<item name="menuItemActionModeStyle">@style/GeckoActionBar.Button</item>
|
||||
<item name="menuItemShareActionButtonStyle">@style/Widget.MenuItemSecondaryActionBar</item>
|
||||
<item name="panelGridViewStyle">@style/Widget.PanelGridView</item>
|
||||
<item name="panelIconGridViewStyle">@style/Widget.PanelIconGridView</item>
|
||||
<item name="topSitesGridItemViewStyle">@style/Widget.TopSitesGridItemView</item>
|
||||
<item name="topSitesGridViewStyle">@style/Widget.TopSitesGridView</item>
|
||||
<item name="topSitesThumbnailViewStyle">@style/Widget.TopSitesThumbnailView</item>
|
||||
|
33
mobile/android/base/widget/SquaredRelativeLayout.java
Normal file
33
mobile/android/base/widget/SquaredRelativeLayout.java
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
public class SquaredRelativeLayout extends RelativeLayout {
|
||||
public SquaredRelativeLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SquaredRelativeLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public SquaredRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
int squareMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
|
||||
|
||||
super.onMeasure(squareMeasureSpec, squareMeasureSpec);
|
||||
}
|
||||
}
|
@ -301,7 +301,8 @@ let HomePanels = (function () {
|
||||
// Valid item types for a panel view.
|
||||
let Item = Object.freeze({
|
||||
ARTICLE: "article",
|
||||
IMAGE: "image"
|
||||
IMAGE: "image",
|
||||
ICON: "icon"
|
||||
});
|
||||
|
||||
// Valid item handlers for a panel view.
|
||||
|
@ -21,8 +21,9 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
* SCHEMA_VERSION history:
|
||||
* 1: Create HomeProvider (bug 942288)
|
||||
* 2: Add filter column to items table (bug 942295/975841)
|
||||
* 3: Add background_color and background_url columns (bug 1157539)
|
||||
*/
|
||||
const SCHEMA_VERSION = 2;
|
||||
const SCHEMA_VERSION = 3;
|
||||
|
||||
// The maximum number of items you can attempt to save at once.
|
||||
const MAX_SAVE_COUNT = 100;
|
||||
@ -54,6 +55,8 @@ const SQL = {
|
||||
"title TEXT," +
|
||||
"description TEXT," +
|
||||
"image_url TEXT," +
|
||||
"background_color TEXT," +
|
||||
"background_url TEXT," +
|
||||
"filter TEXT," +
|
||||
"created INTEGER" +
|
||||
")",
|
||||
@ -62,11 +65,17 @@ const SQL = {
|
||||
"DROP TABLE items",
|
||||
|
||||
insertItem:
|
||||
"INSERT INTO items (dataset_id, url, title, description, image_url, filter, created) " +
|
||||
"VALUES (:dataset_id, :url, :title, :description, :image_url, :filter, :created)",
|
||||
"INSERT INTO items (dataset_id, url, title, description, image_url, background_color, background_url, filter, created) " +
|
||||
"VALUES (:dataset_id, :url, :title, :description, :image_url, :background_color, :background_url, :filter, :created)",
|
||||
|
||||
deleteFromDataset:
|
||||
"DELETE FROM items WHERE dataset_id = :dataset_id"
|
||||
"DELETE FROM items WHERE dataset_id = :dataset_id",
|
||||
|
||||
addColumnBackgroundColor:
|
||||
"ALTER TABLE items ADD COLUMN background_color TEXT",
|
||||
|
||||
addColumnBackgroundUrl:
|
||||
"ALTER TABLE items ADD COLUMN background_url TEXT",
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,15 +223,21 @@ function createDatabase(db) {
|
||||
*/
|
||||
function upgradeDatabase(db, oldVersion, newVersion) {
|
||||
return Task.spawn(function upgrade_database_task() {
|
||||
for (let v = oldVersion + 1; v <= newVersion; v++) {
|
||||
switch(v) {
|
||||
case 2:
|
||||
switch (oldVersion) {
|
||||
case 1:
|
||||
// Migration from v1 to latest:
|
||||
// Recreate the items table discarding any
|
||||
// existing data.
|
||||
yield db.execute(SQL.dropItemsTable);
|
||||
yield db.execute(SQL.createItemsTable);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
// Migration from v2 to latest:
|
||||
// Add new columns: background_color, background_url
|
||||
yield db.execute(SQL.addColumnBackgroundColor);
|
||||
yield db.execute(SQL.addColumnBackgroundUrl);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -354,6 +369,8 @@ HomeStorage.prototype = {
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
image_url: item.image_url,
|
||||
background_color: item.background_color,
|
||||
background_url: item.background_url,
|
||||
filter: item.filter,
|
||||
created: Date.now()
|
||||
};
|
||||
|
@ -14,6 +14,8 @@ Cu.import("resource://gre/modules/Task.jsm");
|
||||
const TEST_DATASET_ID = "test-dataset-id";
|
||||
const TEST_URL = "http://test.com";
|
||||
const TEST_TITLE = "Test";
|
||||
const TEST_BACKGROUND_URL = "http://example.com/background";
|
||||
const TEST_BACKGROUND_COLOR = "#FF9500";
|
||||
|
||||
const PREF_SYNC_CHECK_INTERVAL_SECS = "home.sync.checkIntervalSecs";
|
||||
const TEST_INTERVAL_SECS = 1;
|
||||
@ -48,7 +50,12 @@ add_test(function test_periodic_sync() {
|
||||
add_task(function test_save_and_delete() {
|
||||
// Use the HomeProvider API to save some data.
|
||||
let storage = HomeProvider.getStorage(TEST_DATASET_ID);
|
||||
yield storage.save([{ title: TEST_TITLE, url: TEST_URL }]);
|
||||
yield storage.save([{
|
||||
title: TEST_TITLE,
|
||||
url: TEST_URL,
|
||||
background_url: TEST_BACKGROUND_URL,
|
||||
background_color: TEST_BACKGROUND_COLOR
|
||||
}]);
|
||||
|
||||
// Peek in the DB to make sure we have the right data.
|
||||
let db = yield Sqlite.openConnection({ path: DB_PATH });
|
||||
@ -60,6 +67,8 @@ add_task(function test_save_and_delete() {
|
||||
let result = yield db.execute("SELECT * FROM items", null, function onRow(row){
|
||||
do_check_eq(row.getResultByName("dataset_id"), TEST_DATASET_ID);
|
||||
do_check_eq(row.getResultByName("url"), TEST_URL);
|
||||
do_check_eq(row.getResultByName("background_url"), TEST_BACKGROUND_URL);
|
||||
do_check_eq(row.getResultByName("background_color"), TEST_BACKGROUND_COLOR);
|
||||
});
|
||||
|
||||
// Use the HomeProvider API to delete the data.
|
||||
|
Loading…
Reference in New Issue
Block a user