Browse Source

feat: 6️⃣ icon列表

master
niushuai233 1 year ago
parent
commit
658ea49ac4
  1. 42
      app/src/main/java/cc/niushuai/dididone/MainActivity.java
  2. 14
      app/src/main/java/cc/niushuai/dididone/ui/base/InitAndSetListener.java
  3. 53
      app/src/main/java/cc/niushuai/dididone/ui/setting/icon/IconFragment.java
  4. 91
      app/src/main/java/cc/niushuai/dididone/ui/setting/icon/recycle/IconRecycleAdapter.java
  5. 199
      app/src/main/java/cc/niushuai/dididone/util/Snowflake.java
  6. 97
      app/src/main/res/layout/fragment_icon.xml
  7. 23
      app/src/main/res/layout/icon_grid_item.xml

42
app/src/main/java/cc/niushuai/dididone/MainActivity.java

@ -1,7 +1,10 @@
package cc.niushuai.dididone; package cc.niushuai.dididone;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.LayoutInflaterCompat; import androidx.core.view.LayoutInflaterCompat;
import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout;
@ -18,10 +21,19 @@ import com.mikepenz.foundation_icons_typeface_library.FoundationIcons;
import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.Iconics; import com.mikepenz.iconics.Iconics;
import com.mikepenz.iconics.context.IconicsLayoutInflater2; import com.mikepenz.iconics.context.IconicsLayoutInflater2;
import com.mikepenz.iconics.typeface.IIcon;
import com.mikepenz.ionicons_typeface_library.Ionicons; import com.mikepenz.ionicons_typeface_library.Ionicons;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cc.niushuai.dididone.biz.entity.SavedIcon;
import cc.niushuai.dididone.biz.roomx.DBManager; import cc.niushuai.dididone.biz.roomx.DBManager;
import cc.niushuai.dididone.databinding.ActivityMainBinding; import cc.niushuai.dididone.databinding.ActivityMainBinding;
import cc.niushuai.dididone.ui.setting.icon.recycle.IconRecycleAdapter;
import cc.niushuai.dididone.util.Snowflake;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
@ -37,8 +49,38 @@ public class MainActivity extends AppCompatActivity {
Iconics.registerFont(new Ionicons()); Iconics.registerFont(new Ionicons());
Iconics.registerFont(new FontAwesome()); Iconics.registerFont(new FontAwesome());
Iconics.registerFont(new FoundationIcons()); Iconics.registerFont(new FoundationIcons());
// 初始化icon map
addFontMap(DevIcon.Icon.class);
addFontMap(CommunityMaterial.Icon.class);
addFontMap(GoogleMaterial.Icon.class);
addFontMap(Ionicons.Icon.class);
addFontMap(FontAwesome.Icon.class);
addFontMap(FoundationIcons.Icon.class);
} }
private void addFontMap(Class<? extends IIcon> iconClass) {
if (!iconClass.isEnum()) {
Log.d(this.getClass().getSimpleName(), iconClass.getName() + " class not enum class");
return;
}
List<SavedIcon> items = new ArrayList<>();
for (IIcon enumConstant : iconClass.getEnumConstants()) {
SavedIcon icon = new SavedIcon();
icon.setId(Snowflake.next_id());
icon.setIcon(enumConstant.getName());
icon.setColor(String.valueOf(Color.BLACK));
icon.setSize(52);
items.add(icon);
}
IconRecycleAdapter.ICON_MAP.put(IconRecycleAdapter.getIconClassName(iconClass), items);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
// 初始化icon列表 // 初始化icon列表

14
app/src/main/java/cc/niushuai/dididone/ui/base/InitAndSetListener.java

@ -0,0 +1,14 @@
package cc.niushuai.dididone.ui.base;
public interface InitAndSetListener {
/**
* 初始化数据
*/
void init();
/**
* 控件添加监听器
*/
void setListeners();
}

53
app/src/main/java/cc/niushuai/dididone/ui/setting/icon/IconFragment.java

@ -8,18 +8,69 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cc.niushuai.dididone.biz.entity.SavedIcon;
import cc.niushuai.dididone.databinding.FragmentIconBinding; import cc.niushuai.dididone.databinding.FragmentIconBinding;
import cc.niushuai.dididone.ui.base.InitAndSetListener;
import cc.niushuai.dididone.ui.setting.icon.recycle.IconRecycleAdapter;
public class IconFragment extends Fragment { public class IconFragment extends Fragment implements InitAndSetListener {
private FragmentIconBinding binding; private FragmentIconBinding binding;
private IconRecycleAdapter iconRecycleAdapter;
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentIconBinding.inflate(inflater, container, false); binding = FragmentIconBinding.inflate(inflater, container, false);
View root = binding.getRoot(); View root = binding.getRoot();
init();
setListeners();
return root; return root;
} }
/**
* 初始化数据
*/
@Override
public void init() {
initRecyclerView();
}
private void initRecyclerView() {
binding.iconsRecyclerView.addItemDecoration(new DividerItemDecoration(this.getActivity(), DividerItemDecoration.VERTICAL));
DefaultItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(1000);
itemAnimator.setRemoveDuration(1000);
binding.iconsRecyclerView.setItemAnimator(itemAnimator);
iconRecycleAdapter = new IconRecycleAdapter(getActivity(), FontAwesome.Icon.class);
binding.iconsRecyclerView.setAdapter(iconRecycleAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
binding.iconsRecyclerView.setLayoutManager(layoutManager);
}
/**
* 控件添加监听器
*/
@Override
public void setListeners() {
}
} }

91
app/src/main/java/cc/niushuai/dididone/ui/setting/icon/recycle/IconRecycleAdapter.java

@ -0,0 +1,91 @@
package cc.niushuai.dididone.ui.setting.icon.recycle;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.iconics.typeface.IIcon;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cc.niushuai.dididone.MainActivity;
import cc.niushuai.dididone.R;
import cc.niushuai.dididone.biz.entity.SavedIcon;
public class IconRecycleAdapter extends RecyclerView.Adapter<IconRecycleAdapter.IconRecycleViewHolder> {
public static final Map<String, List<SavedIcon>> ICON_MAP = new HashMap<>();
private List<SavedIcon> savedIconList;
private Context context;
public IconRecycleAdapter(Context context, Class<? extends IIcon> iconClass) {
this.context = context;
this.savedIconList = ICON_MAP.get(getIconClassName(iconClass));
}
/**
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position.
* @param viewType The view type of the new View.
* @return
*/
@NonNull
@Override
public IconRecycleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = View.inflate(context, R.layout.icon_grid_item, null);
return new IconRecycleViewHolder(view);
}
/**
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
@Override
public void onBindViewHolder(@NonNull IconRecycleViewHolder holder, int position) {
SavedIcon icon = savedIconList.get(position);
holder.iconView.setImageDrawable(new IconicsDrawable(context)
.icon(icon.getIcon())
.color(Integer.parseInt(icon.getColor()))
.sizeDp(icon.getSize()));
holder.txtView.setText(icon.getIcon());
}
/**
* @return
*/
@Override
public int getItemCount() {
return savedIconList.size();
}
public static String getIconClassName(Class<? extends IIcon> iconClass) {
String iconClassName = iconClass.getName();
return iconClassName.substring(iconClassName.lastIndexOf(".") + 1, iconClassName.indexOf("$"));
}
public static class IconRecycleViewHolder extends RecyclerView.ViewHolder {
protected ImageView iconView;
protected TextView txtView;
public IconRecycleViewHolder(@NonNull View itemView) {
super(itemView);
iconView = itemView.findViewById(R.id.icons_grid_item);
txtView = itemView.findViewById(R.id.icons_grid_txt);
}
}
}

199
app/src/main/java/cc/niushuai/dididone/util/Snowflake.java

@ -0,0 +1,199 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cc.niushuai.dididone.util;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author funkye
* @author selfishlover
*/
public class Snowflake {
private static final Snowflake snowflake = new Snowflake(0L);
public static long next_id() {
return snowflake.nextId();
}
public static String next_id_str() {
return snowflake.nextId() + "";
}
/**
* Start time cut (2020-05-03)
*/
private final long twepoch = 1588435200000L;
/**
* The number of bits occupied by workerId
*/
private final int workerIdBits = 10;
/**
* The number of bits occupied by timestamp
*/
private final int timestampBits = 41;
/**
* The number of bits occupied by sequence
*/
private final int sequenceBits = 12;
/**
* Maximum supported machine id, the result is 1023
*/
private final int maxWorkerId = ~(-1 << workerIdBits);
/**
* mask that help to extract timestamp and sequence from a long
*/
private final long timestampAndSequenceMask = ~(-1L << (timestampBits + sequenceBits));
/**
* business meaning: machine ID (0 ~ 1023)
* actual layout in memory:
* highest 1 bit: 0
* middle 10 bit: workerId
* lowest 53 bit: all 0
*/
private long workerId;
/**
* timestamp and sequence mix in one Long
* highest 11 bit: not used
* middle 41 bit: timestamp
* lowest 12 bit: sequence
*/
private AtomicLong timestampAndSequence;
/**
* instantiate an IdWorker using given workerId
*
* @param workerId if null, then will auto assign one
*/
public Snowflake(Long workerId) {
initTimestampAndSequence();
initWorkerId(workerId);
}
/**
* init first timestamp and sequence immediately
*/
protected void initTimestampAndSequence() {
long timestamp = getNewestTimestamp();
long timestampWithSequence = timestamp << sequenceBits;
this.timestampAndSequence = new AtomicLong(timestampWithSequence);
}
/**
* init workerId
*
* @param workerId if null, then auto generate one
*/
protected void initWorkerId(Long workerId) {
if (workerId == null) {
workerId = generateWorkerId();
}
if (workerId > maxWorkerId || workerId < 0) {
String message = String.format("worker Id can't be greater than %d or less than 0", maxWorkerId);
throw new IllegalArgumentException(message);
}
this.workerId = workerId << (timestampBits + sequenceBits);
}
/**
* get next UUID(base on snowflake algorithm), which look like:
* highest 1 bit: always 0
* next 10 bit: workerId
* next 41 bit: timestamp
* lowest 12 bit: sequence
*
* @return UUID
*/
public long nextId() {
waitIfNecessary();
long next = timestampAndSequence.incrementAndGet();
long timestampWithSequence = next & timestampAndSequenceMask;
return workerId | timestampWithSequence;
}
/**
* block current thread if the QPS of acquiring UUID is too high
* that current sequence space is exhausted
*/
private void waitIfNecessary() {
long currentWithSequence = timestampAndSequence.get();
long current = currentWithSequence >>> sequenceBits;
long newest = getNewestTimestamp();
if (current >= newest) {
try {
Thread.sleep(5);
} catch (InterruptedException ignore) {
// don't care
}
}
}
/**
* get newest timestamp relative to twepoch
*/
private long getNewestTimestamp() {
return System.currentTimeMillis() - twepoch;
}
/**
* auto generate workerId, try using mac first, if failed, then randomly generate one
*
* @return workerId
*/
private long generateWorkerId() {
try {
return generateWorkerIdBaseOnMac();
} catch (Exception e) {
return generateRandomWorkerId();
}
}
/**
* use lowest 10 bit of available MAC as workerId
*
* @return workerId
* @throws Exception when there is no available mac found
*/
private long generateWorkerIdBaseOnMac() throws Exception {
Enumeration<NetworkInterface> all = NetworkInterface.getNetworkInterfaces();
while (all.hasMoreElements()) {
NetworkInterface networkInterface = all.nextElement();
boolean isLoopback = networkInterface.isLoopback();
boolean isVirtual = networkInterface.isVirtual();
if (isLoopback || isVirtual) {
continue;
}
byte[] mac = networkInterface.getHardwareAddress();
return ((mac[4] & 0B11) << 8) | (mac[5] & 0xFF);
}
throw new RuntimeException("no available mac found");
}
/**
* randomly generate one as workerId
*
* @return workerId
*/
private long generateRandomWorkerId() {
return new Random().nextInt(maxWorkerId + 1);
}
}

97
app/src/main/res/layout/fragment_icon.xml

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#4DD5D1D1" android:background="#4DD5D1D1"
android:orientation="vertical"
android:padding="10dp"
tools:context=".ui.setting.icon.IconFragment"> tools:context=".ui.setting.icon.IconFragment">
<androidx.appcompat.widget.AppCompatEditText <androidx.appcompat.widget.AppCompatEditText
@ -12,89 +13,15 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_marginLeft="15dp" android:layout_marginLeft="15dp"
android:layout_marginTop="30dp" android:layout_marginTop="15dp"
android:layout_marginRight="15dp" android:layout_marginRight="15dp"
android:background="@drawable/bg_miui10" android:background="@drawable/bg_miui10" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/icons_group_FontAwesome" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/icons_recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginStart="10dp" android:clipToPadding="false"
android:layout_marginTop="10dp" android:scrollbars="vertical"/>
app:layout_constraintTop_toBottomOf="@id/icons_search" </LinearLayout>
android:text="@string/icon_name_FontAwesome"
android:textAlignment="inherit"
android:textColor="#CE21D873"
android:textSize="30dp" />
<RelativeLayout
android:id="@+id/icons_group_container_FontAwesome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/icons_group_FontAwesome"
>
<TextView
android:id="@+id/fontAwesome_placeholder"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerHorizontal="true"/>
<RelativeLayout
android:id="@+id/icons_group_rl_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/fontAwesome_placeholder"
android:gravity="center"
>
<ImageView
android:id="@+id/icons_group_faw_laugh"
android:layout_width="50dp"
android:layout_height="50dp"
app:ico_color="@color/black"
app:ico_icon="faw_laugh" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/icons_group_faw_laugh"
android:gravity="center_vertical"
android:text="faw_laugh" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/icons_group_rl_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="@id/fontAwesome_placeholder"
android:gravity="center"
>
<ImageView
android:id="@+id/icons_group_cmd_cards_variant"
android:layout_width="50dp"
android:layout_height="50dp"
app:ico_color="@color/black"
app:ico_icon="cmd_cards_variant" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/icons_group_cmd_cards_variant"
android:gravity="center_vertical"
android:text="cmd_cards_variant" />
</RelativeLayout>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

23
app/src/main/res/layout/icon_grid_item.xml

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="10dp">
<ImageView
android:id="@+id/icons_grid_item"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/icons_grid_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/icons_grid_item"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:textSize="14dp" />
</RelativeLayout>
Loading…
Cancel
Save